diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ebfb25d --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ + +Darner-dan-uh/Darner-dan-uh/.DS_Store + +Darner-dan-uh/Darner-dan-uh/Source/.DS_Store + +Darner-dan-uh/Darner-dan-uh/Source/Base/.DS_Store + +Darner-dan-uh/Darner-dan-uh/Source/Base/Base.lproj/.DS_Store + +Darner-dan-uh/Darner-dan-uh/Source/Modules/.DS_Store + +Darner-dan-uh/Darner-dan-uh/Source/Modules/Memorization/.DS_Store + +Darner-dan-uh/Darner-dan-uh/Source/Modules/Register/.DS_Store + +.DS_Store diff --git a/Darner-dan-uh/.DS_Store b/Darner-dan-uh/.DS_Store deleted file mode 100644 index a0f7c48..0000000 Binary files a/Darner-dan-uh/.DS_Store and /dev/null differ diff --git a/Darner-dan-uh/Darner-dan-uh.xcodeproj/project.pbxproj b/Darner-dan-uh/Darner-dan-uh.xcodeproj/project.pbxproj index dde6fe8..dc919d6 100644 --- a/Darner-dan-uh/Darner-dan-uh.xcodeproj/project.pbxproj +++ b/Darner-dan-uh/Darner-dan-uh.xcodeproj/project.pbxproj @@ -3,16 +3,74 @@ archiveVersion = 1; classes = { }; - objectVersion = 50; + objectVersion = 51; objects = { /* Begin PBXBuildFile section */ + 9F2CE42D25674F600024FD12 /* RankingModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F2CE42C25674F600024FD12 /* RankingModel.swift */; }; + 9F5765482577360A003B37BA /* Mypage.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9F5765472577360A003B37BA /* Mypage.storyboard */; }; + 9FC343302566BA54003AEE58 /* RankingViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC3432F2566BA54003AEE58 /* RankingViewModel.swift */; }; + 9FC7CC91257E1CE000412C16 /* StackViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC7CC90257E1CE000412C16 /* StackViewController.swift */; }; + 9FC7CC94257E47FE00412C16 /* MemoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC7CC93257E47FE00412C16 /* MemoViewController.swift */; }; + 9FC7CC99257E5CA900412C16 /* MemoTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC7CC98257E5CA900412C16 /* MemoTableViewCell.swift */; }; + 9FC7CC9D257E681400412C16 /* MemoModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC7CC9C257E681400412C16 /* MemoModel.swift */; }; + 9FCC818A25772C6B0010123B /* SeeMypageViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FCC818925772C6B0010123B /* SeeMypageViewModel.swift */; }; +<<<<<<< Updated upstream + D620C5372582587800AA628B /* CharacterCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D620C5362582587800AA628B /* CharacterCollectionViewCell.swift */; }; +======= + 9FE5E5482582566B008D2255 /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FE5E5472582566B008D2255 /* DetailViewController.swift */; }; +>>>>>>> Stashed changes + D63FE3212535EF4600DCD75F /* BinggraeMelona-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = D63FE31F2535EF4500DCD75F /* BinggraeMelona-Bold.ttf */; }; + D63FE3222535EF4600DCD75F /* BinggraeMelona.ttf in Resources */ = {isa = PBXBuildFile; fileRef = D63FE3202535EF4500DCD75F /* BinggraeMelona.ttf */; }; + D644AC8825700665002905AE /* CheckCertificationNumberViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D644AC8725700665002905AE /* CheckCertificationNumberViewModel.swift */; }; + D644AC8C257006D2002905AE /* MypageModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D644AC8B257006D2002905AE /* MypageModel.swift */; }; + D644AC8F257006E1002905AE /* TestViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D644AC8E257006E1002905AE /* TestViewModel.swift */; }; + D644AC9225700B21002905AE /* TokenMessageModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D644AC9125700B21002905AE /* TokenMessageModel.swift */; }; + D644AC9625701036002905AE /* UIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D644AC9525701036002905AE /* UIView.swift */; }; + D644AC9A2570113B002905AE /* WordModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D644AC992570113B002905AE /* WordModel.swift */; }; + D644AC9E257011FF002905AE /* MessageModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D644AC9D257011FF002905AE /* MessageModel.swift */; }; + D644ACA325701388002905AE /* TestCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D644ACA125701388002905AE /* TestCollectionViewCell.swift */; }; D6578ACB2500867A000185F1 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6578ACA2500867A000185F1 /* AppDelegate.swift */; }; - D6578ACD2500867A000185F1 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6578ACC2500867A000185F1 /* SceneDelegate.swift */; }; - D6578ACF2500867A000185F1 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6578ACE2500867A000185F1 /* ViewController.swift */; }; D6578AD22500867A000185F1 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D6578AD02500867A000185F1 /* Main.storyboard */; }; D6578AD42500867C000185F1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D6578AD32500867C000185F1 /* Assets.xcassets */; }; D6578AD72500867C000185F1 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D6578AD52500867C000185F1 /* LaunchScreen.storyboard */; }; + D660A212257DA01F00C5FE6F /* LevelModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D660A211257DA01F00C5FE6F /* LevelModel.swift */; }; + D660A215257DA03900C5FE6F /* TestResultModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D660A214257DA03900C5FE6F /* TestResultModel.swift */; }; + D660A21A257DA0D700C5FE6F /* RankingCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D660A219257DA0D700C5FE6F /* RankingCell.swift */; }; + D660A21E257DA10600C5FE6F /* StackViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D660A21D257DA10600C5FE6F /* StackViewController.swift */; }; + D660A23C257DA21D00C5FE6F /* MypageModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D660A23B257DA21D00C5FE6F /* MypageModel.swift */; }; + D6A6E11D25634B6400A77E05 /* ViewControllerName.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A6E11925634B6400A77E05 /* ViewControllerName.swift */; }; + D6A6E11E25634B6400A77E05 /* UIColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A6E11A25634B6400A77E05 /* UIColor.swift */; }; + D6A6E11F25634B6400A77E05 /* UIButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A6E11B25634B6400A77E05 /* UIButton.swift */; }; + D6A6E12025634B6400A77E05 /* UIViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A6E11C25634B6400A77E05 /* UIViewController.swift */; }; + D6A6E22E2563541E00A77E05 /* SetMainCharacterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A6E2282563541E00A77E05 /* SetMainCharacterViewController.swift */; }; + D6A6E22F2563541E00A77E05 /* EnterPwViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A6E2292563541E00A77E05 /* EnterPwViewController.swift */; }; + D6A6E2302563541E00A77E05 /* CharacterCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A6E22A2563541E00A77E05 /* CharacterCollectionViewController.swift */; }; + D6A6E2312563541E00A77E05 /* ModifyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A6E22B2563541E00A77E05 /* ModifyViewController.swift */; }; + D6A6E2322563541E00A77E05 /* MyCharacterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A6E22C2563541E00A77E05 /* MyCharacterViewController.swift */; }; + D6A6E2332563541E00A77E05 /* MypageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A6E22D2563541E00A77E05 /* MypageViewController.swift */; }; + D6A6E23A2563544F00A77E05 /* MypageViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A6E2362563544E00A77E05 /* MypageViewModel.swift */; }; + D6A6E23B2563544F00A77E05 /* ViewModelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A6E2372563544E00A77E05 /* ViewModelType.swift */; }; + D6A6E23C2563544F00A77E05 /* RegisterViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A6E2382563544F00A77E05 /* RegisterViewModel.swift */; }; + D6A6E23D2563544F00A77E05 /* LoginViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A6E2392563544F00A77E05 /* LoginViewModel.swift */; }; + D6A6E2452563554D00A77E05 /* RegisterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A6E2412563554D00A77E05 /* RegisterViewController.swift */; }; + D6A6E2462563554D00A77E05 /* FinishRegisterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A6E2422563554D00A77E05 /* FinishRegisterViewController.swift */; }; + D6A6E2472563554D00A77E05 /* CheckCertificationNumberViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A6E2432563554D00A77E05 /* CheckCertificationNumberViewController.swift */; }; + D6A6E2572563557600A77E05 /* SelectWordNumViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A6E24F2563557600A77E05 /* SelectWordNumViewController.swift */; }; + D6A6E2582563557600A77E05 /* WordResultCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A6E2512563557600A77E05 /* WordResultCell.swift */; }; + D6A6E2592563557600A77E05 /* WordCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A6E2522563557600A77E05 /* WordCell.swift */; }; + D6A6E25A2563557600A77E05 /* TestViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A6E2532563557600A77E05 /* TestViewController.swift */; }; + D6A6E25B2563557600A77E05 /* TestResultViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A6E2542563557600A77E05 /* TestResultViewController.swift */; }; + D6A6E25C2563557600A77E05 /* TestTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A6E2552563557600A77E05 /* TestTableViewController.swift */; }; + D6A6E25D2563557600A77E05 /* MemorizationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A6E2562563557600A77E05 /* MemorizationViewController.swift */; }; + D6A6E2602563558500A77E05 /* LoginViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A6E25F2563558500A77E05 /* LoginViewController.swift */; }; + D6A6E267256355D900A77E05 /* WritingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A6E266256355D900A77E05 /* WritingViewController.swift */; }; + D6A6E26C2563561300A77E05 /* RankingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A6E26B2563561300A77E05 /* RankingViewController.swift */; }; + D6BB372B255D1BE60049BB65 /* DarnerAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6BB372A255D1BE60049BB65 /* DarnerAPI.swift */; }; + D6BB375A255D210D0049BB65 /* DarnerAPIClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6BB3759255D210D0049BB65 /* DarnerAPIClient.swift */; }; + D6E68852252EB53F00FA09C1 /* Writing.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D6E68851252EB53F00FA09C1 /* Writing.storyboard */; }; + D6E68855252EB54600FA09C1 /* Ranking.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D6E68854252EB54600FA09C1 /* Ranking.storyboard */; }; + D6E68858252EB55300FA09C1 /* Memorization.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D6E68857252EB55300FA09C1 /* Memorization.storyboard */; }; FEB933CBE4FCA747B10CDE0A /* Pods_Darner_dan_uh.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2C2C5094395481B434C2AC5C /* Pods_Darner_dan_uh.framework */; }; /* End PBXBuildFile section */ @@ -20,14 +78,72 @@ 0A6D3E1C8424177E67745A13 /* Pods-Darner-dan-uh.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Darner-dan-uh.debug.xcconfig"; path = "Target Support Files/Pods-Darner-dan-uh/Pods-Darner-dan-uh.debug.xcconfig"; sourceTree = ""; }; 2C2C5094395481B434C2AC5C /* Pods_Darner_dan_uh.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Darner_dan_uh.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 773631FB34EA472779385722 /* Pods-Darner-dan-uh.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Darner-dan-uh.release.xcconfig"; path = "Target Support Files/Pods-Darner-dan-uh/Pods-Darner-dan-uh.release.xcconfig"; sourceTree = ""; }; + 9F2CE42C25674F600024FD12 /* RankingModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RankingModel.swift; sourceTree = ""; }; + 9F5765472577360A003B37BA /* Mypage.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Mypage.storyboard; sourceTree = ""; }; + 9FC3432F2566BA54003AEE58 /* RankingViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RankingViewModel.swift; sourceTree = ""; }; + 9FC7CC90257E1CE000412C16 /* StackViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StackViewController.swift; sourceTree = ""; }; + 9FC7CC93257E47FE00412C16 /* MemoViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemoViewController.swift; sourceTree = ""; }; + 9FC7CC98257E5CA900412C16 /* MemoTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemoTableViewCell.swift; sourceTree = ""; }; + 9FC7CC9C257E681400412C16 /* MemoModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemoModel.swift; sourceTree = ""; }; + 9FCC818925772C6B0010123B /* SeeMypageViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeeMypageViewModel.swift; sourceTree = ""; }; +<<<<<<< Updated upstream + D620C5362582587800AA628B /* CharacterCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CharacterCollectionViewCell.swift; sourceTree = ""; }; +======= + 9FE5E5472582566B008D2255 /* DetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailViewController.swift; sourceTree = ""; }; +>>>>>>> Stashed changes + D63FE31F2535EF4500DCD75F /* BinggraeMelona-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "BinggraeMelona-Bold.ttf"; sourceTree = ""; }; + D63FE3202535EF4500DCD75F /* BinggraeMelona.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = BinggraeMelona.ttf; sourceTree = ""; }; + D644AC8725700665002905AE /* CheckCertificationNumberViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CheckCertificationNumberViewModel.swift; sourceTree = ""; }; + D644AC8B257006D2002905AE /* MypageModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MypageModel.swift; path = "Darner-dan-uh/Source/ViewModel/MypageModel.swift"; sourceTree = SOURCE_ROOT; }; + D644AC8E257006E1002905AE /* TestViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestViewModel.swift; sourceTree = ""; }; + D644AC9125700B21002905AE /* TokenMessageModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokenMessageModel.swift; sourceTree = ""; }; + D644AC9525701036002905AE /* UIView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIView.swift; sourceTree = ""; }; + D644AC992570113B002905AE /* WordModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WordModel.swift; sourceTree = ""; }; + D644AC9D257011FF002905AE /* MessageModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageModel.swift; sourceTree = ""; }; + D644ACA125701388002905AE /* TestCollectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestCollectionViewCell.swift; sourceTree = ""; }; D6578AC72500867A000185F1 /* Darner-dan-uh.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Darner-dan-uh.app"; sourceTree = BUILT_PRODUCTS_DIR; }; D6578ACA2500867A000185F1 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - D6578ACC2500867A000185F1 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; - D6578ACE2500867A000185F1 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; D6578AD12500867A000185F1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; D6578AD32500867C000185F1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; D6578AD62500867C000185F1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; D6578AD82500867C000185F1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + D660A211257DA01F00C5FE6F /* LevelModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LevelModel.swift; sourceTree = ""; }; + D660A214257DA03900C5FE6F /* TestResultModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestResultModel.swift; sourceTree = ""; }; + D660A219257DA0D700C5FE6F /* RankingCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = RankingCell.swift; path = "Darner-dan-uh/Source/Extension/RankingCell.swift"; sourceTree = SOURCE_ROOT; }; + D660A21D257DA10600C5FE6F /* StackViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = StackViewController.swift; path = "Darner-dan-uh/Source/Extension/StackViewController.swift"; sourceTree = SOURCE_ROOT; }; + D660A23B257DA21D00C5FE6F /* MypageModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MypageModel.swift; path = "Darner-dan-uh/Source/ViewModel/MypageModel.swift"; sourceTree = SOURCE_ROOT; }; + D6A6E11925634B6400A77E05 /* ViewControllerName.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewControllerName.swift; sourceTree = ""; }; + D6A6E11A25634B6400A77E05 /* UIColor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIColor.swift; sourceTree = ""; }; + D6A6E11B25634B6400A77E05 /* UIButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIButton.swift; sourceTree = ""; }; + D6A6E11C25634B6400A77E05 /* UIViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIViewController.swift; sourceTree = ""; }; + D6A6E2282563541E00A77E05 /* SetMainCharacterViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SetMainCharacterViewController.swift; path = "Darner-dan-uh/Source/Modules/MyPage/SetMainCharacterViewController.swift"; sourceTree = SOURCE_ROOT; }; + D6A6E2292563541E00A77E05 /* EnterPwViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = EnterPwViewController.swift; path = "Darner-dan-uh/Source/Modules/MyPage/EnterPwViewController.swift"; sourceTree = SOURCE_ROOT; }; + D6A6E22A2563541E00A77E05 /* CharacterCollectionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CharacterCollectionViewController.swift; path = "Darner-dan-uh/Source/Modules/MyPage/CharacterCollectionViewController.swift"; sourceTree = SOURCE_ROOT; }; + D6A6E22B2563541E00A77E05 /* ModifyViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ModifyViewController.swift; path = "Darner-dan-uh/Source/Modules/MyPage/ModifyViewController.swift"; sourceTree = SOURCE_ROOT; }; + D6A6E22C2563541E00A77E05 /* MyCharacterViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MyCharacterViewController.swift; path = "Darner-dan-uh/Source/Modules/MyPage/MyCharacterViewController.swift"; sourceTree = SOURCE_ROOT; }; + D6A6E22D2563541E00A77E05 /* MypageViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MypageViewController.swift; path = "Darner-dan-uh/Source/Modules/MyPage/MypageViewController.swift"; sourceTree = SOURCE_ROOT; }; + D6A6E2362563544E00A77E05 /* MypageViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MypageViewModel.swift; sourceTree = ""; }; + D6A6E2372563544E00A77E05 /* ViewModelType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewModelType.swift; sourceTree = ""; }; + D6A6E2382563544F00A77E05 /* RegisterViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RegisterViewModel.swift; sourceTree = ""; }; + D6A6E2392563544F00A77E05 /* LoginViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginViewModel.swift; sourceTree = ""; }; + D6A6E2412563554D00A77E05 /* RegisterViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RegisterViewController.swift; path = "Darner-dan-uh/Source/Modules/Register/RegisterViewController.swift"; sourceTree = SOURCE_ROOT; }; + D6A6E2422563554D00A77E05 /* FinishRegisterViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FinishRegisterViewController.swift; path = "Darner-dan-uh/Source/Modules/Register/FinishRegisterViewController.swift"; sourceTree = SOURCE_ROOT; }; + D6A6E2432563554D00A77E05 /* CheckCertificationNumberViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CheckCertificationNumberViewController.swift; path = "Darner-dan-uh/Source/Modules/Register/CheckCertificationNumberViewController.swift"; sourceTree = SOURCE_ROOT; }; + D6A6E24F2563557600A77E05 /* SelectWordNumViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectWordNumViewController.swift; sourceTree = ""; }; + D6A6E2512563557600A77E05 /* WordResultCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WordResultCell.swift; sourceTree = ""; }; + D6A6E2522563557600A77E05 /* WordCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WordCell.swift; sourceTree = ""; }; + D6A6E2532563557600A77E05 /* TestViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestViewController.swift; sourceTree = ""; }; + D6A6E2542563557600A77E05 /* TestResultViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestResultViewController.swift; sourceTree = ""; }; + D6A6E2552563557600A77E05 /* TestTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestTableViewController.swift; sourceTree = ""; }; + D6A6E2562563557600A77E05 /* MemorizationViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MemorizationViewController.swift; sourceTree = ""; }; + D6A6E25F2563558500A77E05 /* LoginViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = LoginViewController.swift; path = "Darner-dan-uh/Source/Modules/Login/LoginViewController.swift"; sourceTree = SOURCE_ROOT; }; + D6A6E266256355D900A77E05 /* WritingViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WritingViewController.swift; path = "Darner-dan-uh/Source/Modules/Writing/WritingViewController.swift"; sourceTree = SOURCE_ROOT; }; + D6A6E26B2563561300A77E05 /* RankingViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RankingViewController.swift; path = "Darner-dan-uh/Source/Modules/Ranking/RankingViewController.swift"; sourceTree = SOURCE_ROOT; }; + D6BB372A255D1BE60049BB65 /* DarnerAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DarnerAPI.swift; sourceTree = ""; }; + D6BB3759255D210D0049BB65 /* DarnerAPIClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DarnerAPIClient.swift; sourceTree = ""; }; + D6E68851252EB53F00FA09C1 /* Writing.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Writing.storyboard; sourceTree = ""; }; + D6E68854252EB54600FA09C1 /* Ranking.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Ranking.storyboard; sourceTree = ""; }; + D6E68857252EB55300FA09C1 /* Memorization.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Memorization.storyboard; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -48,10 +164,25 @@ 0A6D3E1C8424177E67745A13 /* Pods-Darner-dan-uh.debug.xcconfig */, 773631FB34EA472779385722 /* Pods-Darner-dan-uh.release.xcconfig */, ); - name = Pods; path = Pods; sourceTree = ""; }; + 9FC3431925668426003AEE58 /* Cell */ = { + isa = PBXGroup; + children = ( + D660A219257DA0D700C5FE6F /* RankingCell.swift */, + ); + path = Cell; + sourceTree = ""; + }; + 9FC7CC97257E5C8500412C16 /* Cell */ = { + isa = PBXGroup; + children = ( + 9FC7CC98257E5CA900412C16 /* MemoTableViewCell.swift */, + ); + path = Cell; + sourceTree = ""; + }; A2011636CCE48406938D6CA0 /* Frameworks */ = { isa = PBXGroup; children = ( @@ -60,6 +191,52 @@ name = Frameworks; sourceTree = ""; }; + D620C5352582586000AA628B /* Cell */ = { + isa = PBXGroup; + children = ( + D620C5362582587800AA628B /* CharacterCollectionViewCell.swift */, + ); + path = Cell; + sourceTree = ""; + }; + D63FE3262535EFD400DCD75F /* Source */ = { + isa = PBXGroup; + children = ( + D6A6E11825634B6400A77E05 /* Extension */, + D6BB372D255D1BF30049BB65 /* Modules */, + D6BB3729255D1BE60049BB65 /* NetWorking */, + D63FE3302536116C00DCD75F /* ViewModel */, + D6E68841252EB41B00FA09C1 /* Base */, + D6BB377E255E0D860049BB65 /* Model */, + ); + path = Source; + sourceTree = ""; + }; + D63FE3282535EFDF00DCD75F /* Resource */ = { + isa = PBXGroup; + children = ( + D63FE31F2535EF4500DCD75F /* BinggraeMelona-Bold.ttf */, + D63FE3202535EF4500DCD75F /* BinggraeMelona.ttf */, + ); + path = Resource; + sourceTree = ""; + }; + D63FE3302536116C00DCD75F /* ViewModel */ = { + isa = PBXGroup; + children = ( + D644AC8725700665002905AE /* CheckCertificationNumberViewModel.swift */, + D6A6E2392563544F00A77E05 /* LoginViewModel.swift */, + D660A23B257DA21D00C5FE6F /* MypageModel.swift */, + D644AC8E257006E1002905AE /* TestViewModel.swift */, + D6A6E2362563544E00A77E05 /* MypageViewModel.swift */, + D6A6E2382563544F00A77E05 /* RegisterViewModel.swift */, + D6A6E2372563544E00A77E05 /* ViewModelType.swift */, + 9FC3432F2566BA54003AEE58 /* RankingViewModel.swift */, + 9FCC818925772C6B0010123B /* SeeMypageViewModel.swift */, + ); + path = ViewModel; + sourceTree = ""; + }; D6578ABE2500867A000185F1 = { isa = PBXGroup; children = ( @@ -67,6 +244,7 @@ D6578AC82500867A000185F1 /* Products */, 3BB6742B37E472050727ABC6 /* Pods */, A2011636CCE48406938D6CA0 /* Frameworks */, + D660A1ED257D281D00C5FE6F /* Recovered References */, ); sourceTree = ""; }; @@ -81,17 +259,174 @@ D6578AC92500867A000185F1 /* Darner-dan-uh */ = { isa = PBXGroup; children = ( - D6578ACA2500867A000185F1 /* AppDelegate.swift */, - D6578ACC2500867A000185F1 /* SceneDelegate.swift */, - D6578ACE2500867A000185F1 /* ViewController.swift */, - D6578AD02500867A000185F1 /* Main.storyboard */, - D6578AD32500867C000185F1 /* Assets.xcassets */, - D6578AD52500867C000185F1 /* LaunchScreen.storyboard */, D6578AD82500867C000185F1 /* Info.plist */, + D63FE3282535EFDF00DCD75F /* Resource */, + D63FE3262535EFD400DCD75F /* Source */, + D6E68842252EB42400FA09C1 /* Supporting */, ); path = "Darner-dan-uh"; sourceTree = ""; }; + D660A1ED257D281D00C5FE6F /* Recovered References */ = { + isa = PBXGroup; + children = ( + D644AC8B257006D2002905AE /* MypageModel.swift */, + D644AC9125700B21002905AE /* TokenMessageModel.swift */, + D644AC992570113B002905AE /* WordModel.swift */, + D644AC9D257011FF002905AE /* MessageModel.swift */, + ); + name = "Recovered References"; + sourceTree = ""; + }; + D6A6E11825634B6400A77E05 /* Extension */ = { + isa = PBXGroup; + children = ( + D6A6E11925634B6400A77E05 /* ViewControllerName.swift */, + D6A6E11A25634B6400A77E05 /* UIColor.swift */, + D6A6E11B25634B6400A77E05 /* UIButton.swift */, + D6A6E11C25634B6400A77E05 /* UIViewController.swift */, + D644AC9525701036002905AE /* UIView.swift */, + ); + path = Extension; + sourceTree = ""; + }; + D6A6E24E2563557600A77E05 /* Memorization */ = { + isa = PBXGroup; + children = ( + D6A6E2502563557600A77E05 /* Cell */, + D6A6E24F2563557600A77E05 /* SelectWordNumViewController.swift */, + D6A6E2552563557600A77E05 /* TestTableViewController.swift */, + D6A6E2532563557600A77E05 /* TestViewController.swift */, + D6A6E2542563557600A77E05 /* TestResultViewController.swift */, + D6A6E2562563557600A77E05 /* MemorizationViewController.swift */, + ); + name = Memorization; + path = "Darner-dan-uh/Source/Modules/Memorization"; + sourceTree = SOURCE_ROOT; + }; + D6A6E2502563557600A77E05 /* Cell */ = { + isa = PBXGroup; + children = ( + D644ACA125701388002905AE /* TestCollectionViewCell.swift */, + D6A6E2512563557600A77E05 /* WordResultCell.swift */, + D6A6E2522563557600A77E05 /* WordCell.swift */, + ); + path = Cell; + sourceTree = ""; + }; + D6BB3729255D1BE60049BB65 /* NetWorking */ = { + isa = PBXGroup; + children = ( + D6BB372A255D1BE60049BB65 /* DarnerAPI.swift */, + D6BB3759255D210D0049BB65 /* DarnerAPIClient.swift */, + ); + path = NetWorking; + sourceTree = ""; + }; + D6BB372D255D1BF30049BB65 /* Modules */ = { + isa = PBXGroup; + children = ( + D6A6E24E2563557600A77E05 /* Memorization */, + D6BB3780255E0EB80049BB65 /* Register */, + D6BB372E255D1BF30049BB65 /* Ranking */, + D6BB3739255D1BF30049BB65 /* MyPage */, + D6BB3742255D1BF30049BB65 /* Login */, + D6BB3744255D1BF30049BB65 /* Writing */, + ); + name = Modules; + path = ViewModel/Modules; + sourceTree = ""; + }; + D6BB372E255D1BF30049BB65 /* Ranking */ = { + isa = PBXGroup; + children = ( + 9FC3431925668426003AEE58 /* Cell */, + D6A6E26B2563561300A77E05 /* RankingViewController.swift */, +<<<<<<< Updated upstream + D660A21D257DA10600C5FE6F /* StackViewController.swift */, +======= + 9FC7CC90257E1CE000412C16 /* StackViewController.swift */, +>>>>>>> Stashed changes + ); + path = Ranking; + sourceTree = ""; + }; + D6BB3739255D1BF30049BB65 /* MyPage */ = { + isa = PBXGroup; + children = ( + D620C5352582586000AA628B /* Cell */, + D6A6E22A2563541E00A77E05 /* CharacterCollectionViewController.swift */, + D6A6E2292563541E00A77E05 /* EnterPwViewController.swift */, + D6A6E22B2563541E00A77E05 /* ModifyViewController.swift */, + D6A6E22C2563541E00A77E05 /* MyCharacterViewController.swift */, + D6A6E22D2563541E00A77E05 /* MypageViewController.swift */, + D6A6E2282563541E00A77E05 /* SetMainCharacterViewController.swift */, + ); + path = MyPage; + sourceTree = ""; + }; + D6BB3742255D1BF30049BB65 /* Login */ = { + isa = PBXGroup; + children = ( + D6A6E25F2563558500A77E05 /* LoginViewController.swift */, + ); + path = Login; + sourceTree = ""; + }; + D6BB3744255D1BF30049BB65 /* Writing */ = { + isa = PBXGroup; + children = ( + 9FC7CC97257E5C8500412C16 /* Cell */, + D6A6E266256355D900A77E05 /* WritingViewController.swift */, + 9FC7CC93257E47FE00412C16 /* MemoViewController.swift */, + 9FE5E5472582566B008D2255 /* DetailViewController.swift */, + ); + path = Writing; + sourceTree = ""; + }; + D6BB377E255E0D860049BB65 /* Model */ = { + isa = PBXGroup; + children = ( + D660A211257DA01F00C5FE6F /* LevelModel.swift */, + D660A214257DA03900C5FE6F /* TestResultModel.swift */, + 9F2CE42C25674F600024FD12 /* RankingModel.swift */, + 9FC7CC9C257E681400412C16 /* MemoModel.swift */, + ); + path = Model; + sourceTree = ""; + }; + D6BB3780255E0EB80049BB65 /* Register */ = { + isa = PBXGroup; + children = ( + D6A6E2432563554D00A77E05 /* CheckCertificationNumberViewController.swift */, + D6A6E2422563554D00A77E05 /* FinishRegisterViewController.swift */, + D6A6E2412563554D00A77E05 /* RegisterViewController.swift */, + ); + path = Register; + sourceTree = ""; + }; + D6E68841252EB41B00FA09C1 /* Base */ = { + isa = PBXGroup; + children = ( + D6578AD02500867A000185F1 /* Main.storyboard */, + 9F5765472577360A003B37BA /* Mypage.storyboard */, + D6578AD52500867C000185F1 /* LaunchScreen.storyboard */, + D6E68851252EB53F00FA09C1 /* Writing.storyboard */, + D6E68854252EB54600FA09C1 /* Ranking.storyboard */, + D6E68857252EB55300FA09C1 /* Memorization.storyboard */, + ); + path = Base; + sourceTree = ""; + }; + D6E68842252EB42400FA09C1 /* Supporting */ = { + isa = PBXGroup; + children = ( + D6578ACA2500867A000185F1 /* AppDelegate.swift */, + D6578AD32500867C000185F1 /* Assets.xcassets */, + ); + path = Supporting; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -152,9 +487,15 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + D63FE3212535EF4600DCD75F /* BinggraeMelona-Bold.ttf in Resources */, + D63FE3222535EF4600DCD75F /* BinggraeMelona.ttf in Resources */, + D6E68858252EB55300FA09C1 /* Memorization.storyboard in Resources */, D6578AD72500867C000185F1 /* LaunchScreen.storyboard in Resources */, + 9F5765482577360A003B37BA /* Mypage.storyboard in Resources */, + D6E68852252EB53F00FA09C1 /* Writing.storyboard in Resources */, D6578AD42500867C000185F1 /* Assets.xcassets in Resources */, D6578AD22500867A000185F1 /* Main.storyboard in Resources */, + D6E68855252EB54600FA09C1 /* Ranking.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -207,9 +548,64 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - D6578ACF2500867A000185F1 /* ViewController.swift in Sources */, + D6A6E2462563554D00A77E05 /* FinishRegisterViewController.swift in Sources */, + D644AC8C257006D2002905AE /* MypageModel.swift in Sources */, + D6A6E11F25634B6400A77E05 /* UIButton.swift in Sources */, + D644AC9625701036002905AE /* UIView.swift in Sources */, + D6A6E12025634B6400A77E05 /* UIViewController.swift in Sources */, + D6A6E23C2563544F00A77E05 /* RegisterViewModel.swift in Sources */, + 9F2CE42D25674F600024FD12 /* RankingModel.swift in Sources */, +<<<<<<< Updated upstream + D660A21E257DA10600C5FE6F /* StackViewController.swift in Sources */, + D660A21A257DA0D700C5FE6F /* RankingCell.swift in Sources */, +======= + 9FC7CC9D257E681400412C16 /* MemoModel.swift in Sources */, +>>>>>>> Stashed changes + D6A6E22F2563541E00A77E05 /* EnterPwViewController.swift in Sources */, + D6A6E22E2563541E00A77E05 /* SetMainCharacterViewController.swift in Sources */, + D6A6E11D25634B6400A77E05 /* ViewControllerName.swift in Sources */, + 9FCC818A25772C6B0010123B /* SeeMypageViewModel.swift in Sources */, + D6A6E2592563557600A77E05 /* WordCell.swift in Sources */, + D6BB375A255D210D0049BB65 /* DarnerAPIClient.swift in Sources */, + D644AC8F257006E1002905AE /* TestViewModel.swift in Sources */, + D6A6E23D2563544F00A77E05 /* LoginViewModel.swift in Sources */, + D620C5372582587800AA628B /* CharacterCollectionViewCell.swift in Sources */, + D6A6E2602563558500A77E05 /* LoginViewController.swift in Sources */, + D6BB372B255D1BE60049BB65 /* DarnerAPI.swift in Sources */, + D660A23C257DA21D00C5FE6F /* MypageModel.swift in Sources */, + D6A6E2452563554D00A77E05 /* RegisterViewController.swift in Sources */, + D6A6E2322563541E00A77E05 /* MyCharacterViewController.swift in Sources */, + D6A6E25C2563557600A77E05 /* TestTableViewController.swift in Sources */, + D6A6E25D2563557600A77E05 /* MemorizationViewController.swift in Sources */, + D6A6E2302563541E00A77E05 /* CharacterCollectionViewController.swift in Sources */, + D6A6E2472563554D00A77E05 /* CheckCertificationNumberViewController.swift in Sources */, + 9FC7CC94257E47FE00412C16 /* MemoViewController.swift in Sources */, D6578ACB2500867A000185F1 /* AppDelegate.swift in Sources */, - D6578ACD2500867A000185F1 /* SceneDelegate.swift in Sources */, + 9FC343302566BA54003AEE58 /* RankingViewModel.swift in Sources */, + 9FE5E5482582566B008D2255 /* DetailViewController.swift in Sources */, + D6A6E26C2563561300A77E05 /* RankingViewController.swift in Sources */, + D6A6E23A2563544F00A77E05 /* MypageViewModel.swift in Sources */, + D644AC9225700B21002905AE /* TokenMessageModel.swift in Sources */, + D6A6E2332563541E00A77E05 /* MypageViewController.swift in Sources */, + D6A6E25B2563557600A77E05 /* TestResultViewController.swift in Sources */, + D644AC9A2570113B002905AE /* WordModel.swift in Sources */, + D644ACA325701388002905AE /* TestCollectionViewCell.swift in Sources */, + D660A212257DA01F00C5FE6F /* LevelModel.swift in Sources */, + D660A215257DA03900C5FE6F /* TestResultModel.swift in Sources */, + D6A6E2582563557600A77E05 /* WordResultCell.swift in Sources */, + D6A6E11E25634B6400A77E05 /* UIColor.swift in Sources */, + D6A6E2312563541E00A77E05 /* ModifyViewController.swift in Sources */, + D6A6E25A2563557600A77E05 /* TestViewController.swift in Sources */, +<<<<<<< Updated upstream + D644AC9E257011FF002905AE /* MessageModel.swift in Sources */, +======= + 9FC7CC99257E5CA900412C16 /* MemoTableViewCell.swift in Sources */, +>>>>>>> Stashed changes + D6A6E2572563557600A77E05 /* SelectWordNumViewController.swift in Sources */, + D6A6E23B2563544F00A77E05 /* ViewModelType.swift in Sources */, + D644AC8825700665002905AE /* CheckCertificationNumberViewModel.swift in Sources */, + D6A6E267256355D900A77E05 /* WritingViewController.swift in Sources */, + 9FC7CC91257E1CE000412C16 /* StackViewController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -364,7 +760,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "personal.Darner-dan-uh"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; }; name = Debug; }; @@ -380,10 +776,11 @@ "$(inherited)", "@executable_path/Frameworks", ); + ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = "personal.Darner-dan-uh"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; }; name = Release; }; diff --git a/Darner-dan-uh/Darner-dan-uh.xcodeproj/xcshareddata/xcschemes/Darner-dan-uh.xcscheme b/Darner-dan-uh/Darner-dan-uh.xcodeproj/xcshareddata/xcschemes/Darner-dan-uh.xcscheme new file mode 100644 index 0000000..1fb04da --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh.xcodeproj/xcshareddata/xcschemes/Darner-dan-uh.xcscheme @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Darner-dan-uh/Darner-dan-uh.xcodeproj/xcuserdata/ihyun_wook.xcuserdatad/xcschemes/xcschememanagement.plist b/Darner-dan-uh/Darner-dan-uh.xcodeproj/xcuserdata/ihyun_wook.xcuserdatad/xcschemes/xcschememanagement.plist index 2326810..a208016 100644 --- a/Darner-dan-uh/Darner-dan-uh.xcodeproj/xcuserdata/ihyun_wook.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Darner-dan-uh/Darner-dan-uh.xcodeproj/xcuserdata/ihyun_wook.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,7 +7,15 @@ Darner-dan-uh.xcscheme_^#shared#^_ orderHint - 0 + 5 + + + SuppressBuildableAutocreation + + D6578AC62500867A000185F1 + + primary + diff --git a/Darner-dan-uh/Darner-dan-uh.xcodeproj/xcuserdata/munjisu.xcuserdatad/xcschemes/xcschememanagement.plist b/Darner-dan-uh/Darner-dan-uh.xcodeproj/xcuserdata/munjisu.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..f0f8337 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh.xcodeproj/xcuserdata/munjisu.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,14 @@ + + + + + SchemeUserState + + Darner-dan-uh.xcscheme_^#shared#^_ + + orderHint + 5 + + + + diff --git a/Darner-dan-uh/Darner-dan-uh.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Darner-dan-uh/Darner-dan-uh.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Darner-dan-uh/Darner-dan-uh.xcworkspace/xcuserdata/ihyun_wook.xcuserdatad/UserInterfaceState.xcuserstate b/Darner-dan-uh/Darner-dan-uh.xcworkspace/xcuserdata/ihyun_wook.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..d2a4af3 Binary files /dev/null and b/Darner-dan-uh/Darner-dan-uh.xcworkspace/xcuserdata/ihyun_wook.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/Darner-dan-uh/Darner-dan-uh.xcworkspace/xcuserdata/ihyun_wook.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/Darner-dan-uh/Darner-dan-uh.xcworkspace/xcuserdata/ihyun_wook.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000..ebefe50 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh.xcworkspace/xcuserdata/ihyun_wook.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,6 @@ + + + diff --git a/Darner-dan-uh/Darner-dan-uh.xcworkspace/xcuserdata/munjisu.xcuserdatad/UserInterfaceState.xcuserstate b/Darner-dan-uh/Darner-dan-uh.xcworkspace/xcuserdata/munjisu.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..9d4b26e Binary files /dev/null and b/Darner-dan-uh/Darner-dan-uh.xcworkspace/xcuserdata/munjisu.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/Darner-dan-uh/Darner-dan-uh.xcworkspace/xcuserdata/munjisu.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/Darner-dan-uh/Darner-dan-uh.xcworkspace/xcuserdata/munjisu.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000..81a27da --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh.xcworkspace/xcuserdata/munjisu.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +======= + uuid = "58BD4AF2-9CBD-44F9-9514-E520A4AC46A8" + shouldBeEnabled = "No" + ignoreCount = "0" + continueAfterRunningActions = "No" + filePath = "Darner-dan-uh/Source/NetWorking/DarnerAPI.swift" + startingColumnNumber = "9223372036854775807" + endingColumnNumber = "9223372036854775807" + startingLineNumber = "126" + endingLineNumber = "126" + landmarkName = "parameter" + landmarkType = "24"> +>>>>>>> MypageNetworking + + + + + + + + + + + + + + + + diff --git a/Darner-dan-uh/Darner-dan-uh/AppDelegate.swift b/Darner-dan-uh/Darner-dan-uh/AppDelegate.swift deleted file mode 100644 index 7fa769d..0000000 --- a/Darner-dan-uh/Darner-dan-uh/AppDelegate.swift +++ /dev/null @@ -1,37 +0,0 @@ -// -// AppDelegate.swift -// Darner-dan-uh -// -// Created by 이현욱 on 2020/09/03. -// Copyright © 2020 이현욱. All rights reserved. -// - -import UIKit - -@UIApplicationMain -class AppDelegate: UIResponder, UIApplicationDelegate { - - - - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - // Override point for customization after application launch. - return true - } - - // MARK: UISceneSession Lifecycle - - func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { - // Called when a new scene session is being created. - // Use this method to select a configuration to create the new scene with. - return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) - } - - func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { - // Called when the user discards a scene session. - // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. - // Use this method to release any resources that were specific to the discarded scenes, as they will not return. - } - - -} - diff --git a/Darner-dan-uh/Darner-dan-uh/Base.lproj/Main.storyboard b/Darner-dan-uh/Darner-dan-uh/Base.lproj/Main.storyboard deleted file mode 100644 index 93d487f..0000000 --- a/Darner-dan-uh/Darner-dan-uh/Base.lproj/Main.storyboard +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Darner-dan-uh/Darner-dan-uh/Base/Base.lproj/Main.storyboard b/Darner-dan-uh/Darner-dan-uh/Base/Base.lproj/Main.storyboard new file mode 100644 index 0000000..b3c090f --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Base/Base.lproj/Main.storyboard @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Darner-dan-uh/Darner-dan-uh/Base/Mypage.storyboard b/Darner-dan-uh/Darner-dan-uh/Base/Mypage.storyboard new file mode 100644 index 0000000..b18c581 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Base/Mypage.storyboard @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Darner-dan-uh/Darner-dan-uh/Info.plist b/Darner-dan-uh/Darner-dan-uh/Info.plist index 2a3483c..602be55 100644 --- a/Darner-dan-uh/Darner-dan-uh/Info.plist +++ b/Darner-dan-uh/Darner-dan-uh/Info.plist @@ -2,8 +2,16 @@ - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + + UIAppFonts + + BinggraeMelona-Bold + BinggraeMelona + CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -20,25 +28,6 @@ 1 LSRequiresIPhoneOS - UIApplicationSceneManifest - - UIApplicationSupportsMultipleScenes - - UISceneConfigurations - - UIWindowSceneSessionRoleApplication - - - UISceneConfigurationName - Default Configuration - UISceneDelegateClassName - $(PRODUCT_MODULE_NAME).SceneDelegate - UISceneStoryboardFile - Main - - - - UILaunchStoryboardName LaunchScreen UIMainStoryboardFile diff --git a/Darner-dan-uh/Darner-dan-uh/MyPage/ModifyMyPageVC.swift b/Darner-dan-uh/Darner-dan-uh/MyPage/ModifyMyPageVC.swift new file mode 100644 index 0000000..9953198 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/MyPage/ModifyMyPageVC.swift @@ -0,0 +1,39 @@ +// +// ModifyMyPageVC.swift +// Darner-dan-uh +// +// Created by 문지수 on 2020/10/16. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +class ModifyMyPageVC: UIViewController { + + @IBOutlet weak var profileImage: UIImageView! + @IBOutlet weak var nickNameLabel: UILabel! + @IBOutlet weak var enterNickNameLabel: UILabel! + @IBOutlet weak var passwordLabel: UILabel! + @IBOutlet weak var enterPasswordLabel: UILabel! + @IBOutlet weak var modifyBtn: UIButton! + + override func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + } + + func textfieldBorderLineStyle(_ nameOfTextField: UITextField) { + let border = CALayer() + let width = CGFloat(1.0) + + border.borderColor = UIColor.darkGray.cgColor + border.frame = CGRect(x: 0, y: nameOfTextField.frame.size.height - width, width: nameOfTextField.frame.size.width, height: nameOfTextField.frame.size.height) + + border.borderWidth = width + nameOfTextField.layer.addSublayer(border) + nameOfTextField.layer.masksToBounds = true + + } + +} diff --git a/Darner-dan-uh/Darner-dan-uh/MypageViewController.swift b/Darner-dan-uh/Darner-dan-uh/MypageViewController.swift new file mode 100644 index 0000000..f1c03de --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/MypageViewController.swift @@ -0,0 +1,50 @@ +// +// MypageViewController.swift +// Darner-dan-uh +// +// Created by 문지수 on 2020/10/26. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +class MypageViewController: UIViewController { + + + @IBOutlet weak var profileImage: UIImageView! + @IBOutlet weak var nickNamgeLabel: UILabel! + @IBOutlet weak var modifyProfileBtn: UIButton! + @IBOutlet weak var selectCharacterBtn: UIButton! + @IBOutlet weak var logOutBtn: UIButton! + + override func viewDidLoad() { + super.viewDidLoad() + + //프로필 사진 둥글게 + profileImage.layer.cornerRadius = 55 + profileImage.layer.borderWidth = 1 + profileImage.layer.borderColor = UIColor.clear.cgColor + profileImage.clipsToBounds = true + //프로필 사진 테두리 + profileImage.layer.borderWidth = 2 + profileImage.layer.borderColor = UIColor.black.cgColor + //버튼 테두리 둥글게 + modifyProfileBtn.layer.cornerRadius = 15 + selectCharacterBtn.layer.cornerRadius = 15 + //버튼 테두리 색 + selectCharacterBtn.layer.borderColor = UIColor.mainColor.cgColor + + + } + + +} + +extension UIColor { + + class var mainColor: UIColor { + return UIColor(red: 253.0 / 255.0, green: 125.0 / 255.0, blue: 128.0 / 255.0, alpha: 1.0) + } + +} + diff --git a/Darner-dan-uh/Darner-dan-uh/Resource/BinggraeMelona-Bold.ttf b/Darner-dan-uh/Darner-dan-uh/Resource/BinggraeMelona-Bold.ttf new file mode 100644 index 0000000..5e8ff5f Binary files /dev/null and b/Darner-dan-uh/Darner-dan-uh/Resource/BinggraeMelona-Bold.ttf differ diff --git a/Darner-dan-uh/Darner-dan-uh/Resource/BinggraeMelona.ttf b/Darner-dan-uh/Darner-dan-uh/Resource/BinggraeMelona.ttf new file mode 100644 index 0000000..e38adf7 Binary files /dev/null and b/Darner-dan-uh/Darner-dan-uh/Resource/BinggraeMelona.ttf differ diff --git a/Darner-dan-uh/Darner-dan-uh/SceneDelegate.swift b/Darner-dan-uh/Darner-dan-uh/SceneDelegate.swift deleted file mode 100644 index 0664b85..0000000 --- a/Darner-dan-uh/Darner-dan-uh/SceneDelegate.swift +++ /dev/null @@ -1,53 +0,0 @@ -// -// SceneDelegate.swift -// Darner-dan-uh -// -// Created by 이현욱 on 2020/09/03. -// Copyright © 2020 이현욱. All rights reserved. -// - -import UIKit - -class SceneDelegate: UIResponder, UIWindowSceneDelegate { - - var window: UIWindow? - - - func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { - // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. - // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. - // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). - guard let _ = (scene as? UIWindowScene) else { return } - } - - func sceneDidDisconnect(_ scene: UIScene) { - // Called as the scene is being released by the system. - // This occurs shortly after the scene enters the background, or when its session is discarded. - // Release any resources associated with this scene that can be re-created the next time the scene connects. - // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead). - } - - func sceneDidBecomeActive(_ scene: UIScene) { - // Called when the scene has moved from an inactive state to an active state. - // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. - } - - func sceneWillResignActive(_ scene: UIScene) { - // Called when the scene will move from an active state to an inactive state. - // This may occur due to temporary interruptions (ex. an incoming phone call). - } - - func sceneWillEnterForeground(_ scene: UIScene) { - // Called as the scene transitions from the background to the foreground. - // Use this method to undo the changes made on entering the background. - } - - func sceneDidEnterBackground(_ scene: UIScene) { - // Called as the scene transitions from the foreground to the background. - // Use this method to save data, release shared resources, and store enough scene-specific state information - // to restore the scene back to its current state. - } - - -} - diff --git a/Darner-dan-uh/Darner-dan-uh/Source 2/ViewModel/Modules/Memorization/MemorizationViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source 2/ViewModel/Modules/Memorization/MemorizationViewController.swift new file mode 100644 index 0000000..f25af3c --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source 2/ViewModel/Modules/Memorization/MemorizationViewController.swift @@ -0,0 +1,67 @@ +// +// MemorizationVC.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/10/08. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxSwift +import RxCocoa +final class MemorizationViewController: UIViewController { + + var wordtupeStr: String! + var wordtypeInt: Int! + private let disposeBag = DisposeBag() + + @IBOutlet weak var memorizeTapItem: UINavigationItem! + @IBOutlet weak var myPageBtn: UIButton! + @IBOutlet weak var lawBtn: UIButton! + @IBOutlet weak var traditionBtn: UIButton! + @IBOutlet weak var artBtn: UIButton! + @IBOutlet weak var harborBtn: UIButton! + @IBOutlet weak var agricultureBtn: UIButton! + @IBOutlet weak var militaryBtn: UIButton! + @IBOutlet weak var electricalEnergyBtn: UIButton! + @IBOutlet weak var coalBtn: UIButton! + + override func viewDidLoad() { + super.viewDidLoad() + bindAction() + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + self.tabBarController?.tabBar.isHidden = false + } +} + +extension MemorizationViewController { + private func bindAction() { + Observable.merge(lawBtn.rx.tap.map { self.wordtupeStr = "법률"; self.wordtypeInt = 1 }, + traditionBtn.rx.tap.map { self.wordtupeStr = "전통"; self.wordtypeInt = 2 }, + artBtn.rx.tap.map { self.wordtupeStr = "예술"; self.wordtypeInt = 3 }, + harborBtn.rx.tap.map { self.wordtupeStr = "항구"; self.wordtypeInt = 4 }, + agricultureBtn.rx.tap.map { self.wordtupeStr = "농업"; self.wordtypeInt = 5 }, + militaryBtn.rx.tap.map { self.wordtupeStr = "군사"; self.wordtypeInt = 6 }, + electricalEnergyBtn.rx.tap.map { self.wordtupeStr = "전력"; self.wordtypeInt = 7 }, + coalBtn.rx.tap.map { self.wordtupeStr = "석탄"; self.wordtypeInt = 8 } + ).debounce(.nanoseconds(1), scheduler: MainScheduler.instance) + .subscribe { _ in + let vc = self.makeVC(storyBoardName: .memo, identifier: .selectwordNumVC) as SelectWordNumViewController + vc.wordTypeStr = self.wordtupeStr + vc.wordTypeInt = self.wordtypeInt + self.navigationController?.pushViewController(vc, animated: true) + }.disposed(by: disposeBag) + + myPageBtn.rx.tap + .debounce(.nanoseconds(1500), scheduler: MainScheduler.instance) + .subscribe({ _ in + let vc = self.makeVC(storyBoardName: .myPage, identifier: ViewControllerName.myCharacterVC) + self.present(vc, animated: true, completion: nil) + }) + .disposed(by: disposeBag) + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Base.lproj/LaunchScreen.storyboard b/Darner-dan-uh/Darner-dan-uh/Source/Base/Base.lproj/LaunchScreen.storyboard similarity index 100% rename from Darner-dan-uh/Darner-dan-uh/Base.lproj/LaunchScreen.storyboard rename to Darner-dan-uh/Darner-dan-uh/Source/Base/Base.lproj/LaunchScreen.storyboard diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Base/Base.lproj/Main.storyboard b/Darner-dan-uh/Darner-dan-uh/Source/Base/Base.lproj/Main.storyboard new file mode 100644 index 0000000..7222b44 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Base/Base.lproj/Main.storyboard @@ -0,0 +1,887 @@ + + + + + + + + + + + + + BinggraeMelona-Bold + + + BinggraeMelona + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Base/Memorization.storyboard b/Darner-dan-uh/Darner-dan-uh/Source/Base/Memorization.storyboard new file mode 100644 index 0000000..c45c620 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Base/Memorization.storyboard @@ -0,0 +1,1048 @@ + + + + + + + + + + + + + + BinggraeMelona-Bold + + + BinggraeMelona + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Base/Mypage.storyboard b/Darner-dan-uh/Darner-dan-uh/Source/Base/Mypage.storyboard new file mode 100644 index 0000000..4f69b62 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Base/Mypage.storyboard @@ -0,0 +1,750 @@ + + + + + + + + + + + + + + BinggraeMelona-Bold + + + BinggraeMelona + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Base/Ranking.storyboard b/Darner-dan-uh/Darner-dan-uh/Source/Base/Ranking.storyboard new file mode 100644 index 0000000..3bb4052 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Base/Ranking.storyboard @@ -0,0 +1,303 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Base/Writing.storyboard b/Darner-dan-uh/Darner-dan-uh/Source/Base/Writing.storyboard new file mode 100644 index 0000000..fdc04d6 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Base/Writing.storyboard @@ -0,0 +1,289 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Extension/RankingCell.swift b/Darner-dan-uh/Darner-dan-uh/Source/Extension/RankingCell.swift new file mode 100644 index 0000000..19e09f9 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Extension/RankingCell.swift @@ -0,0 +1,42 @@ +// +// RankingCell.swift +// Darner-dan-uh +// +// Created by 문지수 on 2020/11/19. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +class RankingCell: UITableViewCell { + + @IBOutlet weak var RankingLbl: UILabel! + @IBOutlet weak var nickNameLbl: UILabel! + @IBOutlet weak var starImage: UIImageView! + +// var RankingData: RankingModel! { +// didSet { setUpView() } +// } +// +// private func setUpView() { +// self.RankingLbl?.text = "\(RankingData.ranking)" +// self.profileImage?.image = UIImage(named: RankingData.nickName) +// self.nickNameLbl?.text = RankingData.nickName +// } + +// private func setUpView() { +// self.RankingLbl?.text = "\(RankingData.rank)" +// self.nickNameLbl?.text = RankingData.name +// } + + override func awakeFromNib() { + super.awakeFromNib() + // Initialization code + } + + override func setSelected(_ selected: Bool, animated: Bool) { + super.setSelected(selected, animated: animated) + + // Configure the view for the selected state + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Extension/StackViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/Extension/StackViewController.swift new file mode 100644 index 0000000..d57ebf2 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Extension/StackViewController.swift @@ -0,0 +1,45 @@ +// +// StackViewController.swift +// Darner-dan-uh +// +// Created by 문지수 on 2020/12/04. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxSwift +import RxCocoa + +class StackViewController: UIViewController { + + @IBOutlet weak var rankingBtn: UIButton! + @IBOutlet weak var stackBtn: UIButton! + @IBOutlet weak var stackImage: UIImageView! + + let disposeBag = DisposeBag() + + override func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + navigationClear() + navigationImage() +// buttonAction() + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + self.navigationItem.hidesBackButton = true + } + +// func buttonAction() { +// stackBtn.rx.tap +// .subscribe{ _ in +// self.nextView(identifire: "ranking") +// }.disposed(by: disposeBag) +// } + + + +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Extension/UIButton.swift b/Darner-dan-uh/Darner-dan-uh/Source/Extension/UIButton.swift new file mode 100644 index 0000000..980818e --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Extension/UIButton.swift @@ -0,0 +1,15 @@ +// +// UIButton.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/10/14. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +extension UIButton { + func setTextColor(color: UIColor) { + return self.setTitleColor(color, for: .normal) + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Extension/UIColor.swift b/Darner-dan-uh/Darner-dan-uh/Source/Extension/UIColor.swift new file mode 100644 index 0000000..bd84d44 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Extension/UIColor.swift @@ -0,0 +1,28 @@ +// +// UIColor.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/10/14. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +extension UIColor { + static var customPink: UIColor { + return rgb(red: 253, green: 125, blue: 128, alpha: 1) + } + + static var customGray: UIColor { + return rgb(red: 242, green: 242, blue: 242, alpha: 0.72) + } + + static var customBlack: UIColor { + return rgb(red: 95, green: 89, blue: 89, alpha: 1) + } + + static func rgb(red: Int, green: Int, blue: Int, alpha: CGFloat) -> UIColor { + return .init(red: CGFloat(red) / 255, green: CGFloat(green) / 255, blue: CGFloat(blue) / 255, alpha: alpha) + } +} + diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Extension/UIView.swift b/Darner-dan-uh/Darner-dan-uh/Source/Extension/UIView.swift new file mode 100644 index 0000000..eb799a3 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Extension/UIView.swift @@ -0,0 +1,21 @@ +// +// UIView.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/11/27. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +extension UIView { + func shake() { + let animation = CABasicAnimation(keyPath: "position") + animation.duration = 0.07 + animation.repeatCount = 3 + animation.autoreverses = true + animation.fromValue = NSValue(cgPoint: CGPoint(x: self.center.x - 10, y: self.center.y)) + animation.toValue = NSValue(cgPoint: CGPoint(x: self.center.x + 10, y: self.center.y)) + self.layer.add(animation, forKey: "position") + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Extension/UIViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/Extension/UIViewController.swift new file mode 100644 index 0000000..c27da29 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Extension/UIViewController.swift @@ -0,0 +1,30 @@ +// +// UIViewController.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/10/28. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +extension UIViewController { + func presentAlert(message: String, style: UIAlertController.Style? = .alert, title: String, actionStyle: UIAlertAction.Style, handler: ((UIAlertAction) -> Void)?, secTitle: String? = nil, secActionStyle: UIAlertAction.Style? = nil, secHandler: ((UIAlertAction) -> Void)? = nil) { + let alert = UIAlertController(title: " ", message: message, preferredStyle: .alert) + let titleFont = [NSAttributedString.Key.font: UIFont(name: "BinggraeMelona", size: 17)] + let titleAttrString = NSMutableAttributedString(string: message, attributes: titleFont) + alert.setValue(titleAttrString, forKey:"attributedMessage") + + alert.addAction(UIAlertAction(title: title, style: actionStyle, handler: handler)) + if let existSecTitle = secTitle { alert.addAction(UIAlertAction(title: existSecTitle, style: secActionStyle!, handler: secHandler)) } + alert.view.subviews.first?.subviews.first?.subviews.first?.backgroundColor = .customGray + alert.view.tintColor = .black + present(alert, animated: true, completion: nil) + } + + func makeVC(storyBoardName: StoryBoardName? = .main, identifier: ViewControllerName) -> T where T: UIViewController { + let storyBoard = UIStoryboard(name: storyBoardName!.rawValue, bundle: nil) + let vc = storyBoard.instantiateViewController(identifier: identifier.rawValue) as! T + return vc + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Extension/ViewControllerName.swift b/Darner-dan-uh/Darner-dan-uh/Source/Extension/ViewControllerName.swift new file mode 100644 index 0000000..51a02a8 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Extension/ViewControllerName.swift @@ -0,0 +1,34 @@ +// +// StoryBoardNameEnum.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/11/02. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +enum StoryBoardName: String { + case main = "Main" + case myPage = "Mypage" + case writing = "Writing" + case ranking = "Ranking" + case memo = "Memorization" +} + +enum ViewControllerName: String { + case memoriazeMainVC = "MemorizationViewController" + case selectwordNumVC = "SelectWordNumViewController" + case testTableVC = "TestTableViewController" + case testVC = "TestViewController" + case testResultVC = "TestResultViewController" + case mainVC = "MainViewController" + case registerVC = "RegisterViewController" + case checkCertificationVC = "CheckCertificationNumberViewController" + case finishRegisterVC = "FinishRegisterViewController" + case tabbarVC = "TabbarViewController" + case characterCollectionVC = "CharacterCollectionViewController" + case setMainCharacterVC = "SetMainCharacterViewController" + case myCharacterVC = "MyCharacterViewController" + case mypageVC = "MypageViewController" +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Model/LevelModel.swift b/Darner-dan-uh/Darner-dan-uh/Source/Model/LevelModel.swift new file mode 100644 index 0000000..30cce71 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Model/LevelModel.swift @@ -0,0 +1,13 @@ +// +// LevelModel.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/12/06. +// Copyright © 2020 이현욱. All rights reserved. +// + +import Foundation + +struct LevelModel: Codable { + let level: Int +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Model/MemoModel.swift b/Darner-dan-uh/Darner-dan-uh/Source/Model/MemoModel.swift new file mode 100644 index 0000000..a443176 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Model/MemoModel.swift @@ -0,0 +1,23 @@ +// +// MemoModel.swift +// Darner-dan-uh +// +// Created by 문지수 on 2020/12/07. +// Copyright © 2020 이현욱. All rights reserved. +// + +import Foundation + +class MemoModel: Codable { + let content: String + + + init(content: String) { + self.content = content + } + + static var dummyDataList = [ + MemoModel(content: "DarnerDanuh"), + MemoModel(content: "Daaaarneeeer") + ] +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Model/MessageModel.swift b/Darner-dan-uh/Darner-dan-uh/Source/Model/MessageModel.swift new file mode 100644 index 0000000..a31c365 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Model/MessageModel.swift @@ -0,0 +1,13 @@ +// +// MessageModel.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/11/27. +// Copyright © 2020 이현욱. All rights reserved. +// + +import Foundation + +struct MessageModel: Codable { + var message: String +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Model/MypageModel.swift b/Darner-dan-uh/Darner-dan-uh/Source/Model/MypageModel.swift new file mode 100644 index 0000000..22c6a5d --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Model/MypageModel.swift @@ -0,0 +1,23 @@ +// +// MyPageModel.swift +// Darner-dan-uh +// +// Created by 문지수 on 2020/10/15. +// Copyright © 2020 이현욱. All rights reserved. +// + +import Foundation + +struct MypageModel: Codable { + + //let profileImage: String + let name: String + let userId: String + let ModifyProfile: String + let selectCharacter: String + +} + +struct passwordModel: Codable { + let password: String? +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Model/RankingModel.swift b/Darner-dan-uh/Darner-dan-uh/Source/Model/RankingModel.swift new file mode 100644 index 0000000..44984c8 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Model/RankingModel.swift @@ -0,0 +1,24 @@ +// +// RankingModel.swift +// Darner-dan-uh +// +// Created by 문지수 on 2020/11/20. +// Copyright © 2020 이현욱. All rights reserved. +// + +import Foundation + +struct RankingModel: Codable { + let rank: Int + let name: String +} + +struct Ranking: Codable { + let ranking: [RankingModel] +} +struct myRankingModel: Codable { + let rank: Int? + let message: String? + let ranking: String? + +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Model/TestResultModel.swift b/Darner-dan-uh/Darner-dan-uh/Source/Model/TestResultModel.swift new file mode 100644 index 0000000..f757987 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Model/TestResultModel.swift @@ -0,0 +1,16 @@ +// +// TestResultModel.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/12/04. +// Copyright © 2020 이현욱. All rights reserved. +// + +import Foundation + +import RxSwift + +struct TestRusultModel { + let word: String + let correct: Bool +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Model/TokenMessageModel.swift b/Darner-dan-uh/Darner-dan-uh/Source/Model/TokenMessageModel.swift new file mode 100644 index 0000000..66634c0 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Model/TokenMessageModel.swift @@ -0,0 +1,14 @@ +// +// File.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/11/27. +// Copyright © 2020 이현욱. All rights reserved. +// + +import Foundation + +struct TokenMessageModel: Codable { + var token: String? + var message: String? +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Model/WordModel.swift b/Darner-dan-uh/Darner-dan-uh/Source/Model/WordModel.swift new file mode 100644 index 0000000..74b5065 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Model/WordModel.swift @@ -0,0 +1,18 @@ +// +// WordModel.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/11/27. +// Copyright © 2020 이현욱. All rights reserved. +// + +import Foundation + +struct WordModel: Codable { + let content: [Content]? + let message: String? +} + +struct Content: Codable { + let korea, english: String +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Modules/Login/LoginViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/Modules/Login/LoginViewController.swift new file mode 100644 index 0000000..d9ca948 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Modules/Login/LoginViewController.swift @@ -0,0 +1,89 @@ +// +// LoginVC.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/10/14. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxSwift +import RxCocoa + +final class LoginViewController: UIViewController { + var autoLoginFlag: Bool! = false + let viewModel = LoginViewModel() + let disposeBag = DisposeBag() + static var id: String! + + @IBOutlet weak var idTextField: UITextField! + @IBOutlet weak var pwTextField: UITextField! + @IBOutlet weak var autoLoginLblBtn: UIButton! + @IBOutlet weak var autoLoginBtn: UIButton! + @IBOutlet weak var loginBtn: UIButton! + @IBOutlet weak var popVCBtn: UIButton! + + override func viewDidLoad() { + super.viewDidLoad() + bindAction() + bind() + } +} + + + +extension LoginViewController { + private func bindAction() { + loginBtn.rx.tap + .debounce(.seconds(2), scheduler: MainScheduler.instance) + .withLatestFrom(Observable.combineLatest(self.idTextField.rx.text.orEmpty, self.pwTextField.rx.text.orEmpty)) + .map { DarnerAPI.login(userId: $0.0, password: $0.1) } + .flatMap { (request:DarnerAPI) -> Observable in + return DarnerAPIClient.shared.networkingResult(from: request) + } + .subscribe { (model:TokenMessageModel) in + guard let nToken = model.token else { self.loginBtn.shake(); return } + UserDefaults.standard.setValue(self.idTextField.text, forKey: "id") + UserDefaults.standard.setValue(nToken, forKey: "token") + let vc = self.makeVC(identifier: ViewControllerName.tabbarVC) + vc.modalPresentationStyle = .fullScreen + DispatchQueue.main.async { + self.navigationController?.pushViewController(vc, animated: true) + } + } onError: { (_:Error) in + self.loginBtn.shake() + }.disposed(by: self.disposeBag) + + Observable.merge( + autoLoginBtn.rx.tap.map {}, + autoLoginLblBtn.rx.tap.map {} + ).map { self.autoLoginBtn.isSelected.toggle() } + .map { if self.autoLoginBtn.isSelected { + self.autoLoginBtn.setImage(UIImage(named: "Icon ionic-ios-checkmark-circle"), for: .selected) + } else { + self.autoLoginBtn.setImage(UIImage(named: "Icon material-radio-button-unchecked"), for: .normal) + }} + .subscribe() + .disposed(by: disposeBag) + + popVCBtn.rx.tap + .subscribe { _ in + self.navigationController?.popViewController(animated: true) + }.disposed(by: disposeBag) + } + + private func bind() { + let input = LoginViewModel.Input.init(idTextFieldSubject: idTextField.rx.text.orEmpty.asObservable(), pwTextFieldSubject: pwTextField.rx.text.orEmpty.asObservable()) + + let output = viewModel.transform(input) + + output.result.drive (onNext:{ b in + self.loginBtn.layer.borderColor = b ? UIColor.customPink.cgColor : UIColor.black.cgColor + self.loginBtn.backgroundColor = b ? .customPink : .white + b ? self.loginBtn.setTextColor(color: .white) : self.loginBtn.setTextColor(color: .black) + self.loginBtn.isUserInteractionEnabled = b + }).disposed(by: disposeBag) + } +} + diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Modules/Memorization/Cell/TestCollectionViewCell.swift b/Darner-dan-uh/Darner-dan-uh/Source/Modules/Memorization/Cell/TestCollectionViewCell.swift new file mode 100644 index 0000000..3e56199 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Modules/Memorization/Cell/TestCollectionViewCell.swift @@ -0,0 +1,29 @@ +// +// TestCollectionViewCell.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/11/24. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxSwift +import RxCocoa + +class TestCollectionViewCell: UICollectionViewCell { + static let cellName = "TestCollectionViewCell" + var sign: ((String) -> Void)? = nil + + @IBOutlet weak var wordMeanTextField: UITextField! + @IBOutlet weak var nextBtn: UIButton! + @IBOutlet weak var wordTestLbl: UILabel! + + override func awakeFromNib() { + super.awakeFromNib() + } + + @IBAction func b(_ sender: UIButton) { + sign?(wordMeanTextField.text!) + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Modules/Memorization/Cell/WordCell.swift b/Darner-dan-uh/Darner-dan-uh/Source/Modules/Memorization/Cell/WordCell.swift new file mode 100644 index 0000000..0b6046a --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Modules/Memorization/Cell/WordCell.swift @@ -0,0 +1,28 @@ +// +// WordCell.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/11/01. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +class WordCell: UITableViewCell { + static let cellName = "WordCell" + + @IBOutlet weak var wordKoreanMeanLbl: UILabel! + @IBOutlet weak var wordEnglishMeanLbl: UILabel! + + override func awakeFromNib() { + super.awakeFromNib() + // Initialization code + } + + override func setSelected(_ selected: Bool, animated: Bool) { + super.setSelected(selected, animated: animated) + + // Configure the view for the selected state + } + +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Modules/Memorization/Cell/WordResultCell.swift b/Darner-dan-uh/Darner-dan-uh/Source/Modules/Memorization/Cell/WordResultCell.swift new file mode 100644 index 0000000..633e55a --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Modules/Memorization/Cell/WordResultCell.swift @@ -0,0 +1,28 @@ +// +// WordResultCell.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/11/03. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +class WordResultCell: UITableViewCell { + static let cellName = "WordResultCell" + + @IBOutlet weak var wordMeanLbl: UILabel! + @IBOutlet weak var isCorrectLbl: UILabel! + + override func awakeFromNib() { + super.awakeFromNib() + // Initialization code + } + + override func setSelected(_ selected: Bool, animated: Bool) { + super.setSelected(selected, animated: animated) + + // Configure the view for the selected state + } + +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Modules/Memorization/MemorizationViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/Modules/Memorization/MemorizationViewController.swift new file mode 100644 index 0000000..280f038 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Modules/Memorization/MemorizationViewController.swift @@ -0,0 +1,67 @@ +// +// MemorizationVC.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/10/08. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxSwift +import RxCocoa +final class MemorizationViewController: UIViewController { + + var wordtupeStr: String! + var wordtypeInt: Int! + private let disposeBag = DisposeBag() + + @IBOutlet weak var memorizeTapItem: UINavigationItem! + @IBOutlet weak var myPageBtn: UIButton! + @IBOutlet weak var lawBtn: UIButton! + @IBOutlet weak var traditionBtn: UIButton! + @IBOutlet weak var artBtn: UIButton! + @IBOutlet weak var harborBtn: UIButton! + @IBOutlet weak var agricultureBtn: UIButton! + @IBOutlet weak var militaryBtn: UIButton! + @IBOutlet weak var electricalEnergyBtn: UIButton! + @IBOutlet weak var coalBtn: UIButton! + + override func viewDidLoad() { + super.viewDidLoad() + bindAction() + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + self.tabBarController?.tabBar.isHidden = false + } +} + +extension MemorizationViewController { + private func bindAction() { + Observable.merge(lawBtn.rx.tap.map { self.wordtupeStr = "과일"; self.wordtypeInt = 1 }, + traditionBtn.rx.tap.map { self.wordtupeStr = "채소"; self.wordtypeInt = 2 }, + artBtn.rx.tap.map { self.wordtupeStr = "항공"; self.wordtypeInt = 3 }, + harborBtn.rx.tap.map { self.wordtupeStr = "항구"; self.wordtypeInt = 4 }, + agricultureBtn.rx.tap.map { self.wordtupeStr = "농업"; self.wordtypeInt = 5 }, + militaryBtn.rx.tap.map { self.wordtupeStr = "군사"; self.wordtypeInt = 6 }, + electricalEnergyBtn.rx.tap.map { self.wordtupeStr = "전력"; self.wordtypeInt = 7 }, + coalBtn.rx.tap.map { self.wordtupeStr = "석탄"; self.wordtypeInt = 8 } + ).debounce(.nanoseconds(1), scheduler: MainScheduler.instance) + .subscribe { _ in + let vc = self.makeVC(storyBoardName: .memo, identifier: .selectwordNumVC) as SelectWordNumViewController + vc.wordTypeStr = self.wordtupeStr + vc.wordTypeInt = self.wordtypeInt + self.navigationController?.pushViewController(vc, animated: true) + }.disposed(by: disposeBag) + + myPageBtn.rx.tap + .observeOn(MainScheduler.instance) + .map{ _ in + let vc = self.makeVC(storyBoardName: .myPage, identifier: ViewControllerName.mypageVC) + self.present(vc, animated: true, completion: nil) + }.subscribe() + .disposed(by: disposeBag) + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Modules/Memorization/SelectWordNumViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/Modules/Memorization/SelectWordNumViewController.swift new file mode 100644 index 0000000..7119060 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Modules/Memorization/SelectWordNumViewController.swift @@ -0,0 +1,81 @@ +// +// SelectWordNumVC.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/10/28. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxCocoa +import RxSwift + +final class SelectWordNumViewController: UIViewController { + var wordTypeStr: String! + var wordTypeInt: Int! + var wordNum = 10 + let disposeBag = DisposeBag() + + @IBOutlet weak var backVCBtn: UIButton! + @IBOutlet weak var minusWordNumBtn: UIButton! + @IBOutlet weak var plusWordNumBtn: UIButton! + @IBOutlet weak var nextVCBtn: UIButton! + @IBOutlet weak var wordNumLbl: UILabel! + + override func viewDidLoad() { + super.viewDidLoad() + bindAction() + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + self.tabBarController?.tabBar.isHidden = true + } +} + +extension SelectWordNumViewController { + private func bindAction() { + minusWordNumBtn.rx.tap + .map { self.editWordCount(self.minusWordNumBtn, self.wordNum)} + .bind(onNext: { num in + self.wordNumLbl.text = String(num) + }).disposed(by: disposeBag) + + plusWordNumBtn.rx.tap + .map { self.editWordCount(self.plusWordNumBtn, self.wordNum)} + .bind(onNext: { num in + self.wordNumLbl.text = String(num) + }).disposed(by: disposeBag) + + backVCBtn.rx.tap + .bind(onNext: { + self.navigationController?.popViewController(animated: true) + }).disposed(by: disposeBag) + + nextVCBtn.rx.tap + .bind(onNext: { + let vc: TestTableViewController = self.makeVC(storyBoardName: .memo, identifier: .testTableVC) + vc.wordNum = self.wordNum + vc.wordTypeInt = self.wordTypeInt + vc.wordTypeStr = self.wordTypeStr + self.navigationController?.pushViewController(vc, animated: true) + }).disposed(by: disposeBag) + } + + private func editWordCount(_ sender: UIButton,_ num: Int) -> Int { + if num <= 0 || num >= 100 { return num } + switch sender.tag { + case 0: + wordNum = num - 1 + return wordNum + + case 1: + wordNum = num + 1 + return num + 1 + + default: + return 0 + } + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Modules/Memorization/TestResultViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/Modules/Memorization/TestResultViewController.swift new file mode 100644 index 0000000..91875fb --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Modules/Memorization/TestResultViewController.swift @@ -0,0 +1,71 @@ +// +// TestResultViewController.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/11/01. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxSwift +import RxCocoa + +final class TestResultViewController: UIViewController { + var arr: Observable<[TestRusultModel]>! = nil + let disposeBag = DisposeBag() + var correctCnt = 0 + + @IBOutlet weak var tableView: UITableView! + @IBOutlet weak var finishWordTestBtn: UIButton! + + override func viewDidLoad() { + super.viewDidLoad() + bindAction() + bindUI() + // Do any additional setup after loading the view. + } +} + +extension TestResultViewController { + private func bindUI() { + arr.bind(to: tableView.rx.items(cellIdentifier: WordResultCell.cellName, cellType: WordResultCell.self)) { _, result, cell in + cell.wordMeanLbl.text = result.word + if result.correct { + cell.isCorrectLbl.text = "정답" + cell.isCorrectLbl.textColor = .customBlack + self.correctCnt += 1 + } else { + cell.isCorrectLbl.text = "오답" + cell.isCorrectLbl.textColor = .customPink + } + print(self.correctCnt) + }.disposed(by: disposeBag) + + let id = UserDefaults.standard.value(forKey: "id") as! String + let os: Observable = DarnerAPIClient.shared.networkingResult(from: .savedata(id: id, count: self.correctCnt)) + .retry() + + os.subscribe(onNext: { model in + if model.message == "success" { + print("success") + } else { + print("fail") + } + }).disposed(by: disposeBag) + } + + private func bindAction() { + finishWordTestBtn.rx.tap + .map { _ in + guard var controllers = self.navigationController?.viewControllers else { return } + let count = controllers.count + if count > 2 { + controllers.removeSubrange(1...count-2) + } + self.navigationController?.viewControllers = controllers + self.navigationController?.popViewController(animated: true) + }.subscribe() + .disposed(by: disposeBag) + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Modules/Memorization/TestTableViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/Modules/Memorization/TestTableViewController.swift new file mode 100644 index 0000000..293cf78 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Modules/Memorization/TestTableViewController.swift @@ -0,0 +1,67 @@ +// +// TestTableViewController.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/11/01. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxSwift +import RxCocoa + +final class TestTableViewController: UIViewController { + var wordTypeStr: String! + var wordTypeInt: Int! + var wordNum: Int! + private let disposeBag = DisposeBag() + + @IBOutlet weak var wordTypeLbl: UILabel! + @IBOutlet weak var testBtn: UIButton! + @IBOutlet weak var popVCBtn: UIButton! + @IBOutlet weak var tableView: UITableView! + + override func viewDidLoad() { + super.viewDidLoad() + bindAction() + bindUI() + // Do any additional setup after loading the view. + } + +} + +extension TestTableViewController { + private func bindAction() { + testBtn.rx.tap.map { + self.presentAlert(message: "단어 시험을 볼 준비가 됐나요?", style: .alert, title: "더 공부할게요", actionStyle: .destructive, handler: nil, secTitle: "준비됐습니다", secActionStyle: .default) { _ in + let vc: TestViewController = self.makeVC(storyBoardName: .memo, identifier: .testVC) + vc.wordnum = self.wordNum + self.navigationController?.pushViewController(vc, animated: true) + } + }.subscribe() + .disposed(by: disposeBag) + + popVCBtn.rx.tap + .take(1) + .map { + self.navigationController?.popViewController(animated: true) + } + .subscribe() + .disposed(by: disposeBag) + } + + private func bindUI() { + self.wordTypeLbl.text = self.wordTypeStr + self.testBtn.layer.borderColor = UIColor.customPink.cgColor + self.tabBarController?.tabBar.isHidden = false + + let words: Observable = DarnerAPIClient.shared.networkingResult(from: .wordGenre(word_id: String(self.wordTypeInt), number: String(self.wordNum))) + words.map { $0.content! } + .bind(to: tableView.rx.items(cellIdentifier: WordCell.cellName, cellType: WordCell.self)) { idx, model, cell in + cell.wordEnglishMeanLbl.text = model.english + cell.wordKoreanMeanLbl.text = model.korea + }.disposed(by: disposeBag) + } + +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Modules/Memorization/TestViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/Modules/Memorization/TestViewController.swift new file mode 100644 index 0000000..c928be9 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Modules/Memorization/TestViewController.swift @@ -0,0 +1,103 @@ +// +// TestViewController.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/11/01. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxSwift +import RxCocoa + +final class TestViewController: UIViewController { + lazy var resultWord = BehaviorSubject<[TestRusultModel]>(value: list) + var list: [TestRusultModel] = [] + private let disposeBag = DisposeBag() + var wordnum: Int = 0 + + @IBOutlet weak var collectionView: UICollectionView! + @IBOutlet weak var popVCBtn: UIButton! + + override func viewDidLoad() { + super.viewDidLoad() + bindUI() + bindAction() + // Do any additional setup after loading the view. + } +} + +extension TestViewController { + private func bindAction() { + popVCBtn.rx.tap + .map { + self.presentAlert(message: "시험을 포기하시겠어요?", style: .alert, title: "포기하겠습니다", actionStyle: .destructive, handler: { _ in + self.navigationController?.popViewController(animated: true) + }, secTitle: "계속 할게요", secActionStyle: .default, secHandler: nil) + }.subscribe().disposed(by: disposeBag) + } + + private func bindUI() { + collectionView.rx + .setDelegate(self) + .disposed(by: disposeBag) + + let words: Observable = DarnerAPIClient.shared.networkingResult(from:.wordTest) + words.map { $0.content! } + .bind(to: collectionView.rx.items(cellIdentifier: TestCollectionViewCell.cellName, cellType: TestCollectionViewCell.self)) { idx, model, cell in + let word: String + if idx % 2 == 0 { + cell.wordTestLbl?.text = model.korea + word = model.english + } else { + cell.wordTestLbl?.text = model.english + word = model.korea + } + cell.sign = { txt in + if txt == "" { + self.presentAlert(message: "값이 비었습니다.", title: "정답을 채워주세요.", actionStyle: .destructive, handler: nil) + return + } + self.checkValue(txt, word, cell.wordTestLbl.text!) + if idx == self.wordnum - 1 { + self.presentAlert(message: "마지막 문제입니다", title: "결과 확인하기", actionStyle: .destructive) { _ in + let vc = self.makeVC(storyBoardName: .memo, identifier: .testResultVC) as TestResultViewController + vc.arr = self.resultWord + self.navigationController?.pushViewController(vc, animated: true) + } + } + self.nextCell() + } + }.disposed(by: disposeBag) + } +} + +extension TestViewController { + func checkValue(_ userAnswer: String, _ answer: String, _ mean: String) { + if userAnswer == answer { + self.list.append(TestRusultModel(word: mean, correct: true)) + resultWord.onNext(self.list) + } else { + self.list.append(TestRusultModel(word: mean, correct: false)) + resultWord.onNext(self.list) + } + } + + func nextCell() { + let cellSize = CGSize(width: self.collectionView.frame.width, height: self.collectionView.frame.height); + let contentOffset = self.collectionView.contentOffset; + self.collectionView.scrollRectToVisible(CGRect(origin: CGPoint(x: contentOffset.x + cellSize.width, y: contentOffset.y), size: CGSize(width: 414, height: 730)), animated: true) + } +} + +extension TestViewController: UICollectionViewDelegateFlowLayout { + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { + return 0 + } + + + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + return CGSize(width: 414, height: 730) + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Modules/MyPage/CharacterCollectionViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/Modules/MyPage/CharacterCollectionViewController.swift new file mode 100644 index 0000000..1d49735 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Modules/MyPage/CharacterCollectionViewController.swift @@ -0,0 +1,80 @@ +// +// CharacterCollectionViewController.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/11/05. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxSwift +import RxCocoa + +final class CharacterCollectionViewController: UIViewController { + private let disposeBag = DisposeBag() + let arr: [Character] = [ + Character(name: "핑키", photo: "핑크알", level: 1, lock: ""), + Character(name: "핑키핑키", photo: "핑크병아리", level: 2, lock: ""), + Character(name: "레몬", photo: "노란알", level: 3, lock: ""), + Character(name: "계란말이", photo: "노란병아리", level: 5, lock: ""), + Character(name: "블루레몬", photo: "파란알", level: 10, lock: ""), + Character(name: "블루베리", photo: "파란병아리", level: 30, lock: "") + ] + + @IBOutlet weak var collectionView: UICollectionView! + @IBOutlet weak var firstCharacterBtn: UIButton! + @IBOutlet weak var cancelBtn: UIBarButtonItem! + @IBOutlet weak var secCharacterBtn: UIButton! + @IBOutlet weak var thirdCharacterBtn: UIButton! + @IBOutlet weak var fourthCharacterBtn: UIButton! + @IBOutlet weak var fifthCharacterBtn: UIButton! + @IBOutlet weak var sixCharacterBtn: UIButton! + + override func viewDidLoad() { + super.viewDidLoad() + bindAction() +// bindUI() + // Do any additional setup after loading the view. + } +} + +extension CharacterCollectionViewController { +// private func bindUI() { +// Observable.just(arr) +// .bind(to: collectionView.rx.items(cellIdentifier: CharacterCollectionViewCell.cellName, cellType: CharacterCollectionViewCell.self) { idx, model, cell in +// cell.lbl.text = model.name +// if model.level == 1 { +// +// } +// cell.imageView.image = UIImage(named: model.photo) +// }).disposed(by:disposeBag) +// } + + private func bindAction() { + Observable.merge(firstCharacterBtn.rx.tap.map {}, + secCharacterBtn.rx.tap.map {}, + thirdCharacterBtn.rx.tap.map {}, + fourthCharacterBtn.rx.tap.map {}, + fifthCharacterBtn.rx.tap.map {}, + sixCharacterBtn.rx.tap.map {} + ) + .subscribe({ _ in + let vc = self.makeVC(storyBoardName: .myPage, identifier: .setMainCharacterVC) + self.present(vc, animated: true, completion: nil) + }).disposed(by: disposeBag) + + cancelBtn.rx.tap + .subscribe { _ in + self.dismiss(animated: true, completion: nil) + }.disposed(by: disposeBag) + } +} + + +struct Character { + let name: String + let photo: String + let level: Int? + let lock: String? +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Modules/MyPage/EnterPwViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/Modules/MyPage/EnterPwViewController.swift new file mode 100644 index 0000000..b635abf --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Modules/MyPage/EnterPwViewController.swift @@ -0,0 +1,80 @@ +// +// EnterPwViewController.swift +// Darner-dan-uh +// +// Created by 문지수 on 2020/11/05. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxSwift +import RxCocoa + +class EnterPwViewController: UIViewController { + + @IBOutlet weak var titleLbl: UILabel! + @IBOutlet weak var subLbl: UILabel! + @IBOutlet weak var passwordLbl: UILabel! + @IBOutlet weak var passwordTxtField: UITextField! + @IBOutlet weak var nextBtn: UIButton! + @IBOutlet weak var cancleBtn: UIBarButtonItem! + + private let disposeBag = DisposeBag() + + override func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + + nextBtn.buttonStyle() + passwordTxtField.isSecureTextEntry = true + + passwordTxtField.underLine() + password() + self.bindAction() + } + + + func password() { + nextBtn.rx.tap + .map{ self.passwordTxtField.text!} + .map { DarnerAPI.verifyPassword(pw: $0)} + .flatMap {request -> Observable in + return DarnerAPIClient.shared.networkingResult(from: request) + }.subscribe { model in + self.passwordTxtField.text = model.password + }.disposed(by: disposeBag) + } + + func bindAction() { + nextBtn.rx.tap + .subscribe({ _ in + self.nextModal(indentifier: "modify") + }).disposed(by: disposeBag) + +// cancleBtn.rx.tap +// .subscribe(onNext: { _ in +// self.backView(identifire: "mypage") +// }).disposed(by: disposeBag) + + + } + + +} + +extension UIViewController { + func nextView(identifier: String) { + let viewController = self.storyboard?.instantiateViewController(identifier: identifier) + navigationController?.pushViewController(viewController!, animated: true) + } + + func nextModal(indentifier: String) { + let viewController = self.storyboard?.instantiateViewController(identifier: indentifier) + viewController?.modalPresentationStyle = .fullScreen + present(viewController!, animated: true, completion: nil) + } +} + + diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Modules/MyPage/ModifyViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/Modules/MyPage/ModifyViewController.swift new file mode 100644 index 0000000..5b10c9e --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Modules/MyPage/ModifyViewController.swift @@ -0,0 +1,108 @@ +// +// ModifyViewController.swift +// Darner-dan-uh +// +// Created by 문지수 on 2020/11/05. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxSwift +import RxCocoa + +class ModifyViewController: UIViewController { + + @IBOutlet weak var profileImage: UIImageView! + @IBOutlet weak var nickNameLbl: UILabel! + @IBOutlet weak var idLbl: UILabel! + @IBOutlet weak var nickNameTxtField: UITextField! + @IBOutlet weak var modifyBtn: UIButton! + + private let disposeBag = DisposeBag() + private let viewModel = MypageViewModel() + + override func viewDidLoad() { + super.viewDidLoad() + + self.navigationItem.title = "마이페이지" + + nickNameTxtField.clearButtonMode = .whileEditing + + // Do any additional setup after loading the view. + profileImage.layer.cornerRadius = profileImage.frame.width/2 + modifyBtn.buttonStyle() + nickNameTxtField.underLine() + + viewProfile() + modifyProfile() + bindAction() + } + + func viewProfile() { + let mypage: Observable = DarnerAPIClient.shared.networkingResult(from: .myProfile) + mypage.asObservable().subscribe(onNext: { model in + self.nickNameLbl.text = model.name + self.idLbl.text = model.userId + }).disposed(by: disposeBag) + } + + func modifyProfile() { + + let mypage: Observable = DarnerAPIClient.shared.networkingResult(from: .updateProfile(changeId: self.nickNameTxtField.text!)) + + modifyBtn.rx.tap + .map{ self.nickNameTxtField.text} + .subscribe(onNext: { _ in + mypage.asObservable().subscribe(onNext: { model in + self.nickNameTxtField.text = model.name + }).disposed(by: self.disposeBag) + }).disposed(by: disposeBag) + + + } + + func bindAction() { + modifyBtn.rx.tap + .subscribe(onNext: { _ in + self.presentAlert(message: "", title: "회원정보 수정완료", actionStyle: .default, handler: nil) + }).disposed(by: disposeBag) + } + +struct a: Codable { + let code: Int + let name: String + } +} + +extension UITextField { + func underLine() { + let border = CALayer() + let width = CGFloat(1.0) + border.borderColor = UIColor.customGray.cgColor + border.frame = CGRect(x: 0, y: self.frame.size.height - width, width: self.frame.size.width, height: self.frame.size.height) + border.borderWidth = width + border.borderColor = UIColor.black.cgColor + self.layer.addSublayer(border) + self.layer.masksToBounds = true + } +} + +extension UIButton { + func buttonStyle() { + self.layer.borderWidth = 2 + self.layer.borderColor = UIColor.customPink.cgColor + self.layer.cornerRadius = 15 + } +} + + + + + + + + + + + diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Modules/MyPage/MyCharacterViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/Modules/MyPage/MyCharacterViewController.swift new file mode 100644 index 0000000..0f03044 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Modules/MyPage/MyCharacterViewController.swift @@ -0,0 +1,73 @@ +// +// MyCharacterViewController.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/11/05. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxCocoa +import RxSwift + +class MyCharacterViewController: UIViewController { + private let disposeBag = DisposeBag() + + @IBOutlet weak var userIdLbl: UILabel! + @IBOutlet weak var imageView: UIImageView! + @IBOutlet weak var userLevelLbl: UILabel! + @IBOutlet weak var nextEvolutionLbl: UILabel! + @IBOutlet weak var showCharacterVCBtn: UIButton! + @IBOutlet weak var cancelBtn: UIBarButtonItem! + + override func viewDidLoad() { + super.viewDidLoad() + bindUI() + bindAction() + } +} + +extension MyCharacterViewController { + private func bindUI() { + let os: Observable = DarnerAPIClient.shared.networkingResult(from: .getLevel) + + os.subscribe(onNext: { model in + self.userLevelLbl.text = String(model.level) + switch model.level { + case 0...2: + self.nextEvolutionLbl.text = String(3) + case 3...9: + self.nextEvolutionLbl.text = String(10) + case 10...29: + self.nextEvolutionLbl.text = String(30) + default: + return + } + }).disposed(by: disposeBag) + + let id = UserDefaults.standard.value(forKey: "id") as! String + userIdLbl.text = id + + if imageView.image == nil { + imageView.image = UIImage(named: "핑크알") + } else { + let image = UserDefaults.standard.value(forKey: "image") as! UIImage + imageView.image = image + } + } + + private func bindAction() { + cancelBtn.rx.tap + .subscribe({_ in + self.dismiss(animated: true, completion: nil) + }).disposed(by: disposeBag) + + showCharacterVCBtn.rx.tap + .map { _ in + let vc = self.makeVC(storyBoardName: .myPage, identifier: .characterCollectionVC) + self.present(vc, animated: true, completion: nil) + }.subscribe() + .disposed(by: disposeBag) + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Modules/MyPage/MypageViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/Modules/MyPage/MypageViewController.swift new file mode 100644 index 0000000..745a2ab --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Modules/MyPage/MypageViewController.swift @@ -0,0 +1,40 @@ +// +// MypageViewController.swift +// Darner-dan-uh +// +// Created by 문지수 on 2020/11/05. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxSwift +import RxCocoa + +class MypageViewController: UIViewController { + + @IBOutlet weak var profileImage: UIImageView! + @IBOutlet weak var nickNameLbl: UILabel! + @IBOutlet weak var modifyBtn: UIButton! + @IBOutlet weak var characterBtn: UIButton! + + private let disposeBag = DisposeBag() + private let viewModel = SeeMypageViewModel() + + override func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + profileImage.layer.cornerRadius = profileImage.frame.width/3 + characterBtn.buttonStyle() + modifyBtn.buttonStyle() + + + } + + + + +} + + diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Modules/MyPage/SetMainCharacterViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/Modules/MyPage/SetMainCharacterViewController.swift new file mode 100644 index 0000000..761191b --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Modules/MyPage/SetMainCharacterViewController.swift @@ -0,0 +1,44 @@ +// +// SetMainCharacterViewController.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/11/11. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxCocoa +import RxSwift + +final class SetMainCharacterViewController: UIViewController { + private let disposeBag = DisposeBag() + + @IBOutlet weak var cancelBtn: UIBarButtonItem! + @IBOutlet weak var characterNameLbl: UILabel! + @IBOutlet weak var characterImageView: UIImageView! + @IBOutlet weak var levelLbl: UILabel! + @IBOutlet weak var setProfileBtn: UIButton! + + override func viewDidLoad() { + super.viewDidLoad() + bindAction() + // Do any additional setup after loading the view. + } +} + +extension SetMainCharacterViewController { + private func bindAction() { + cancelBtn.rx.tap + .subscribe { _ in + self.dismiss(animated: true, completion: nil) + }.disposed(by: disposeBag) + + setProfileBtn.rx.tap.map { self.characterImageView.image } + .subscribe(onNext: { (img) in + UserDefaults.standard.setValue(img, forKey: "image") + self.presentingViewController?.presentingViewController? + .dismiss(animated: true, completion: nil) + }).disposed(by: disposeBag) + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Modules/Ranking/RankingViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/Modules/Ranking/RankingViewController.swift new file mode 100644 index 0000000..ade309b --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Modules/Ranking/RankingViewController.swift @@ -0,0 +1,119 @@ +// +// RankingVC.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/10/08. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxSwift +import RxCocoa + +final class RankingViewController: UIViewController { + + @IBOutlet weak var rankingBtn: UIButton! + @IBOutlet weak var stackBtn: UIButton! + @IBOutlet weak var messageLbl: UILabel! + @IBOutlet weak var myRankingLbl: UILabel! + @IBOutlet weak var myRankingView: UIView! + @IBOutlet weak var myRanknumLbl: UILabel! + @IBOutlet weak var myNameLbl: UILabel! + @IBOutlet weak var tableView: UITableView! + + private let disposeBag = DisposeBag() + private let viewModel = RankingViewModel() + private let loadData = BehaviorRelay(value: ()) + + + + override func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + + registerCell() + navigationImage() + navigationClear() + rank() + myRank() + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + self.navigationItem.hidesBackButton = true + } + + func myRank() { + let rank: Observable = DarnerAPIClient.shared.networkingResult(from: .myrank("smKim")) + rank.asObservable().subscribe(onNext: { model in + self.myRanknumLbl.text = String(model.rank ?? 3) + }).disposed(by: disposeBag) + } + + func myRank() { + let rank: Observable = DarnerAPIClient.shared.networkingResult(from: .myrank("smKim")) + rank.asObservable().subscribe(onNext: { model in + self.myRanknumLbl.text = String(model.rank ?? 2) + }).disposed(by: disposeBag) + } + + func rank() { + + let rank: Observable = DarnerAPIClient.shared.networkingResult(from: .rank(3)) + rank.map { $0.ranking }.bind(to: tableView.rx.items(cellIdentifier: "rankingCell", cellType: RankingCell.self)) { idx, model, cell in + cell.nickNameLbl?.text = model.name + cell.RankingLbl?.text = String(model.rank) + }.disposed(by: disposeBag) + } + + struct a: Codable { + let rank: Int? + let message: String? + } + + private func registerCell() { + tableView.rowHeight = 80 + } +} +struct a: Codable { + let rank: Int? + let message: String? +} + + +extension UIViewController { + func navigationClear() { + let bar: UINavigationBar! = self.navigationController?.navigationBar + bar.setBackgroundImage(UIImage(), for: UIBarMetrics.default) + bar.shadowImage = UIImage() + bar.backgroundColor = UIColor.clear + } + + + func navigationImage() { + let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 40, height: 35)) + imageView.contentMode = .scaleAspectFit + + let image = UIImage(named: "LogoImage") + imageView.image = image + + navigationItem.titleView = imageView + } + +} + +extension UIViewController { + func navigationImage() { + let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 40, height: 35)) + imageView.contentMode = .scaleAspectFit + + let image = UIImage(named: "LogoImage") + imageView.image = image + + navigationItem.titleView = imageView + } + +} + diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Modules/Register/CheckCertificationNumberViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/Modules/Register/CheckCertificationNumberViewController.swift new file mode 100644 index 0000000..ec7ecc2 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Modules/Register/CheckCertificationNumberViewController.swift @@ -0,0 +1,70 @@ +// +// CheckCertificationNumberVC.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/10/19. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxCocoa +import RxSwift + +final class CheckCertificationNumberViewController: UIViewController { + + let disposeBag = DisposeBag() + let viewModel = CheckCertificationNumberViewModel() + + @IBOutlet weak var previousVCBtn: UIButton! + @IBOutlet weak var nextBtn: UIButton! + @IBOutlet weak var certificationNumberTxtField: UITextField! + + override func viewDidLoad() { + super.viewDidLoad() + bindUI() + bindAction() + } +} + +extension CheckCertificationNumberViewController { + private func bindAction() { + nextBtn.rx.tap + .withLatestFrom(self.certificationNumberTxtField.rx.text) + .map { DarnerAPI.verifywithemail(email: RegisterViewController.email, code: $0!) } + .flatMap {(request: DarnerAPI) -> Observable in + DarnerAPIClient.shared.networkingResult(from: request) + } + .subscribe { response in + if response.message == "true" { + let vc = self.makeVC(identifier: .finishRegisterVC) + DispatchQueue.main.async { + self.navigationController?.pushViewController(vc, animated: true) + } + } else { + self.nextBtn.shake() + } + } onError: { _ in + self.nextBtn.shake() + }.disposed(by: disposeBag) + + + previousVCBtn.rx.tap + .subscribe { _ in + self.navigationController?.popViewController(animated: true) + }.disposed(by: disposeBag) + } + + private func bindUI() { + let input = CheckCertificationNumberViewModel.Input.init(codeSubject: certificationNumberTxtField.rx.text.orEmpty.asObservable()) + + let output = viewModel.transform(input) + + output.result.drive(onNext: { bool in + bool ? self.nextBtn.setTextColor(color: .white) : self.nextBtn.setTextColor(color: .black) + self.nextBtn.isUserInteractionEnabled = bool + self.nextBtn.layer.borderColor = bool ? UIColor.customPink.cgColor : UIColor.black.cgColor + self.nextBtn.backgroundColor = bool ? .customPink : .white + }).disposed(by: disposeBag) + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Modules/Register/FinishRegisterViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/Modules/Register/FinishRegisterViewController.swift new file mode 100644 index 0000000..0ac33a0 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Modules/Register/FinishRegisterViewController.swift @@ -0,0 +1,41 @@ +// +// FinishRegisterViewController.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/10/21. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxCocoa +import RxSwift + +final class FinishRegisterViewController: UIViewController { + private let disposeBag = DisposeBag() + + @IBOutlet weak var popToMainBtn: UIButton! + + override func viewDidLoad() { + super.viewDidLoad() + bindAction() + } +} + +extension FinishRegisterViewController { + private func bindAction() { + self.popToMainBtn.rx.tap + .subscribe { _ in + guard var controllers = self.navigationController?.viewControllers else { return } + let count = controllers.count + if count > 2 { + controllers.removeSubrange(1...count-2) + } + self.navigationController?.viewControllers = controllers + self.navigationController?.popViewController(animated: true) + }.disposed(by: disposeBag) + } +} + + + diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Modules/Register/RegisterViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/Modules/Register/RegisterViewController.swift new file mode 100644 index 0000000..d64ebdd --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Modules/Register/RegisterViewController.swift @@ -0,0 +1,87 @@ +// +// RegisterVC.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/10/14. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxSwift +import RxCocoa + +final class RegisterViewController: UIViewController { + static var email: String! + + let disposeBag = DisposeBag() + let viewModel = RegisterViewModel() + + @IBOutlet weak var sameIdNoticeLbl: UILabel! + @IBOutlet weak var wrongPwLbl: UILabel! + @IBOutlet weak var emailTextField: UITextField! + @IBOutlet weak var nameTextField: UITextField! + @IBOutlet weak var idTextField: UITextField! + @IBOutlet weak var pwTextField: UITextField! + @IBOutlet weak var registerBtn: UIButton! + @IBOutlet weak var popVCBtn: UIButton! + + override func viewDidLoad() { + super.viewDidLoad() + bindUI() + bindAction() + } +} + +extension RegisterViewController { + private func bindUI() { + + let input = RegisterViewModel.Input.init(idTextFieldSubject: nameTextField.rx.text.orEmpty.asObservable(), + pwTextFieldSubject: idTextField.rx.text.orEmpty.asObservable(), + emailTextFieldSubject: pwTextField.rx.text.orEmpty.asObservable(), + nameTextField: emailTextField.rx.text.orEmpty.asObservable()) + + let output = viewModel.transform(input) + + output.signal.drive(onNext: { b in + self.registerBtn.layer.borderColor = b ? UIColor.customPink.cgColor : UIColor.black.cgColor + self.registerBtn.backgroundColor = b ? .customPink : .white + b ? self.registerBtn.setTextColor(color: .white) : self.registerBtn.setTextColor(color: .black) + self.registerBtn.isUserInteractionEnabled = b + }).disposed(by: disposeBag) + } + + private func bindAction() { + popVCBtn.rx.tap + .subscribe { _ in + self.navigationController?.popViewController(animated: true) + }.disposed(by: disposeBag) + + registerBtn.rx.tap + .debounce(.seconds(2), scheduler: MainScheduler.instance) + .withLatestFrom(Observable.combineLatest(self.idTextField.rx.text.orEmpty, + self.emailTextField.rx.text.orEmpty, + self.pwTextField.rx.text.orEmpty, + self.nameTextField.rx.text.orEmpty)) + .map { + RegisterViewController.email = $0.1; + return DarnerAPI.register(userId: $0.0, name: $0.3, email: $0.1, password: $0.2) + } + .flatMap { (request:DarnerAPI) -> Observable in + return DarnerAPIClient.shared.networkingResult(from: request) + } + .subscribe { model in + if model.message == "success" { + let vc: CheckCertificationNumberViewController = self.makeVC(identifier: .checkCertificationVC) + DispatchQueue.main.async { + self.navigationController?.pushViewController(vc, animated: true) + } + } else { + self.registerBtn.shake() + } + } onError: { _ in + self.registerBtn.shake() + } + .disposed(by: disposeBag) + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/Modules/Writing/WritingViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/Modules/Writing/WritingViewController.swift new file mode 100644 index 0000000..e190ed0 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/Modules/Writing/WritingViewController.swift @@ -0,0 +1,86 @@ +// +// WritingVC.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/09/03. +// Copyright © 2020 이현욱. All rights reserved. +// +import UIKit + +import RxSwift +import RxCocoa + +class WritingViewController: UIViewController { + + @IBOutlet weak var saveBtn: UIBarButtonItem! + @IBOutlet weak var titleTxtField: UITextField! + @IBOutlet weak var writingTxtView: UITextView! + + private let disposeBag = DisposeBag() + var dummyData = [String]() + + override func viewDidLoad() { + super.viewDidLoad() + + let memo = UserDefaults.standard.object(forKey: "no") as? Int + + if(memo == -1) { + dummyData = (UserDefaults.standard.object(forKey: "data") as? [String])! + writingTxtView.text = "..."; + + } + + writingTxtView.layer.borderWidth = 2 + writingTxtView.layer.borderColor = UIColor.gray.cgColor + writingTxtView.layer.cornerRadius = 15 + + save(saveBtn) + bindAction() + navigationImage() + + } + + override func didReceiveMemoryWarning() { + super.didReceiveMemoryWarning() + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + self.navigationItem.hidesBackButton = false + } + + func save(_ button: UIBarButtonItem) { + let memo = UserDefaults.standard.object(forKey: "no") as? Int + + if(memo == -1) { + dummyData.insert(writingTxtView.text, at: 0) + UserDefaults.standard.set(dummyData, forKey: "data") + } + // else { +// dummyData.remove(at: memo?) +// dummyData.insert(writingTxtView.text, at: memo?) +// +// UserDefaults.standard.set(dummyData, forKey: "data") +// } + + print("save") + + dismiss(animated: true, completion: nil) + + } + + func bindAction() { + saveBtn.rx.tap + .subscribe(onNext: { _ in + self.backView(identifire: "memo") + }).disposed(by: disposeBag) + } +} + +extension UIViewController { + func backView(identifire: String) { + navigationController!.popViewController(animated: true) + } +} + + diff --git a/Darner-dan-uh/Darner-dan-uh/Source/NetWorking/DarnerAPI.swift b/Darner-dan-uh/Darner-dan-uh/Source/NetWorking/DarnerAPI.swift new file mode 100644 index 0000000..08fe14f --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/NetWorking/DarnerAPI.swift @@ -0,0 +1,162 @@ +// +// DarnerAPI.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/11/02. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import Alamofire +import RxAlamofire + +enum DarnerAPI { + case register(userId: String, name: String, email: String, password: String) + case verifywithemail(email: String, code: String) + case login(userId: String, password: String) + case logout + case rank(_ count: Int) + case myrank(_ id: String) + case stack + case wordGenre(word_id: String, number: String) + case wordTest + case myProfile + case updateProfile(changeId: String) + case verifyPassword(pw: String) + case getLevel + case memoTitle + case memoContents + case deleteMemo + case savedata(id: String, count: Int) +} + +extension DarnerAPI { + var baseURL: String { + return "http://10.156.145.103:9032" + } + + var path: String { + switch self { + case .getLevel: + return "/user/level" + case .savedata: + return "/word/savedata" + case .register: + return "/register" + case .verifywithemail: + return "/verifywithemail" + case .login: + return "/login" + case.logout: + return "/logout" + case .rank(let count): + return "/rank?count=\(count)" + case .myrank(let id): + return "/myrank?id=\(id)" + case .stack: + return "/stack" + case .wordGenre: + return "/word/genre" + case .wordTest: + return "/word/test" + case .myProfile: + return "/user/profile" + case .updateProfile: + return "/user/update" + case .verifyPassword: + return "/user/verifyPassword" + case .memoTitle: + return "/memo/title" + case .memoContents: + return "memo/title/contents" + case .deleteMemo: + return "memo/delete" + } + } + + var method: HTTPMethod? { + switch self { + case .register, + .verifywithemail, + .login, + .verifyPassword, + .wordGenre, + .savedata, + .login: + return .post + + case .logout, + .rank, + .myrank, + .stack, + .wordTest, + .myProfile, + .memoTitle, + .getLevel, + .memoContents: + return .get + + case .deleteMemo: + return .delete + + case .updateProfile: + return .patch + + default: + return nil + } + } + + var header: HTTPHeaders? { + switch self { + case .verifywithemail(_, let code): + return ["code" : code] + case .verifyPassword: + return ["Authorization": "Bearer " + "eyJhbGciOiJIUzUxMiJ9.eyJqdGkiOiJzbWtpbSIsImlhdCI6MTYwNzI2MjAzMSwiZXhwIjoxNjA3MjgwMDMxfQ.mlzlDztiWAWUwDXW_7DUN3SA1FRU9khqOcTqfh4lhP5xJV9PxNeLsuU7bdBYjQOQbsAiETzR020Z-44lp8JjIw", + "content-type": "application/json"] + default: + return ["Content-Type":"application/json"] + } + } + + var encoding: ParameterEncoding { + switch self { + case .logout, + .rank, + .stack, + .wordTest, + .myProfile, + .memoTitle, + .memoContents: + return URLEncoding.queryString + default: + return JSONEncoding.default + } + } + + var parameter: Parameters? { + switch self { + case .updateProfile(let changeId): + return ["name": changeId] + + case .verifywithemail(let email,let code): + return ["email" : email, "code": code] + + case .register(let userId, let name, let email, let password): + return ["userId" : userId, "name" : name, "email" : email, "password": password] + + case .login(let userId, let password): + return ["userId": userId, "password": password] + + case .wordGenre(let word_id, let number): + return ["word_id": word_id, "number": number] + + case .verifyPassword(let pw): + return ["password": pw] + + default: + return nil + } + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/NetWorking/DarnerAPIClient.swift b/Darner-dan-uh/Darner-dan-uh/Source/NetWorking/DarnerAPIClient.swift new file mode 100644 index 0000000..1e02253 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/NetWorking/DarnerAPIClient.swift @@ -0,0 +1,43 @@ +// +// DarnerAPIClient.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/11/12. +// Copyright © 2020 이현욱. All rights reserved. +// + +import Foundation + +import RxSwift +import Alamofire +import RxAlamofire + +class DarnerAPIClient { + static let shared = DarnerAPIClient() + + func networkingResult(from api: DarnerAPI) -> Observable { + return Observable.create { obs in + let request = AF.request(URL(string: api.baseURL + api.path)!, + method: api.method!, + parameters: api.parameter, + encoding: JSONEncoding.default, + headers: api.header).responseData { response in + debugPrint(response) + switch response.result { + case .success(let data): + do { + let dataToUse: T = try JSONDecoder().decode(T.self, from: data) + return obs.onNext(dataToUse) + } catch(let error) { + return obs.onError(error) + } + case .failure(let error): + return obs.onError(error) + } + } + return Disposables.create { + request.cancel() + } + } + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/CheckCertificationNumberViewModel.swift b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/CheckCertificationNumberViewModel.swift new file mode 100644 index 0000000..433adde --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/CheckCertificationNumberViewModel.swift @@ -0,0 +1,29 @@ +// +// CheckCertificationNumberViewModel.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/11/23. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxCocoa +import RxSwift + +class CheckCertificationNumberViewModel: ViewModelType { + struct Input { + let codeSubject: Observable + } + + struct Output { + let result: Driver + } + + func transform(_ input: Input) -> Output { + let bool = input.codeSubject + .map { !$0.isEmpty } + .asDriver(onErrorJustReturn: false) + return Output(result: bool) + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/LoginViewModel.swift b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/LoginViewModel.swift new file mode 100644 index 0000000..eeebf1e --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/LoginViewModel.swift @@ -0,0 +1,31 @@ +// +// LoginViewModel.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/10/14. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxSwift +import RxCocoa + +class LoginViewModel: ViewModelType { + let disposeBag = DisposeBag() + + struct Input { + let idTextFieldSubject: Observable + let pwTextFieldSubject: Observable + } + + struct Output { + let result: Driver + } + + func transform(_ input: Input) -> Output { + let bool = Observable.combineLatest(input.idTextFieldSubject, input.pwTextFieldSubject).map { !$0.isEmpty && !$1.isEmpty }.asDriver(onErrorJustReturn: false) + return Output(result: bool) + } +} + diff --git a/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Login/LoginViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Login/LoginViewController.swift new file mode 100644 index 0000000..919d973 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Login/LoginViewController.swift @@ -0,0 +1,73 @@ +// +// LoginVC.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/10/14. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxSwift +import RxCocoa + +final class LoginViewController: UIViewController { + + var autoLoginFlag: Bool! = false + let viewModel = LoginViewModel() + let disposeBag = DisposeBag() + + @IBOutlet weak var idTextField: UITextField! + @IBOutlet weak var pwTextField: UITextField! + @IBOutlet weak var autoLoginLblBtn: UIButton! + @IBOutlet weak var autoLoginBtn: UIButton! + @IBOutlet weak var loginBtn: UIButton! + @IBOutlet weak var popVCBtn: UIButton! + + override func viewDidLoad() { + super.viewDidLoad() + bindAction() + bindUI() + } +} + +extension LoginViewController { + private func bindAction() { + popVCBtn.rx.tap + .subscribe { _ in + self.navigationController?.popViewController(animated: true) + }.disposed(by: disposeBag) + + loginBtn.rx.tap + .map { /* 서버 통신 */ } + .map { /* 자동 로그인에 대한 처리 */} + .subscribe { _ in + let vc = self.makeVC(identifier: ViewControllerName.tabbarVC) + vc.modalPresentationStyle = .fullScreen + self.present(vc, animated: true, completion: nil) + }.disposed(by: disposeBag) + + Observable.merge(autoLoginBtn.rx.tap.map {}, autoLoginLblBtn.rx.tap.map {}) + .map { self.autoLoginBtn.isSelected.toggle() } + .map { if self.autoLoginBtn.isSelected == true { + self.autoLoginBtn.setImage(UIImage(named: "Icon ionic-ios-checkmark-circle"), for: .selected) + } else { + self.autoLoginBtn.setImage(UIImage(named: "Icon material-radio-button-unchecked"), for: .normal) + }} + .subscribe { _ in + // keychain에 유저 정보 저장 + }.disposed(by: disposeBag) + } + + private func bindUI() { + idTextField.rx.text.map { $0 ?? "" }.bind(to: viewModel.idTextFieldSubject).disposed(by: disposeBag) + pwTextField.rx.text.map { $0 ?? "" }.bind(to: viewModel.pwTextFieldSubject).disposed(by: disposeBag) + viewModel.isValid().subscribe(onNext :{ value in + self.loginBtn.layer.borderColor = value ? UIColor.customPink.cgColor : UIColor.black.cgColor + self.loginBtn.backgroundColor = value ? .customPink : .white + value ? self.loginBtn.setTextColor(color: .white) : self.loginBtn.setTextColor(color: .black) + self.loginBtn.isUserInteractionEnabled = value + }).disposed(by: disposeBag) + } +} + diff --git a/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Memorization/Cell/WordCell.swift b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Memorization/Cell/WordCell.swift new file mode 100644 index 0000000..4884f3b --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Memorization/Cell/WordCell.swift @@ -0,0 +1,34 @@ +// +// WordCell.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/11/01. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +class WordCell: UITableViewCell { + + static let cellName = "WordCell" + + @IBOutlet weak var wordKoreanMeanLbl: UILabel! + @IBOutlet weak var wordEnglishMeanLbl: UILabel! + + override func awakeFromNib() { + super.awakeFromNib() + // Initialization code + } + + override func setSelected(_ selected: Bool, animated: Bool) { + super.setSelected(selected, animated: animated) + + // Configure the view for the selected state + } + +} + +struct DecodeWordCell { + var englishMean: String + var koreanMean: String +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Memorization/Cell/WordResultCell.swift b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Memorization/Cell/WordResultCell.swift new file mode 100644 index 0000000..633e55a --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Memorization/Cell/WordResultCell.swift @@ -0,0 +1,28 @@ +// +// WordResultCell.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/11/03. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +class WordResultCell: UITableViewCell { + static let cellName = "WordResultCell" + + @IBOutlet weak var wordMeanLbl: UILabel! + @IBOutlet weak var isCorrectLbl: UILabel! + + override func awakeFromNib() { + super.awakeFromNib() + // Initialization code + } + + override func setSelected(_ selected: Bool, animated: Bool) { + super.setSelected(selected, animated: animated) + + // Configure the view for the selected state + } + +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Memorization/MemorizationViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Memorization/MemorizationViewController.swift new file mode 100644 index 0000000..65c6539 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Memorization/MemorizationViewController.swift @@ -0,0 +1,205 @@ +// +// MemorizationVC.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/10/08. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxSwift +import RxCocoa + +final class MemorizationViewController: UIViewController { + static var wordType: wordTypeEnum! + private let disposeBag = DisposeBag() + + @IBOutlet weak var memorizeTapItem: UINavigationItem! + @IBOutlet weak var myPageBtn: UIButton! + @IBOutlet weak var lawBtn: UIButton! + @IBOutlet weak var traditionBtn: UIButton! + @IBOutlet weak var artBtn: UIButton! + @IBOutlet weak var harborBtn: UIButton! + @IBOutlet weak var agricultureBtn: UIButton! + @IBOutlet weak var militaryBtn: UIButton! + @IBOutlet weak var electricalEnergyBtn: UIButton! + @IBOutlet weak var coalBtn: UIButton! + + override func viewDidLoad() { + super.viewDidLoad() + bindAction() + bindUI() + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + self.tabBarController?.tabBar.isHidden = false + } +} + +extension MemorizationViewController { + private func bindUI() { +// memorizeTapItem.≥÷÷≥¿÷title. + } + + private func bindAction() { + Observable.merge(lawBtn.rx.tap.map { MemorizationViewController.wordType = wordTypeEnum(rawValue: wordTypeEnum.law.rawValue) }, + traditionBtn.rx.tap.map { MemorizationViewController.wordType = wordTypeEnum(rawValue: wordTypeEnum.tradition.rawValue)}, + artBtn.rx.tap.map { MemorizationViewController.wordType = wordTypeEnum(rawValue: wordTypeEnum.art.rawValue)}, + harborBtn.rx.tap.map { MemorizationViewController.wordType = wordTypeEnum(rawValue: wordTypeEnum.harbor.rawValue)}, + agricultureBtn.rx.tap.map { MemorizationViewController.wordType = wordTypeEnum(rawValue: wordTypeEnum.agriculture.rawValue)}, + militaryBtn.rx.tap.map { MemorizationViewController.wordType = wordTypeEnum(rawValue: wordTypeEnum.military.rawValue)}, + electricalEnergyBtn.rx.tap.map { MemorizationViewController.wordType = wordTypeEnum(rawValue: wordTypeEnum.electricalEnergy.rawValue)}, + coalBtn.rx.tap.map { MemorizationViewController.wordType = wordTypeEnum(rawValue: wordTypeEnum.coal.rawValue)} + ).subscribe { _ in + let vc = self.makeVC(identifier: ViewControllerName.selectwordNumVC) + self.navigationController?.pushViewController(vc, animated: true) + }.disposed(by: disposeBag) + + + myPageBtn.rx.tap + .subscribe({ _ in + let vc = self.makeVC(identifier: ViewControllerName.myCharacterVC) + self.present(vc, animated: true, completion: nil) + }) + .disposed(by: disposeBag) + } +} + +enum wordTypeEnum: String, CaseIterable { + case law = "법률" + case tradition = "전통" + case art = "예술" + case harbor = "항구" + case agriculture = "농업" + case military = "군사" + case electricalEnergy = "전력" + case coal = "석탄" + + static var asArray: [wordTypeEnum] {return self.allCases} + + func asInt() -> Int { + return wordTypeEnum.asArray.firstIndex(of: self)! + } +} + +/* + // + // MemorizationVC.swift + // Darner-dan-uh + // + // Created by 이현욱 on 2020/10/08. + // Copyright © 2020 이현욱. All rights reserved. + // + + import UIKit + + import RxSwift + import RxCocoa + + final class MemorizationViewController: UIViewController { + static var wordType: wordTypeEnum! + private let disposeBag = DisposeBag() + + @IBOutlet weak var memorizeTapItem: UINavigationItem! + @IBOutlet weak var myPageBtn: UIButton! + @IBOutlet weak var lawBtn: UIButton! + @IBOutlet weak var traditionBtn: UIButton! + @IBOutlet weak var artBtn: UIButton! + @IBOutlet weak var harborBtn: UIButton! + @IBOutlet weak var agricultureBtn: UIButton! + @IBOutlet weak var militaryBtn: UIButton! + @IBOutlet weak var electricalEnergyBtn: UIButton! + @IBOutlet weak var coalBtn: UIButton! + + override func viewDidLoad() { + super.viewDidLoad() + bindAction() + bindUI() + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + self.tabBarController?.tabBar.isHidden = false + } + } + + extension MemorizationViewController { + private func bindUI() { + // memorizeTapItem.≥÷÷≥¿÷title. + } + + private func bindAction() { + Observable.merge(lawBtn.rx.tap.map { MemorizationViewController.wordType = wordTypeEnum.law.rawValue }, + traditionBtn.rx.tap.map { MemorizationViewController.wordType = wordTypeEnum.tradition.rawValue}, + artBtn.rx.tap.map { MemorizationViewController.wordType = wordTypeEnum.art.rawValue}, + harborBtn.rx.tap.map { MemorizationViewController.wordType = wordTypeEnum.harbor.rawValue}, + agricultureBtn.rx.tap.map { MemorizationViewController.wordType = wordTypeEnum.agriculture.rawValue}, + militaryBtn.rx.tap.map { MemorizationViewController.wordType = wordTypeEnum.military.rawValue}, + electricalEnergyBtn.rx.tap.map { MemorizationViewController.wordType = wordTypeEnum.electricalEnergy.rawValue}, + coalBtn.rx.tap.map { MemorizationViewController.wordType = wordTypeEnum.coal.rawValue} + ).subscribe { _ in + let vc = self.makeVC(identifier: ViewControllerName.selectwordNumVC) + self.navigationController?.pushViewController(vc, animated: true) + }.disposed(by: disposeBag) + + + myPageBtn.rx.tap + .subscribe({ _ in + let vc = self.makeVC(identifier: ViewControllerName.myCharacterVC) + self.present(vc, animated: true, completion: nil) + }) + .disposed(by: disposeBag) + } + } + + enum wordTypeEnum: Int, CaseIterable { + case law = 1 + case tradition + case art + case harbor + case agriculture + case military + case electricalEnergy + case coal + + static var asArray: [wordTypeEnum] { return wordTypeEnum.allCases } + + func asInt() -> Int { + return wordTypeEnum.asArray.firstIndex(of: self)! + } + + var description: String { + switch self { + case .law: + return "법률" + case .tradition: + return "전통" + case .art: + return "예술" + case .harbor: + return "항구" + case .agriculture: + return "농업" + case .military: + return "군사" + case .electricalEnergy: + return "전력" + case.coal: + return "석탄" + } + } + } + + enum Directions: String, CaseIterable { + case north, south, east, west + + static var asArray: [Directions] {return self.allCases} + + func asInt() -> Int { + return Directions.asArray.firstIndex(of: self)! + } + } + + */ diff --git a/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Memorization/SelectWordNumViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Memorization/SelectWordNumViewController.swift new file mode 100644 index 0000000..94efc68 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Memorization/SelectWordNumViewController.swift @@ -0,0 +1,82 @@ +// +// SelectWordNumVC.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/10/28. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxCocoa +import RxSwift + +final class SelectWordNumViewController: UIViewController { + + lazy var number: Int! = wordNum + var wordNum = 10 + let disposeBag = DisposeBag() + + @IBOutlet weak var backVCBtn: UIButton! + @IBOutlet weak var minusWordNumBtn: UIButton! + @IBOutlet weak var plusWordNumBtn: UIButton! + @IBOutlet weak var nextVCBtn: UIButton! + @IBOutlet weak var wordNumLbl: UILabel! + + override func viewDidLoad() { + super.viewDidLoad() + bindAction() + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + self.tabBarController?.tabBar.isHidden = true + } +} + +extension SelectWordNumViewController { + private func bindAction() { + minusWordNumBtn.rx.tap + .map { self.editWordCount(self.minusWordNumBtn, self.wordNum)} + .bind(onNext: { num in + self.wordNumLbl.text = String(num) + }).disposed(by: disposeBag) + + plusWordNumBtn.rx.tap + .map { self.editWordCount(self.plusWordNumBtn, self.wordNum)} + .bind(onNext: { num in + self.wordNumLbl.text = String(num) + }).disposed(by: disposeBag) + + backVCBtn.rx.tap + .bind(onNext: { + self.navigationController?.popViewController(animated: true) + }).disposed(by: disposeBag) + + nextVCBtn.rx.tap + .map { [weak self] in + self?.number = self?.wordNum + } + .bind(onNext: { + let vc: TestTableViewController = self.makeVC(identifier: ViewControllerName.testTableVC) + vc.wordnum = self.number + self.navigationController?.pushViewController(vc, animated: true) + }).disposed(by: disposeBag) + } + + private func editWordCount(_ sender: UIButton,_ num: Int) -> Int { + if num <= 0 || num >= 100 { return num } + switch sender.tag { + case 0: + wordNum = num - 1 + return wordNum + + case 1: + wordNum = num + 1 + return num + 1 + + default: + return 0 + } + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Memorization/TestResultViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Memorization/TestResultViewController.swift new file mode 100644 index 0000000..2cae151 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Memorization/TestResultViewController.swift @@ -0,0 +1,36 @@ +// +// TestResultViewController.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/11/01. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxSwift +import RxCocoa + +final class TestResultViewController: UIViewController { + + @IBOutlet weak var tableView: UITableView! + @IBOutlet weak var finishWordTestBtn: UIButton! + + override func viewDidLoad() { + super.viewDidLoad() + bindAction() + + // Do any additional setup after loading the view. + } +} + +extension TestResultViewController { + private func bindAction() { + finishWordTestBtn.rx.tap + .map { var controller = self.navigationController?.viewControllers + controller?.removeAll() + self.navigationController?.viewControllers = controller! + self.navigationController?.popViewController(animated: true) + }.subscribe().dispose() + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Memorization/TestTableViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Memorization/TestTableViewController.swift new file mode 100644 index 0000000..d064841 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Memorization/TestTableViewController.swift @@ -0,0 +1,65 @@ +// +// TestTableViewController.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/11/01. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxSwift +import RxCocoa + +final class TestTableViewController: UIViewController { + private let disposeBag = DisposeBag() + var wordnum: Int! + + @IBOutlet weak var wordTypeLbl: UILabel! + @IBOutlet weak var testBtn: UIButton! + @IBOutlet weak var popVCBtn: UIButton! + @IBOutlet weak var tableView: UITableView! + + override func viewDidLoad() { + super.viewDidLoad() + bindAction() + bindUI() + // Do any additional setup after loading the view. + } + +} + +extension TestTableViewController { + private func bindAction() { + testBtn.rx.tap.map { + self.presentAlert(message: "단어 시험을 볼 준비가 됐나요?", style: .alert, title: "더 공부할게요", actionStyle: .destructive, handler: nil, secTitle: "준비됐습니다", secActionStyle: .default) { _ in + let vc: TestViewController = self.makeVC(identifier: ViewControllerName.testVC) + self.navigationController?.pushViewController(vc, animated: true) + } + }.subscribe() + .disposed(by: disposeBag) + + popVCBtn.rx.tap + .map { + self.navigationController?.popViewController(animated: true) + } + .subscribe() + .disposed(by: disposeBag) + } + + private func bindUI() { + self.wordTypeLbl.text = MemorizationViewController.wordType.rawValue + self.testBtn.layer.borderColor = UIColor.customPink.cgColor + self.tabBarController?.tabBar.isHidden = false + + let words: Observable = DarnerAPIClient.shared.networkingResult(from: .wordGenre(word_id: "\(MemorizationViewController.wordType.asInt())", number: "\(String(describing: wordnum))")) + words.map { [$0] } + .bind(to: tableView.rx.items(cellIdentifier: WordCell.cellName, cellType: WordCell.self)) { _, result, cell in + cell.wordEnglishMeanLbl.text = result.a + }.disposed(by: disposeBag) + } +} + +struct a: Codable { + var a: String +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Memorization/TestViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Memorization/TestViewController.swift new file mode 100644 index 0000000..cfc1b25 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Memorization/TestViewController.swift @@ -0,0 +1,51 @@ +// +// TestViewController.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/11/01. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxSwift +import RxCocoa + +final class TestViewController: UIViewController { + + // realm에서 받아온 단어 배열 변수 생성 + private let disposeBag = DisposeBag() + + @IBOutlet weak var englishWordMeanLbl: UILabel! + @IBOutlet weak var nextWordBtn: UIButton! + @IBOutlet weak var popVCBtn: UIButton! + + override func viewDidLoad() { + super.viewDidLoad() + bindUI() + bindAction() + // Do any additional setup after loading the view. + } + +} + +extension TestViewController { + private func bindAction() { + popVCBtn.rx.tap + .map { + self.presentAlert(message: "시험을 포기하시겠어요?", style: .alert, title: "포기하겠습니다", actionStyle: .destructive, handler: { _ in + self.navigationController?.popViewController(animated: true) + }, secTitle: "계속 할게요", secActionStyle: .default, secHandler: nil) + }.subscribe().disposed(by: disposeBag) + + nextWordBtn.rx.tap + .map { /* label 바꿔야함*/ } + } + + private func bindUI() { + // 단어 배열 변수가 마지막이면 alert 방출 + + + englishWordMeanLbl.text = "a" // realm에서 받아온 거 넣어주기 + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/MyPage/Cell/CharacterCollectionViewCell.swift b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/MyPage/Cell/CharacterCollectionViewCell.swift new file mode 100644 index 0000000..488f0e7 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/MyPage/Cell/CharacterCollectionViewCell.swift @@ -0,0 +1,21 @@ +// +// CharacterCollectionViewCell.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/12/10. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +class CharacterCollectionViewCell: UICollectionViewCell { + static let cellName = "CharacterCollectionViewCell" + + override func awakeFromNib() { + super.awakeFromNib() + // Initialization code + } + + @IBOutlet weak var lbl: UILabel! + @IBOutlet weak var imageView: UIImageView! +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/MyPage/CharacterCollectionViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/MyPage/CharacterCollectionViewController.swift new file mode 100644 index 0000000..2b7ec5d --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/MyPage/CharacterCollectionViewController.swift @@ -0,0 +1,55 @@ +// +// CharacterCollectionViewController.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/11/05. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit +import RxSwift +import RxCocoa + +final class CharacterCollectionViewController: UIViewController { + private let disposeBag = DisposeBag() + + @IBOutlet weak var firstCharacterBtn: UIButton! + @IBOutlet weak var cancelBtn: UIBarButtonItem! + @IBOutlet weak var secCharacterBtn: UIButton! + @IBOutlet weak var thirdCharacterBtn: UIButton! + @IBOutlet weak var fourthCharacterBtn: UIButton! + @IBOutlet weak var fifthCharacterBtn: UIButton! + @IBOutlet weak var sixCharacterBtn: UIButton! + + override func viewDidLoad() { + super.viewDidLoad() + bindAction() + // Do any additional setup after loading the view. + } +} + +extension CharacterCollectionViewController { + private func bindUI() { + + + } + + private func bindAction() { + Observable.merge(firstCharacterBtn.rx.tap.map {}, + secCharacterBtn.rx.tap.map {}, + thirdCharacterBtn.rx.tap.map {}, + fourthCharacterBtn.rx.tap.map {}, + fifthCharacterBtn.rx.tap.map {}, + sixCharacterBtn.rx.tap.map {} + ) + .subscribe({ _ in + let vc = self.makeVC(identifier: ViewControllerName.setMainCharacterVC) + self.present(vc, animated: true, completion: nil) + }).disposed(by: disposeBag) + + cancelBtn.rx.tap + .subscribe { _ in + self.dismiss(animated: true, completion: nil) + }.disposed(by: disposeBag) + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/MyPage/EnterPwViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/MyPage/EnterPwViewController.swift new file mode 100644 index 0000000..517717f --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/MyPage/EnterPwViewController.swift @@ -0,0 +1,43 @@ +// +// EnterPwViewController.swift +// Darner-dan-uh +// +// Created by 문지수 on 2020/11/05. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxSwift +import RxCocoa + +class EnterPwViewController: UIViewController { + + @IBOutlet weak var titleLbl: UILabel! + @IBOutlet weak var subLbl: UILabel! + @IBOutlet weak var passwordLbl: UILabel! + @IBOutlet weak var passwordTxtField: UITextField! + @IBOutlet weak var nextBtn: UIButton! + + private let disposeBag = DisposeBag() + // private let viewModel = MypageViewModel() + + override func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + + nextBtn.buttonStyle() + + passwordTxtField.isSecureTextEntry = true + + passwordTxtField.underLine() + + let alret = UIAlertController(title: "비밀번호 확인이 되었습니다!", message: "", preferredStyle: UIAlertController.Style.alert) + alret.addAction(UIAlertAction(title: "다음", style: .default, handler: nil)) + present(alret, animated: true, completion: nil) + + } +} + + diff --git a/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/MyPage/ModifyViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/MyPage/ModifyViewController.swift new file mode 100644 index 0000000..0094692 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/MyPage/ModifyViewController.swift @@ -0,0 +1,93 @@ +// +// ModifyViewController.swift +// Darner-dan-uh +// +// Created by 문지수 on 2020/11/05. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxSwift +import RxCocoa + +class ModifyViewController: UIViewController { + + @IBOutlet weak var profileImage: UIImageView! + @IBOutlet weak var nickNameLbl: UILabel! + @IBOutlet weak var nickNameTxtField: UITextField! + @IBOutlet weak var passwordLbl: UILabel! + @IBOutlet weak var passwordTxtFiled: UITextField! + @IBOutlet weak var modifyBtn: UIButton! + + private let disposeBag = DisposeBag() + private let viewModel = MypageViewModel() + + override func viewDidLoad() { + super.viewDidLoad() + + self.navigationItem.title = "마이페이지" + + nickNameTxtField.clearButtonMode = .whileEditing + passwordTxtFiled.clearButtonMode = .whileEditing + + // Do any additional setup after loading the view. + profileImage.layer.cornerRadius = profileImage.frame.width/2 + modifyBtn.buttonStyle() + nickNameTxtField.underLine() + passwordTxtFiled.underLine() + + passwordTxtFiled.isSecureTextEntry = true + + } + + func bindViewModel() { + let input = MypageViewModel.Input(userName: nickNameTxtField.rx.text.orEmpty.asDriver(), userPw: passwordTxtFiled.rx.text.orEmpty.asDriver()) + let output = viewModel.transform(input) + + } + + func bindAction() { + modifyBtn.rx.tap + .map{ let controller = + self.navigationController?.viewControllers + self.navigationController?.viewControllers = controller! + self.navigationController?.popViewController(animated: true) + } + } + + @IBAction func nextView(_ sender: UIButton) { + guard let nextVC = self.storyboard?.instantiateViewController(identifier: "enterPw") else { return } + self.present(nextVC, animated: true) + self.dismiss(animated: true) + } +} + +extension UITextField { + func underLine() { + let border = CALayer() + let width = CGFloat(1.0) + border.borderColor = UIColor.customGray.cgColor + border.frame = CGRect(x: 0, y: self.frame.size.height - width, width: self.frame.size.width, height: self.frame.size.height) + border.borderWidth = width + self.layer.addSublayer(border) + self.layer.masksToBounds = true + } +} + +extension UIButton { + func buttonStyle() { + self.layer.borderWidth = 2 + self.layer.borderColor = UIColor.customPink.cgColor + self.layer.cornerRadius = 15 + } +} + + + + + + + + + diff --git a/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/MyPage/MyCharacterViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/MyPage/MyCharacterViewController.swift new file mode 100644 index 0000000..6c3c8cc --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/MyPage/MyCharacterViewController.swift @@ -0,0 +1,78 @@ +// +// MyCharacterViewController.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/11/05. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxCocoa +import RxSwift + +class MyCharacterViewController: UIViewController { + let stringObs: Observable! = nil // 서버 통신 후 받아온 문자 + let level: Int = 3 // 사용자 캐릭터의 레벨 + private let disposeBag = DisposeBag() + + @IBOutlet weak var userIdLbl: UILabel! + @IBOutlet weak var imageView: UIImageView! + @IBOutlet weak var userLevelLbl: UILabel! + @IBOutlet weak var nextEvolutionLbl: UILabel! + @IBOutlet weak var showCharacterVCBtn: UIButton! + @IBOutlet weak var cancelBtn: UIBarButtonItem! + + override func viewDidLoad() { + super.viewDidLoad() + bindUI() + bindAction() + } +} + +extension MyCharacterViewController { + private func bindUI() { +// stringObs +// .bind(to: self.userIdLbl.rx.text) +// .disposed(by: disposeBag) +// +// stringObs +// .bind(to: self.userLevelLbl.rx.text) +// .disposed(by: disposeBag) +// + let a : Int? + switch level { + + case 0...2: + a = 3 + case 3...9: + a = 10 + case 10...29: + a = 30 + default: + a = nil + } + + nextEvolutionLbl.text = String(a!) + } + + private func bindAction() { + cancelBtn.rx.tap + .subscribe({_ in + self.dismiss(animated: true, completion: nil) + }).disposed(by: disposeBag) + + showCharacterVCBtn.rx.tap + .bind(to: { _ in + let vc = makeVC(identifier: ViewControllerName.characterCollectionVC) + self.present(vc, animated: true, completion: nil) + }) + + showCharacterVCBtn.rx.tap + .subscribe(onNext: { _ in + let vc = self.makeVC(identifier: ViewControllerName.characterCollectionVC) + vc.modalPresentationStyle = .popover + self.present(vc, animated: true, completion: nil) + }).disposed(by: disposeBag) + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/MyPage/MypageViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/MyPage/MypageViewController.swift new file mode 100644 index 0000000..b867ae5 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/MyPage/MypageViewController.swift @@ -0,0 +1,69 @@ +// +// MypageViewController.swift +// Darner-dan-uh +// +// Created by 문지수 on 2020/11/05. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxSwift +import RxCocoa + +class MypageViewController: UIViewController { + + @IBOutlet weak var profileImage: UIImageView! + @IBOutlet weak var nickNameLbl: UILabel! + @IBOutlet weak var modifyBtn: UIButton! + @IBOutlet weak var characterBtn: UIButton! + @IBOutlet weak var logOutBtn: UIButton! + + private let disposeBag = DisposeBag() + private let viewModel = MypageViewModel() + + override func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + profileImage.layer.cornerRadius = profileImage.frame.width/2 + characterBtn.buttonStyle() + modifyBtn.buttonStyle() + + bindAction() + + let alret = UIAlertController(title: "로그아웃 하시겠습니까?", message: "", preferredStyle: UIAlertController.Style.alert) + + alret.addAction(UIAlertAction(title: "네", style: .default, handler: nil)) + alret.addAction(UIAlertAction(title: "아니요", style: .cancel, handler: nil)) + + present(alret, animated: true, completion: nil) + + + } + + func bindAction() { + modifyBtn.rx.tap + .map{ let controller = self.navigationController?.viewControllers + self.navigationController?.viewControllers = controller! + self.navigationController?.popViewController(animated: true) + } + } + + @IBAction func nextVC(_ sender: UIButton) { + guard let nextVC = self.storyboard?.instantiateViewController(identifier: "modify") else { return } + self.present(nextVC, animated: true) + self.dismiss(animated: true) + } +} + + + +extension UIColor { + class var customPink: UIColor { + return UIColor(red: 253.0 / 255.0, green: 125.0 / 255.0, blue: 128.0 / 255.0, alpha: 1.0) + } + class var customGray: UIColor { + return UIColor(red: 112.0 / 255/0, green: 112.0 / 255.0, blue: 112.0 / 255.0, alpha: 1.0) + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/MyPage/SetMainCharacterViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/MyPage/SetMainCharacterViewController.swift new file mode 100644 index 0000000..caa6a87 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/MyPage/SetMainCharacterViewController.swift @@ -0,0 +1,45 @@ +// +// SetMainCharacterViewController.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/11/11. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxCocoa +import RxSwift + +final class SetMainCharacterViewController: UIViewController { + private let disposeBag = DisposeBag() + + @IBOutlet weak var cancelBtn: UIBarButtonItem! + @IBOutlet weak var characterNameLbl: UILabel! + @IBOutlet weak var characterImageView: UIImageView! + @IBOutlet weak var levelLbl: UILabel! + @IBOutlet weak var setProfileBtn: UIButton! + + override func viewDidLoad() { + super.viewDidLoad() + bindAction() + // Do any additional setup after loading the view. + } +} + +extension SetMainCharacterViewController { + private func bindAction() { + cancelBtn.rx.tap + .subscribe { _ in + self.dismiss(animated: true, completion: nil) + }.disposed(by: disposeBag) + + setProfileBtn.rx.tap.map { self.characterImageView.image } + .subscribe { (img) in + + self.presentingViewController?.presentingViewController? + .dismiss(animated: true, completion: nil) + + }.disposed(by: disposeBag) + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Ranking/Cell/RankingCell.swift b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Ranking/Cell/RankingCell.swift new file mode 100644 index 0000000..7698852 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Ranking/Cell/RankingCell.swift @@ -0,0 +1,42 @@ +// +// RankingCell.swift +// Darner-dan-uh +// +// Created by 문지수 on 2020/11/19. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +class RankingCell: UITableViewCell { + + @IBOutlet weak var RankingLbl: UILabel! + @IBOutlet weak var nickNameLbl: UILabel! + @IBOutlet weak var starImage: UIImageView! + +// var RankingData: RankingModel! { +// didSet { setUpView() } +// } +// +// private func setUpView() { +// self.RankingLbl?.text = "\(RankingData.ranking)" +// self.profileImage?.image = UIImage(named: RankingData.nickName) +// self.nickNameLbl?.text = RankingData.nickName +// } + + private func setUpView() { + self.RankingLbl?.text = "\(RankingData.rank)" + self.nickNameLbl?.text = RankingData.name + } + + override func awakeFromNib() { + super.awakeFromNib() + // Initialization code + } + + override func setSelected(_ selected: Bool, animated: Bool) { + super.setSelected(selected, animated: animated) + + // Configure the view for the selected state + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Ranking/RankingViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Ranking/RankingViewController.swift new file mode 100644 index 0000000..e9db216 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Ranking/RankingViewController.swift @@ -0,0 +1,30 @@ +// +// RankingVC.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/10/08. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +final class RankingViewController: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + } + + + /* + // MARK: - Navigation + + // In a storyboard-based application, you will often want to do a little preparation before navigation + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + // Get the new view controller using segue.destination. + // Pass the selected object to the new view controller. + } + */ + +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Ranking/StackViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Ranking/StackViewController.swift new file mode 100644 index 0000000..39b75cf --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Ranking/StackViewController.swift @@ -0,0 +1,62 @@ +// +// StackViewController.swift +// Darner-dan-uh +// +// Created by 문지수 on 2020/12/07. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxSwift +import RxCocoa + +class StackViewController: UIViewController { + + @IBOutlet weak var rankingBtn: UIButton! + @IBOutlet weak var stackBtn: UIButton! + @IBOutlet weak var stackImage: UIImageView! + + let disposeBag = DisposeBag() + + override func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + navigationClear() + navigationImage() + //buttonAction() + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + self.navigationItem.hidesBackButton = true + } + + func buttonAction() { + rankingBtn.rx.tap + .subscribe{ _ in + self.nextVC(identifier: "ranking") + }.disposed(by: disposeBag) + } + + + +} + +extension UIViewController { + func navigationClear(){ + let bar:UINavigationBar! = self.navigationController?.navigationBar + bar.setBackgroundImage(UIImage(), for: UIBarMetrics.default) + bar.shadowImage = UIImage() + bar.backgroundColor = UIColor.clear + } + + func nextVC(identifier: String) { + let viewController = self.storyboard?.instantiateViewController(identifier: identifier) + viewController?.modalPresentationStyle = .fullScreen + present(viewController!, animated: false, completion: nil) + + + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Register/CheckCertificationNumberViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Register/CheckCertificationNumberViewController.swift new file mode 100644 index 0000000..03f01a1 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Register/CheckCertificationNumberViewController.swift @@ -0,0 +1,61 @@ +// +// CheckCertificationNumberVC.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/10/19. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxCocoa +import RxSwift + +final class CheckCertificationNumberViewController: UIViewController { + + let disposeBag = DisposeBag() + + @IBOutlet weak var previousVCBtn: UIButton! + @IBOutlet weak var nextBtn: UIButton! + @IBOutlet weak var certificationNumberTxtField: UITextField! + + override func viewDidLoad() { + super.viewDidLoad() + bindUI() + bindAction() + } +} + +extension CheckCertificationNumberViewController { + private func bindAction() { + nextBtn.rx.tap + .map { // textfiled 값 post + // sussess 면 다음 페이지 + // fail 이면 알람 + } + .subscribe { _ in + let vc = self.makeVC(identifier: ViewControllerName.finishRegisterVC) + self.navigationController?.pushViewController(vc, animated: true) + }.disposed(by: disposeBag) + + previousVCBtn.rx.tap + .subscribe { _ in + self.navigationController?.popViewController(animated: true) + }.disposed(by: disposeBag) + } + + private func bindUI() { + certificationNumberTxtField.rx.text.orEmpty + .map { self.checkEmail(email: $0) } + .subscribe(onNext: { bool in + bool ? self.nextBtn.setTextColor(color: .white) : self.nextBtn.setTextColor(color: .black) + self.nextBtn.isUserInteractionEnabled = bool + self.nextBtn.layer.borderColor = bool ? UIColor.customPink.cgColor : UIColor.black.cgColor + self.nextBtn.backgroundColor = bool ? .customPink : .white + }).disposed(by: disposeBag) + } + + private func checkEmail(email: String) -> Bool { + return !email.isEmpty + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Register/DoubleCheckViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Register/DoubleCheckViewController.swift new file mode 100644 index 0000000..979829b --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Register/DoubleCheckViewController.swift @@ -0,0 +1,52 @@ +// +// DoubleCheckVC.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/10/14. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxSwift +import RxCocoa + +final class DoubleCheckViewController: UIViewController { + + let disposeBag = DisposeBag() + + @IBOutlet weak var emailTxtField: UITextField! + @IBOutlet weak var nextBtn: UIButton! + + override func viewDidLoad() { + super.viewDidLoad() + bindUI() + bindAction() + } +} + +extension DoubleCheckViewController { + private func bindAction() { + nextBtn.rx.tap + .map {/* 이메일 보냄*/ } + .subscribe { _ in + let vc = self.makeVC(identifier: ViewControllerName.checkCertificationVC) + self.navigationController?.pushViewController(vc, animated: true) + }.disposed(by: disposeBag) + } + + private func bindUI() { + emailTxtField.rx.text.orEmpty + .map { self.checkEmail(email: $0) } + .subscribe(onNext: { bool in + bool ? self.nextBtn.setTextColor(color: .white) : self.nextBtn.setTextColor(color: .black) + self.nextBtn.isUserInteractionEnabled = bool + self.nextBtn.layer.borderColor = bool ? UIColor.customPink.cgColor : UIColor.black.cgColor + self.nextBtn.backgroundColor = bool ? .customPink : .white + }).disposed(by: disposeBag) + } + + private func checkEmail(email: String) -> Bool { + return !email.isEmpty + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Register/FinishRegisterViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Register/FinishRegisterViewController.swift new file mode 100644 index 0000000..8089dc2 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Register/FinishRegisterViewController.swift @@ -0,0 +1,54 @@ +// +// FinishRegisterViewController.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/10/21. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxCocoa +import RxSwift + +final class FinishRegisterViewController: UIViewController { + private let disposeBag = DisposeBag() + + @IBOutlet weak var startBtn: UIButton! + @IBOutlet weak var popToMainBtn: UIButton! + + override func viewDidLoad() { + super.viewDidLoad() + bindAction() + } +} + +extension FinishRegisterViewController { + private func bindAction() { + self.startBtn.rx.tap + .subscribe { _ in + guard var controllers = self.navigationController?.viewControllers else { return } + let count = controllers.count + if count > 2 { + controllers.removeSubrange(1...count-2) + } + self.navigationController?.viewControllers = controllers + self.navigationController?.popViewController(animated: true) + }.disposed(by: disposeBag) + + func bindAction() { + self.popToMainBtn.rx.tap + .subscribe { _ in + guard var controllers = self.navigationController?.viewControllers else { return } + let count = controllers.count + if count > 2 { + controllers.removeSubrange(1...count-2) + } + self.navigationController?.viewControllers = controllers + self.navigationController?.popViewController(animated: true) + }.disposed(by: disposeBag) + } + } +} + + diff --git a/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Register/RegisterViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Register/RegisterViewController.swift new file mode 100644 index 0000000..88033dd --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Register/RegisterViewController.swift @@ -0,0 +1,97 @@ +// +// RegisterVC.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/10/14. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxSwift +import RxCocoa + +final class RegisterViewController: UIViewController { + + let disposeBag = DisposeBag() + let viewModel = RegisterViewModel() + + @IBOutlet weak var sameIdNoticeLbl: UILabel! + @IBOutlet weak var wrongPwLbl: UILabel! + @IBOutlet weak var nameTextField: UITextField! + @IBOutlet weak var idTextField: UITextField! + @IBOutlet weak var pwTextField: UITextField! + @IBOutlet weak var registerBtn: UIButton! + @IBOutlet weak var popVCBtn: UIButton! + + + override func viewDidLoad() { + super.viewDidLoad() + bindUI() + bindAction() + } +} + +extension RegisterViewController { + private func bindUI() { + nameTextField.rx.text + .map { $0 ?? "" } + .bind(to: viewModel.nameTextFieldSubject) + .disposed(by: disposeBag) + + idTextField.rx.text + .map { $0 ?? "" } + .bind(to: viewModel.idTextFieldSubject) + .disposed(by: disposeBag) + + pwTextField.rx.text + .map { $0 ?? "" } + .bind(to: viewModel.pwTextFieldSubject) + .disposed(by: disposeBag) + + nameTextField.rx.text.map { $0 ?? "" }.bind(to: viewModel.nameTextFieldSubject).disposed(by: disposeBag) + + idTextField.rx.text.map { $0 ?? "" }.bind(to: viewModel.idTextFieldSubject).disposed(by: disposeBag) + + pwTextField.rx.text.map { $0 ?? "" }.bind(to: viewModel.pwTextFieldSubject).disposed(by: disposeBag) + + viewModel.isValid().subscribe(onNext: { value in + self.registerBtn.layer.borderColor = value ? UIColor.customPink.cgColor : UIColor.black.cgColor + self.registerBtn.backgroundColor = value ? .customPink : .white + value ? self.registerBtn.setTextColor(color: .white) : self.registerBtn.setTextColor(color: .black) + self.registerBtn.isUserInteractionEnabled = value + }).disposed(by: disposeBag) + + idTextField.rx.text + .subscribe( { text in + // text를 넣은 후 네트워킹해서 그 결과값을 sameIdNoticeLbl에 사용 + }).disposed(by: disposeBag) + + pwTextField.rx.text + .map { self.viewModel.checkPw(PassWord: $0!)} + .subscribe { bool in + self.wrongPwLbl.isHidden = bool + }.disposed(by: disposeBag) + + idTextField.rx.text.subscribe( { text in + // text를 넣은 후 네트워킹해서 그 결과값을 sameIdNoticeLbl에 사용 + }).disposed(by: disposeBag) + pwTextField.rx.text.map { self.viewModel.checkPw(PassWord: $0!)}.subscribe { bool in + self.wrongPwLbl.isHidden = bool + }.disposed(by: disposeBag) + } + + private func bindAction() { + popVCBtn.rx.tap + .subscribe { _ in + self.navigationController?.popViewController(animated: true) + }.disposed(by: disposeBag) + + registerBtn.rx.tap.map { + // 이름, 아이디, 비밀번호를 서버에 보냄 + }.subscribe { _ in + let vc = self.makeVC(identifier: ViewControllerName.doubleCheckVC) + self.navigationController?.pushViewController(vc, animated: true) + }.disposed(by: disposeBag) + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Writing/Cell/MemoTableViewCell.swift b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Writing/Cell/MemoTableViewCell.swift new file mode 100644 index 0000000..eeed1a9 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Writing/Cell/MemoTableViewCell.swift @@ -0,0 +1,26 @@ +// +// MemoTableViewCell.swift +// Darner-dan-uh +// +// Created by 문지수 on 2020/12/07. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +class MemoTableViewCell: UITableViewCell { + + @IBOutlet weak var titleLbl: UILabel! + + override func awakeFromNib() { + super.awakeFromNib() + // Initialization code + } + + override func setSelected(_ selected: Bool, animated: Bool) { + super.setSelected(selected, animated: animated) + + // Configure the view for the selected state + } + +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Writing/DetailViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Writing/DetailViewController.swift new file mode 100644 index 0000000..c1962c1 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Writing/DetailViewController.swift @@ -0,0 +1,28 @@ +// +// DetailViewController.swift +// Darner-dan-uh +// +// Created by 문지수 on 2020/12/10. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +class DetailViewController: UIViewController { + + @IBOutlet weak var txtField: UITextField! + @IBOutlet weak var txtView: UITextView! + + override func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + + txtView.layer.borderColor = UIColor.customGray.cgColor + txtView.layer.borderWidth = 1.5 + txtView.layer.cornerRadius = 20 + } + + + +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Writing/MemoViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Writing/MemoViewController.swift new file mode 100644 index 0000000..8435d14 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Writing/MemoViewController.swift @@ -0,0 +1,65 @@ +// +// MemoViewController.swift +// Darner-dan-uh +// +// Created by 문지수 on 2020/12/07. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxSwift +import RxCocoa + +class MemoViewController: UIViewController, UITableViewDataSource { + + let disposeBag = DisposeBag() + + @IBOutlet weak var memoView: UIView! + @IBOutlet weak var tableView: UITableView! + @IBOutlet weak var memoLbl: UILabel! + @IBOutlet weak var writeBtn: UIButton! + + override func viewDidLoad() { + super.viewDidLoad() + // Do any additional setup after loading the view. + + registerCell() + bindAction() + navigationImage() + navigationClear() + + memoView.layer.borderColor = UIColor.black.cgColor + memoView.layer.borderWidth = 1.5 + memoView.layer.cornerRadius = 20 + + + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return MemoModel.dummyDataList.count + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: "memoCell", for: indexPath) + let target = MemoModel.dummyDataList[indexPath.row] + cell.textLabel?.text = target.content + + return cell + } + + func registerCell() { + tableView.rowHeight = 80 + } + + func bindAction() { + writeBtn.rx.tap + .subscribe(onNext: { _ in + self.nextView(identifier: "write") + }).disposed(by: disposeBag) + } + + + + +} diff --git a/Darner-dan-uh/Darner-dan-uh/ViewController.swift b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Writing/WritingViewController.swift similarity index 73% rename from Darner-dan-uh/Darner-dan-uh/ViewController.swift rename to Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Writing/WritingViewController.swift index b1a69ca..41e217d 100644 --- a/Darner-dan-uh/Darner-dan-uh/ViewController.swift +++ b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/Modules/Writing/WritingViewController.swift @@ -1,5 +1,5 @@ // -// ViewController.swift +// WritingVC.swift // Darner-dan-uh // // Created by 이현욱 on 2020/09/03. @@ -8,13 +8,15 @@ import UIKit -class ViewController: UIViewController { +final class WritingViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. } - - + + + + } diff --git a/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/MypageModel.swift b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/MypageModel.swift new file mode 100644 index 0000000..b06ca79 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/MypageModel.swift @@ -0,0 +1,23 @@ +// +// MyPageModel.swift +// Darner-dan-uh +// +// Created by 문지수 on 2020/10/15. +// Copyright © 2020 이현욱. All rights reserved. +// + +import Foundation + +struct MypageModel: Codable { + //let profileImage: String + let name: String + let userId: String + let ModifyProfile: String + let selectCharacter: String + +} + +struct passwordModel: Codable { + let password: String? + +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/MypageViewModel.swift b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/MypageViewModel.swift new file mode 100644 index 0000000..8ea9b71 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/MypageViewModel.swift @@ -0,0 +1,30 @@ +// +// MypageViewModel.swift +// Darner-dan-uh +// +// Created by 문지수 on 2020/11/05. +// Copyright © 2020 이현욱. All rights reserved. +// + +import Foundation + +import RxSwift +import RxCocoa + +class MypageViewModel { + + let disposeBag = DisposeBag() + + struct Input { + let nickName: Driver + } + struct Output { + let result: Signal + } + func transform(_ input: Input) -> Output { + let result = PublishSubject() + + + return Output(result: result.asSignal(onErrorJustReturn: "실패")) + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/RankingViewModel.swift b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/RankingViewModel.swift new file mode 100644 index 0000000..86deeaf --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/RankingViewModel.swift @@ -0,0 +1,34 @@ +// +// RankingViewModel.swift +// Darner-dan-uh +// +// Created by 문지수 on 2020/11/19. +// Copyright © 2020 이현욱. All rights reserved. +// + +import Foundation + +import RxSwift +import RxCocoa + +class RankingViewModel: ViewModelType { + + private let disposeBag = DisposeBag() + let loadData = PublishRelay() + + struct Input { + let loadData: Signal + } + struct Output { + let result: Signal + let loadApplyList: PublishRelay<[RankingModel]> + } + + func transform(_ input: Input) -> Output { + let result = PublishSubject() + let loadApplyList = PublishRelay<[RankingModel]>() + + + return Output(result: result.asSignal(onErrorJustReturn: "메시지 메시지"), loadApplyList: loadApplyList) + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/RegisterViewModel.swift b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/RegisterViewModel.swift new file mode 100644 index 0000000..eec9eff --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/RegisterViewModel.swift @@ -0,0 +1,32 @@ +// +// RegisterViewModel.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/10/14. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxSwift +import RxCocoa + +class RegisterViewModel: ViewModelType { + struct Input { + var idTextFieldSubject: Observable + var pwTextFieldSubject: Observable + var emailTextFieldSubject: Observable + var nameTextField: Observable + } + + struct Output { + var signal: Driver + } + + func transform(_ input: Input) -> Output { + let bool = Observable.combineLatest(input.idTextFieldSubject, input.emailTextFieldSubject, input.nameTextField, input.pwTextFieldSubject).map { !$0.isEmpty && !$1.isEmpty && !$2.isEmpty && !$3.isEmpty }.asDriver(onErrorJustReturn: false) + + return Output(signal: bool) + } +} + diff --git a/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/SeeMypageViewModel.swift b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/SeeMypageViewModel.swift new file mode 100644 index 0000000..061fd1e --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/SeeMypageViewModel.swift @@ -0,0 +1,30 @@ +// +// SeeMypageViewModel.swift +// Darner-dan-uh +// +// Created by 문지수 on 2020/12/02. +// Copyright © 2020 이현욱. All rights reserved. +// + +import Foundation + +import RxSwift +import RxCocoa + +class SeeMypageViewModel: ViewModelType { + + let disposeBag = DisposeBag() + + struct Input { + let doneTap: Driver + } + struct Output { + let result: Signal + } + + func transform(_ input: Input) -> Output { + let result = PublishSubject() + + return Output(result: result.asSignal(onErrorJustReturn: "")) + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/TestViewModel.swift b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/TestViewModel.swift new file mode 100644 index 0000000..af9a729 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/TestViewModel.swift @@ -0,0 +1,29 @@ +// +// TestViewModel.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/11/24. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +import RxCocoa +import RxSwift + +class TestViewModel: ViewModelType { + var word: String! + struct Input { + let meanSubject: Observable + let nextWordTap: Single + } + + struct Output { + let resultWord: Observable + } + + func transform(_ input: Input) -> Output { + return Output(resultWord: input.meanSubject.map { $0.isEmpty }.asObservable()) + + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/ViewModelType.swift b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/ViewModelType.swift new file mode 100644 index 0000000..d6d5e92 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Source/ViewModel/ViewModelType.swift @@ -0,0 +1,16 @@ +// +// ViewModelType.swift +// Darner-dan-uh +// +// Created by 문지수 on 2020/10/15. +// Copyright © 2020 이현욱. All rights reserved. +// + +import Foundation + +protocol ViewModelType { + associatedtype Input + associatedtype Output + + func transform(_ input: Input) -> Output +} diff --git a/.DS_Store b/Darner-dan-uh/Darner-dan-uh/Supporting/.DS_Store similarity index 80% rename from .DS_Store rename to Darner-dan-uh/Darner-dan-uh/Supporting/.DS_Store index 799fa62..a6b7b4d 100644 Binary files a/.DS_Store and b/Darner-dan-uh/Darner-dan-uh/Supporting/.DS_Store differ diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/AppDelegate.swift b/Darner-dan-uh/Darner-dan-uh/Supporting/AppDelegate.swift new file mode 100644 index 0000000..e5bd481 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Supporting/AppDelegate.swift @@ -0,0 +1,21 @@ +// +// AppDelegate.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/09/03. +// Copyright © 2020 이현욱. All rights reserved. +// + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + var window:UIWindow? + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + // Override point for customization after application launch. + return true + } +} + diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/<.imageset/<.png b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/<.imageset/<.png new file mode 100644 index 0000000..b01846b Binary files /dev/null and b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/<.imageset/<.png differ diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/<.imageset/<@2x.png b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/<.imageset/<@2x.png new file mode 100644 index 0000000..c0a8639 Binary files /dev/null and b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/<.imageset/<@2x.png differ diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/<.imageset/<@3x.png b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/<.imageset/<@3x.png new file mode 100644 index 0000000..1a3ba30 Binary files /dev/null and b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/<.imageset/<@3x.png differ diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/<.imageset/Contents.json b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/<.imageset/Contents.json new file mode 100644 index 0000000..9e357ab --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/<.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "<.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "<@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "<@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Assets.xcassets/AppIcon.appiconset/Contents.json b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from Darner-dan-uh/Darner-dan-uh/Assets.xcassets/AppIcon.appiconset/Contents.json rename to Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/Darner-dan-uh/Darner-dan-uh/Assets.xcassets/Contents.json b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/Contents.json similarity index 100% rename from Darner-dan-uh/Darner-dan-uh/Assets.xcassets/Contents.json rename to Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/Contents.json diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/Icon ionic-ios-checkmark-circle.imageset/Contents.json b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/Icon ionic-ios-checkmark-circle.imageset/Contents.json new file mode 100644 index 0000000..4f1f2f5 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/Icon ionic-ios-checkmark-circle.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Icon ionic-ios-checkmark-circle.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Icon ionic-ios-checkmark-circle@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Icon ionic-ios-checkmark-circle@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/Icon ionic-ios-checkmark-circle.imageset/Icon ionic-ios-checkmark-circle.png b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/Icon ionic-ios-checkmark-circle.imageset/Icon ionic-ios-checkmark-circle.png new file mode 100644 index 0000000..6c6054b Binary files /dev/null and b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/Icon ionic-ios-checkmark-circle.imageset/Icon ionic-ios-checkmark-circle.png differ diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/Icon ionic-ios-checkmark-circle.imageset/Icon ionic-ios-checkmark-circle@2x.png b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/Icon ionic-ios-checkmark-circle.imageset/Icon ionic-ios-checkmark-circle@2x.png new file mode 100644 index 0000000..b1ac77e Binary files /dev/null and b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/Icon ionic-ios-checkmark-circle.imageset/Icon ionic-ios-checkmark-circle@2x.png differ diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/Icon ionic-ios-checkmark-circle.imageset/Icon ionic-ios-checkmark-circle@3x.png b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/Icon ionic-ios-checkmark-circle.imageset/Icon ionic-ios-checkmark-circle@3x.png new file mode 100644 index 0000000..64aa178 Binary files /dev/null and b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/Icon ionic-ios-checkmark-circle.imageset/Icon ionic-ios-checkmark-circle@3x.png differ diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/Icon material-radio-button-unchecked.imageset/Contents.json b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/Icon material-radio-button-unchecked.imageset/Contents.json new file mode 100644 index 0000000..3579ff2 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/Icon material-radio-button-unchecked.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Icon material-radio-button-unchecked.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Icon material-radio-button-unchecked@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Icon material-radio-button-unchecked@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/Icon material-radio-button-unchecked.imageset/Icon material-radio-button-unchecked.png b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/Icon material-radio-button-unchecked.imageset/Icon material-radio-button-unchecked.png new file mode 100644 index 0000000..a5a1272 Binary files /dev/null and b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/Icon material-radio-button-unchecked.imageset/Icon material-radio-button-unchecked.png differ diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/Icon material-radio-button-unchecked.imageset/Icon material-radio-button-unchecked@2x.png b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/Icon material-radio-button-unchecked.imageset/Icon material-radio-button-unchecked@2x.png new file mode 100644 index 0000000..a2d8eb9 Binary files /dev/null and b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/Icon material-radio-button-unchecked.imageset/Icon material-radio-button-unchecked@2x.png differ diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/Icon material-radio-button-unchecked.imageset/Icon material-radio-button-unchecked@3x.png b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/Icon material-radio-button-unchecked.imageset/Icon material-radio-button-unchecked@3x.png new file mode 100644 index 0000000..fcba74c Binary files /dev/null and b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/Icon material-radio-button-unchecked.imageset/Icon material-radio-button-unchecked@3x.png differ diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/LogoImage.imageset/Contents.json b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/LogoImage.imageset/Contents.json new file mode 100644 index 0000000..332ffd1 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/LogoImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "LogoImage.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "LogoImage@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "LogoImage@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/LogoImage.imageset/LogoImage.png b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/LogoImage.imageset/LogoImage.png new file mode 100644 index 0000000..301e5ab Binary files /dev/null and b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/LogoImage.imageset/LogoImage.png differ diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/LogoImage.imageset/LogoImage@2x.png b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/LogoImage.imageset/LogoImage@2x.png new file mode 100644 index 0000000..04ebdd0 Binary files /dev/null and b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/LogoImage.imageset/LogoImage@2x.png differ diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/LogoImage.imageset/LogoImage@3x.png b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/LogoImage.imageset/LogoImage@3x.png new file mode 100644 index 0000000..d40e4f7 Binary files /dev/null and b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/LogoImage.imageset/LogoImage@3x.png differ diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/book.imageset/Contents.json b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/book.imageset/Contents.json new file mode 100644 index 0000000..4b338ae --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/book.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "book.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "book@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "book@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/book.imageset/book.png b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/book.imageset/book.png new file mode 100644 index 0000000..963a57d Binary files /dev/null and b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/book.imageset/book.png differ diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/book.imageset/book@2x.png b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/book.imageset/book@2x.png new file mode 100644 index 0000000..fedcdd0 Binary files /dev/null and b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/book.imageset/book@2x.png differ diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/book.imageset/book@3x.png b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/book.imageset/book@3x.png new file mode 100644 index 0000000..ee68425 Binary files /dev/null and b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/book.imageset/book@3x.png differ diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/minus.imageset/Contents.json b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/minus.imageset/Contents.json new file mode 100644 index 0000000..94f9239 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/minus.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "minus.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "minus@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "minus@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/minus.imageset/minus.png b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/minus.imageset/minus.png new file mode 100644 index 0000000..21b4b5e Binary files /dev/null and b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/minus.imageset/minus.png differ diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/minus.imageset/minus@2x.png b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/minus.imageset/minus@2x.png new file mode 100644 index 0000000..3f0486c Binary files /dev/null and b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/minus.imageset/minus@2x.png differ diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/minus.imageset/minus@3x.png b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/minus.imageset/minus@3x.png new file mode 100644 index 0000000..c9a398e Binary files /dev/null and b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/minus.imageset/minus@3x.png differ diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/pencil.imageset/Contents.json b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/pencil.imageset/Contents.json new file mode 100644 index 0000000..4c3712f --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/pencil.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "pencil.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "pencil@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "pencil@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/pencil.imageset/pencil.png b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/pencil.imageset/pencil.png new file mode 100644 index 0000000..5de8f8c Binary files /dev/null and b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/pencil.imageset/pencil.png differ diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/pencil.imageset/pencil@2x.png b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/pencil.imageset/pencil@2x.png new file mode 100644 index 0000000..df37758 Binary files /dev/null and b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/pencil.imageset/pencil@2x.png differ diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/pencil.imageset/pencil@3x.png b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/pencil.imageset/pencil@3x.png new file mode 100644 index 0000000..d1fb5ce Binary files /dev/null and b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/pencil.imageset/pencil@3x.png differ diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/plus.imageset/Contents.json b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/plus.imageset/Contents.json new file mode 100644 index 0000000..c28f99d --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/plus.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "plust.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "plust@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "plust@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/plus.imageset/plust.png b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/plus.imageset/plust.png new file mode 100644 index 0000000..ac00d00 Binary files /dev/null and b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/plus.imageset/plust.png differ diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/plus.imageset/plust@2x.png b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/plus.imageset/plust@2x.png new file mode 100644 index 0000000..b0ca24e Binary files /dev/null and b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/plus.imageset/plust@2x.png differ diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/plus.imageset/plust@3x.png b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/plus.imageset/plust@3x.png new file mode 100644 index 0000000..101a4c5 Binary files /dev/null and b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/plus.imageset/plust@3x.png differ diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/profileImg.imageset/Contents.json b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/profileImg.imageset/Contents.json new file mode 100644 index 0000000..28df6a6 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/profileImg.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "profileImg.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "profileImg@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "profileImg@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/profileImg.imageset/profileImg.png b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/profileImg.imageset/profileImg.png new file mode 100644 index 0000000..ae53084 Binary files /dev/null and b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/profileImg.imageset/profileImg.png differ diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/profileImg.imageset/profileImg@2x.png b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/profileImg.imageset/profileImg@2x.png new file mode 100644 index 0000000..386b5ca Binary files /dev/null and b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/profileImg.imageset/profileImg@2x.png differ diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/profileImg.imageset/profileImg@3x.png b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/profileImg.imageset/profileImg@3x.png new file mode 100644 index 0000000..2f22fec Binary files /dev/null and b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/profileImg.imageset/profileImg@3x.png differ diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/ranking.imageset/Contents.json b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/ranking.imageset/Contents.json new file mode 100644 index 0000000..ea5bd2e --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/ranking.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "ranking.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "ranking@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "ranking@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/ranking.imageset/ranking.png b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/ranking.imageset/ranking.png new file mode 100644 index 0000000..0f11644 Binary files /dev/null and b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/ranking.imageset/ranking.png differ diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/ranking.imageset/ranking@2x.png b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/ranking.imageset/ranking@2x.png new file mode 100644 index 0000000..b3d2948 Binary files /dev/null and b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/ranking.imageset/ranking@2x.png differ diff --git a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/ranking.imageset/ranking@3x.png b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/ranking.imageset/ranking@3x.png new file mode 100644 index 0000000..8241ebe Binary files /dev/null and b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/ranking.imageset/ranking@3x.png differ diff --git "a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\353\205\270\353\236\200\353\263\221\354\225\204\353\246\254.imageset/120703954_2817423671803873_5352483087556580530_n.png" "b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\353\205\270\353\236\200\353\263\221\354\225\204\353\246\254.imageset/120703954_2817423671803873_5352483087556580530_n.png" new file mode 100644 index 0000000..2fe8157 Binary files /dev/null and "b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\353\205\270\353\236\200\353\263\221\354\225\204\353\246\254.imageset/120703954_2817423671803873_5352483087556580530_n.png" differ diff --git "a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\353\205\270\353\236\200\353\263\221\354\225\204\353\246\254.imageset/Contents.json" "b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\353\205\270\353\236\200\353\263\221\354\225\204\353\246\254.imageset/Contents.json" new file mode 100644 index 0000000..28ecd1a --- /dev/null +++ "b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\353\205\270\353\236\200\353\263\221\354\225\204\353\246\254.imageset/Contents.json" @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "120703954_2817423671803873_5352483087556580530_n.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git "a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\353\205\270\353\236\200\354\225\214.imageset/Contents.json" "b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\353\205\270\353\236\200\354\225\214.imageset/Contents.json" new file mode 100644 index 0000000..c4088b2 --- /dev/null +++ "b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\353\205\270\353\236\200\354\225\214.imageset/Contents.json" @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "스크린샷 2020-10-08 오전 11.15.48.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git "a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\353\205\270\353\236\200\354\225\214.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2020-10-08 \354\230\244\354\240\204 11.15.48.png" "b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\353\205\270\353\236\200\354\225\214.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2020-10-08 \354\230\244\354\240\204 11.15.48.png" new file mode 100644 index 0000000..4f7f132 Binary files /dev/null and "b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\353\205\270\353\236\200\354\225\214.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2020-10-08 \354\230\244\354\240\204 11.15.48.png" differ diff --git "a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\353\241\234\352\263\240&\355\225\221\355\201\254 \353\263\221\354\225\204\353\246\254.imageset/Contents.json" "b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\353\241\234\352\263\240&\355\225\221\355\201\254 \353\263\221\354\225\204\353\246\254.imageset/Contents.json" new file mode 100644 index 0000000..a84850d --- /dev/null +++ "b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\353\241\234\352\263\240&\355\225\221\355\201\254 \353\263\221\354\225\204\353\246\254.imageset/Contents.json" @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "스크린샷 2020-09-25 오전 9.57.56.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git "a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\353\241\234\352\263\240&\355\225\221\355\201\254 \353\263\221\354\225\204\353\246\254.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2020-09-25 \354\230\244\354\240\204 9.57.56-1.png" "b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\353\241\234\352\263\240&\355\225\221\355\201\254 \353\263\221\354\225\204\353\246\254.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2020-09-25 \354\230\244\354\240\204 9.57.56-1.png" new file mode 100644 index 0000000..2b9b7b2 Binary files /dev/null and "b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\353\241\234\352\263\240&\355\225\221\355\201\254 \353\263\221\354\225\204\353\246\254.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2020-09-25 \354\230\244\354\240\204 9.57.56-1.png" differ diff --git "a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\354\212\244\355\203\235.imageset/Contents.json" "b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\354\212\244\355\203\235.imageset/Contents.json" new file mode 100644 index 0000000..2c9759c --- /dev/null +++ "b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\354\212\244\355\203\235.imageset/Contents.json" @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "스크린샷 2020-12-07 오후 7.26.08.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git "a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\354\212\244\355\203\235.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2020-12-06 \354\230\244\355\233\204 2.48.22.png" "b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\354\212\244\355\203\235.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2020-12-06 \354\230\244\355\233\204 2.48.22.png" new file mode 100644 index 0000000..da03764 Binary files /dev/null and "b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\354\212\244\355\203\235.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2020-12-06 \354\230\244\355\233\204 2.48.22.png" differ diff --git "a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\354\212\244\355\203\235.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2020-12-07 \354\230\244\355\233\204 7.26.08.png" "b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\354\212\244\355\203\235.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2020-12-07 \354\230\244\355\233\204 7.26.08.png" new file mode 100644 index 0000000..b41141e Binary files /dev/null and "b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\354\212\244\355\203\235.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2020-12-07 \354\230\244\355\233\204 7.26.08.png" differ diff --git "a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\354\236\220\353\254\274\354\207\240.imageset/Contents.json" "b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\354\236\220\353\254\274\354\207\240.imageset/Contents.json" new file mode 100644 index 0000000..df089d9 --- /dev/null +++ "b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\354\236\220\353\254\274\354\207\240.imageset/Contents.json" @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "그룹 49.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "그룹 49@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "그룹 49@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git "a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\354\236\220\353\254\274\354\207\240.imageset/\352\267\270\353\243\271 49.png" "b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\354\236\220\353\254\274\354\207\240.imageset/\352\267\270\353\243\271 49.png" new file mode 100644 index 0000000..f974728 Binary files /dev/null and "b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\354\236\220\353\254\274\354\207\240.imageset/\352\267\270\353\243\271 49.png" differ diff --git "a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\354\236\220\353\254\274\354\207\240.imageset/\352\267\270\353\243\271 49@2x.png" "b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\354\236\220\353\254\274\354\207\240.imageset/\352\267\270\353\243\271 49@2x.png" new file mode 100644 index 0000000..4481b28 Binary files /dev/null and "b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\354\236\220\353\254\274\354\207\240.imageset/\352\267\270\353\243\271 49@2x.png" differ diff --git "a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\354\236\220\353\254\274\354\207\240.imageset/\352\267\270\353\243\271 49@3x.png" "b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\354\236\220\353\254\274\354\207\240.imageset/\352\267\270\353\243\271 49@3x.png" new file mode 100644 index 0000000..dd715e5 Binary files /dev/null and "b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\354\236\220\353\254\274\354\207\240.imageset/\352\267\270\353\243\271 49@3x.png" differ diff --git "a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\355\214\214\353\236\200 \353\263\221\354\225\204\353\246\254.imageset/Contents.json" "b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\355\214\214\353\236\200 \353\263\221\354\225\204\353\246\254.imageset/Contents.json" new file mode 100644 index 0000000..2b84201 --- /dev/null +++ "b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\355\214\214\353\236\200 \353\263\221\354\225\204\353\246\254.imageset/Contents.json" @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "스크린샷 2020-10-08 오전 11.15.13.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git "a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\355\214\214\353\236\200 \353\263\221\354\225\204\353\246\254.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2020-10-08 \354\230\244\354\240\204 11.15.13-1.png" "b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\355\214\214\353\236\200 \353\263\221\354\225\204\353\246\254.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2020-10-08 \354\230\244\354\240\204 11.15.13-1.png" new file mode 100644 index 0000000..13c7399 Binary files /dev/null and "b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\355\214\214\353\236\200 \353\263\221\354\225\204\353\246\254.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2020-10-08 \354\230\244\354\240\204 11.15.13-1.png" differ diff --git "a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\355\214\214\353\236\200\354\225\214.imageset/Contents.json" "b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\355\214\214\353\236\200\354\225\214.imageset/Contents.json" new file mode 100644 index 0000000..7ad7144 --- /dev/null +++ "b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\355\214\214\353\236\200\354\225\214.imageset/Contents.json" @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "스크린샷 2020-10-08 오전 11.15.36.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git "a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\355\214\214\353\236\200\354\225\214.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2020-10-08 \354\230\244\354\240\204 11.15.36.png" "b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\355\214\214\353\236\200\354\225\214.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2020-10-08 \354\230\244\354\240\204 11.15.36.png" new file mode 100644 index 0000000..a086565 Binary files /dev/null and "b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\355\214\214\353\236\200\354\225\214.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2020-10-08 \354\230\244\354\240\204 11.15.36.png" differ diff --git "a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\355\225\221\355\201\254\354\225\214.imageset/Contents.json" "b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\355\225\221\355\201\254\354\225\214.imageset/Contents.json" new file mode 100644 index 0000000..0678fe8 --- /dev/null +++ "b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\355\225\221\355\201\254\354\225\214.imageset/Contents.json" @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "스크린샷 2020-10-08 오전 11.15.54.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git "a/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\355\225\221\355\201\254\354\225\214.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2020-10-08 \354\230\244\354\240\204 11.15.54-1.png" "b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\355\225\221\355\201\254\354\225\214.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2020-10-08 \354\230\244\354\240\204 11.15.54-1.png" new file mode 100644 index 0000000..24cbf33 Binary files /dev/null and "b/Darner-dan-uh/Darner-dan-uh/Supporting/Assets.xcassets/\355\225\221\355\201\254\354\225\214.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2020-10-08 \354\230\244\354\240\204 11.15.54-1.png" differ diff --git a/Darner-dan-uh/Darner-dan-uh/ViewModelType.swift b/Darner-dan-uh/Darner-dan-uh/ViewModelType.swift new file mode 100644 index 0000000..d6d5e92 --- /dev/null +++ b/Darner-dan-uh/Darner-dan-uh/ViewModelType.swift @@ -0,0 +1,16 @@ +// +// ViewModelType.swift +// Darner-dan-uh +// +// Created by 문지수 on 2020/10/15. +// Copyright © 2020 이현욱. All rights reserved. +// + +import Foundation + +protocol ViewModelType { + associatedtype Input + associatedtype Output + + func transform(_ input: Input) -> Output +} diff --git a/Darner-dan-uh/MessageModel.swift b/Darner-dan-uh/MessageModel.swift new file mode 100644 index 0000000..a31c365 --- /dev/null +++ b/Darner-dan-uh/MessageModel.swift @@ -0,0 +1,13 @@ +// +// MessageModel.swift +// Darner-dan-uh +// +// Created by 이현욱 on 2020/11/27. +// Copyright © 2020 이현욱. All rights reserved. +// + +import Foundation + +struct MessageModel: Codable { + var message: String +} diff --git a/Darner-dan-uh/Podfile b/Darner-dan-uh/Podfile index 1a1012e..f535e47 100644 --- a/Darner-dan-uh/Podfile +++ b/Darner-dan-uh/Podfile @@ -6,8 +6,11 @@ target 'Darner-dan-uh' do use_frameworks! # Pods for Darner-dan-uh - pod 'RxSwift' - pod 'RxCocoa' + pod 'RxSwift', '~> 5.1' + pod 'RxCocoa', '~> 5.1' pod 'Alamofire', '~> 5.2' + pod 'RxAlamofire' + pod 'RealmSwift' + end diff --git a/Darner-dan-uh/Podfile.lock b/Darner-dan-uh/Podfile.lock index 040d2a1..7e10ed0 100644 --- a/Darner-dan-uh/Podfile.lock +++ b/Darner-dan-uh/Podfile.lock @@ -1,5 +1,15 @@ PODS: - Alamofire (5.2.2) + - Realm (10.1.1): + - Realm/Headers (= 10.1.1) + - Realm/Headers (10.1.1) + - RealmSwift (10.1.1): + - Realm (= 10.1.1) + - RxAlamofire (5.6.2): + - RxAlamofire/Core (= 5.6.2) + - RxAlamofire/Core (5.6.2): + - Alamofire (~> 5.2) + - RxSwift (~> 5.1) - RxCocoa (5.1.1): - RxRelay (~> 5) - RxSwift (~> 5) @@ -9,22 +19,30 @@ PODS: DEPENDENCIES: - Alamofire (~> 5.2) - - RxCocoa - - RxSwift + - RealmSwift + - RxAlamofire + - RxCocoa (~> 5.1) + - RxSwift (~> 5.1) SPEC REPOS: trunk: - Alamofire + - Realm + - RealmSwift + - RxAlamofire - RxCocoa - RxRelay - RxSwift SPEC CHECKSUMS: Alamofire: 814429acc853c6c54ff123fc3d2ef66803823ce0 + Realm: 784ca1da1453e31a9c9adc14445421a81f316119 + RealmSwift: cc52fe0dcea56387274dff36e19219e055a3bb84 + RxAlamofire: aa949d345b1689eae02b7c7a217518878144f6df RxCocoa: 32065309a38d29b5b0db858819b5bf9ef038b601 RxRelay: d77f7d771495f43c556cbc43eebd1bb54d01e8e9 RxSwift: 81470a2074fa8780320ea5fe4102807cb7118178 -PODFILE CHECKSUM: 9b6797e092ebfb6e468c59415b10823426df6923 +PODFILE CHECKSUM: c84c9ff937882d44a7fe52d67dbc8a1a15920136 -COCOAPODS: 1.9.3 +COCOAPODS: 1.10.0 diff --git a/Darner-dan-uh/Pods/Manifest.lock b/Darner-dan-uh/Pods/Manifest.lock index 040d2a1..7e10ed0 100644 --- a/Darner-dan-uh/Pods/Manifest.lock +++ b/Darner-dan-uh/Pods/Manifest.lock @@ -1,5 +1,15 @@ PODS: - Alamofire (5.2.2) + - Realm (10.1.1): + - Realm/Headers (= 10.1.1) + - Realm/Headers (10.1.1) + - RealmSwift (10.1.1): + - Realm (= 10.1.1) + - RxAlamofire (5.6.2): + - RxAlamofire/Core (= 5.6.2) + - RxAlamofire/Core (5.6.2): + - Alamofire (~> 5.2) + - RxSwift (~> 5.1) - RxCocoa (5.1.1): - RxRelay (~> 5) - RxSwift (~> 5) @@ -9,22 +19,30 @@ PODS: DEPENDENCIES: - Alamofire (~> 5.2) - - RxCocoa - - RxSwift + - RealmSwift + - RxAlamofire + - RxCocoa (~> 5.1) + - RxSwift (~> 5.1) SPEC REPOS: trunk: - Alamofire + - Realm + - RealmSwift + - RxAlamofire - RxCocoa - RxRelay - RxSwift SPEC CHECKSUMS: Alamofire: 814429acc853c6c54ff123fc3d2ef66803823ce0 + Realm: 784ca1da1453e31a9c9adc14445421a81f316119 + RealmSwift: cc52fe0dcea56387274dff36e19219e055a3bb84 + RxAlamofire: aa949d345b1689eae02b7c7a217518878144f6df RxCocoa: 32065309a38d29b5b0db858819b5bf9ef038b601 RxRelay: d77f7d771495f43c556cbc43eebd1bb54d01e8e9 RxSwift: 81470a2074fa8780320ea5fe4102807cb7118178 -PODFILE CHECKSUM: 9b6797e092ebfb6e468c59415b10823426df6923 +PODFILE CHECKSUM: c84c9ff937882d44a7fe52d67dbc8a1a15920136 -COCOAPODS: 1.9.3 +COCOAPODS: 1.10.0 diff --git a/Darner-dan-uh/Pods/Pods.xcodeproj/project.pbxproj b/Darner-dan-uh/Pods/Pods.xcodeproj/project.pbxproj index fcd19b0..6de53f1 100644 --- a/Darner-dan-uh/Pods/Pods.xcodeproj/project.pbxproj +++ b/Darner-dan-uh/Pods/Pods.xcodeproj/project.pbxproj @@ -3,764 +3,1360 @@ archiveVersion = 1; classes = { }; - objectVersion = 50; + objectVersion = 51; objects = { /* Begin PBXBuildFile section */ - 00FA1801533D853DDBCE33A57D28D648 /* PublishRelay+Signal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A4B1BFFB33A19ABE0476723FF458911 /* PublishRelay+Signal.swift */; }; - 013BAC24F7AC722E59517CB110A9E685 /* HTTPMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2671F655EE04D6C0885DE056312A4A03 /* HTTPMethod.swift */; }; - 02C64A705AFBB72766D93EC1EF5CD60C /* UIScrollView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A11A7403C8F81B77F8C11652F2506DE /* UIScrollView+Rx.swift */; }; - 02D1115606C8781D7F76BCE3033EEB9D /* Queue.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA4D142FFB629B426F6F7629322ED1F8 /* Queue.swift */; }; - 03A4EF6D6ACF6027EE70E29F57D05C93 /* CurrentThreadScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0FB17359AB6A988872D730206FFEBD8 /* CurrentThreadScheduler.swift */; }; - 06504FFE7AB5C57B2E1626C35E42023A /* ControlEvent+Signal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58E09376519428A591949F090A35B864 /* ControlEvent+Signal.swift */; }; - 07346B19736ECE7D9BA113A615C601D6 /* GroupBy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69272EAAED861BAC838702AA74D4304E /* GroupBy.swift */; }; - 078528915ABA677900726FAE8A8D0D05 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 169AAA422E46B126BBAD577E53742277 /* Foundation.framework */; }; - 089D379A99B15CCB464114CCDC8A48A8 /* Deprecated.swift in Sources */ = {isa = PBXBuildFile; fileRef = F45F941037CC8A4B549EB846D4E8A16C /* Deprecated.swift */; }; - 09FC4987B40193613404BC3AC42C84CC /* SynchronizedUnsubscribeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76EDB2CA5901A84A6295300BFF0991EB /* SynchronizedUnsubscribeType.swift */; }; - 0A15F6D793421163A92E18ED9E911F87 /* Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF14D9E05169A85F309D5DBE3E472064 /* Logging.swift */; }; - 0A1849775CF90D514963187D3A771CF8 /* Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7D82EFD974A7B79DCB06387BFA6925C9 /* Combine.swift */; }; - 0A42BD548A8D5A0800D7CDD82B41EFF0 /* UINavigationItem+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2159023945A21C8A29D239741B1B810E /* UINavigationItem+Rx.swift */; }; - 0A900DF17E3B64F08AF673E9A0DDD697 /* OperationQueue+Alamofire.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5399BBECE22553D36BE196941994439E /* OperationQueue+Alamofire.swift */; }; - 0BB5D87B0D3F6911A672D1D064B7EADB /* Disposables.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE61BF1C347838ECDC5CA622A6258781 /* Disposables.swift */; }; - 0BF392DCED5271A700BB662938E60583 /* Skip.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0672041CFD2E8E368862BC23B86B5FC6 /* Skip.swift */; }; - 0C2AEEA5C30032AF2F9EC02C0128ED13 /* ControlEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24C9AE967D758E6AB98C25E5D66EE0A2 /* ControlEvent.swift */; }; - 0D09D765CA4AA853CC79DB9677D60DD3 /* Window.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04C814DE3552E1C0885EB29AE5F93775 /* Window.swift */; }; - 0EEF619C2531D6CCFD15EA37C965F3A0 /* Zip+Collection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95FBECA2920D68E70F2D918ED16EE65F /* Zip+Collection.swift */; }; - 1171EDC4E196453CF248BBB703A105FC /* Sink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51EE13A170006C38AA759AC268753B9A /* Sink.swift */; }; - 11DB4B048DFAA48121111E915D511F12 /* Platform.Linux.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE06908A1B2870327F0ADF60A1C33E5A /* Platform.Linux.swift */; }; - 1208E81DA8B532D0646D627B50290EB6 /* AFError.swift in Sources */ = {isa = PBXBuildFile; fileRef = EFFD32926EA4BD2FE54020AEF89AF043 /* AFError.swift */; }; - 1381BECD9CEAC751B1D9C4D25D13A25B /* SkipUntil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17612A8C6862BA406B34D6804B974582 /* SkipUntil.swift */; }; - 139CA98072F5DBA2277D37E5CF6B56D2 /* StartWith.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8298B6CF3236C82E2CAD1913C751A27A /* StartWith.swift */; }; - 144B84C01342DD588EE98169B133057B /* NSView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9DA3AB3AE025125F455612E4434A6CBB /* NSView+Rx.swift */; }; - 15D0D8EE39393B4628502414BD95C248 /* NSObject+Rx+RawRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48F1B0D43C35A06740FE33CFC6A0F5D3 /* NSObject+Rx+RawRepresentable.swift */; }; - 164528FB725289ABED8C8DAC554C5FE5 /* Throttle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EABE903FA94A1A4C7BCE0C7FA3792 /* Throttle.swift */; }; - 16B1D83EEC7F48EA8F95F891519AE6D9 /* BinaryDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D51CA2749FDF55B4FCB399B3C2D0CD2 /* BinaryDisposable.swift */; }; - 16BB39EAD21D4FF5A0D3E70AC1B18859 /* Observable+Bind.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5FFF26103E94AD4A7D0FC160FBB109D /* Observable+Bind.swift */; }; - 16BE28E8C4861D7097B857C480542D16 /* DispatchQueue+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08877CA69F0BFBF0E65E49E70100C379 /* DispatchQueue+Extensions.swift */; }; - 179A924CC44BF28726F6D33001A5F5D8 /* Bag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FFF273E60390BCB4D3FDF0CF08E2348 /* Bag.swift */; }; - 17AE39C327A90155996F848C3E08D8BA /* Merge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 491B91C5AEEA5379C8161A8EF83C2201 /* Merge.swift */; }; - 17B9CEBBD5764D362F71128009E4469A /* RxCocoa-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = D7B70AB67697E4837993DBE6B65020DB /* RxCocoa-dummy.m */; }; - 1921A4C797E065C3175C89C03085BC29 /* Reduce.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6649FD173A631AE0DF45F9BD4F0394AA /* Reduce.swift */; }; - 19D605A3233499828FB6B790869F3E9C /* NetworkReachabilityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96FF3C3F6E5DD44B9D6F1953F267234B /* NetworkReachabilityManager.swift */; }; - 1A0290651373E42FF136C54678A70388 /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7118B325E21EA425E6E5598213DEB350 /* Errors.swift */; }; - 1A7F311C56CE2CEC64BFEA35C2DA89BE /* Just.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8DFF242FF6AD0B5D39025559BF1464 /* Just.swift */; }; - 1AFA7FE153D916110AAE766EE1920588 /* SerialDispatchQueueScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2CE2C996E16841660D5D11A174F1C0D /* SerialDispatchQueueScheduler.swift */; }; - 1F6B55D049CA4A0F17091F158365273E /* SharedSequence+Operators+arity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1EEF839E1B9A94BD94894E8610B796B2 /* SharedSequence+Operators+arity.swift */; }; - 212EDC48B68107BEA9247F3464CE696E /* StringEncoding+Alamofire.swift in Sources */ = {isa = PBXBuildFile; fileRef = D27DC19B8134DEAE3D1C8C556C7A2E59 /* StringEncoding+Alamofire.swift */; }; - 218C14EAE5AA31C30314AE0289B732A0 /* Protected.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39DCD13C6B63A7BC27F88C977C14B2D8 /* Protected.swift */; }; - 21B090D339DBFB4F7FD1BE9E80BE5E85 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 144449BF4EA97422477E85516C12E4BD /* Utils.swift */; }; - 21B0B6449882CCDCCD83C054AC5E2792 /* SynchronizedOnType.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7D2B542D62F95B89FE0D38ED224B69E /* SynchronizedOnType.swift */; }; - 23A4EF746AB64504DEB5EFDBA5450492 /* RxCocoa-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = E146C0BF7BD9F63449F05D956A7582FE /* RxCocoa-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 2533166320ACEE9728B4F16958FC90F8 /* UISearchBar+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF04A13053CD1DF27E37D06B154FA99 /* UISearchBar+Rx.swift */; }; - 2550B408EF306E05ED36C6AAB6837BF1 /* ControlProperty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 225CD57AAC4DAEE8605668C406DE44C3 /* ControlProperty.swift */; }; - 27E37AE40D404DFA7A4B0FE122789204 /* Driver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82222D308116F3DD1A7671C934667A99 /* Driver.swift */; }; - 27E59A11A2743B0595CDE3A08675EAE1 /* DispatchQueue+Alamofire.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A045B4142C036B090AF9E5756BB4564 /* DispatchQueue+Alamofire.swift */; }; - 28B256513A58DB398A2E4BD2CE8EE2A5 /* Generate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2647AC98C4E44EA259D099263375ABA1 /* Generate.swift */; }; - 28FEE3F61E1275C9E2E82FE7A97915D5 /* ObservableConvertibleType+Driver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 194A03463DA0EA64C8D837D89C6AE963 /* ObservableConvertibleType+Driver.swift */; }; - 29D33B120FF9E542C526ECC4F8C18B32 /* SerialDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96F2CC4F3C17654C39122D70966D11A1 /* SerialDisposable.swift */; }; - 2A8FD3A693CCE3F0B20522C1DD4F82B3 /* RxCocoa.h in Headers */ = {isa = PBXBuildFile; fileRef = F6A5D86D62C130F07B87521EC453E5AC /* RxCocoa.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 2AB97EB5B0C17CB8AB8F9B5DF4662B49 /* Concat.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA6709C059CE7E7AE6B666EC6A288782 /* Concat.swift */; }; - 2B9DE05CC8ACBEB8B8B6FEFDFAA9FABD /* Create.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D3DB0FAE03FDA2754ED33CD92F81F37 /* Create.swift */; }; - 2C3CFDD65F1BA7AB67BAC592017179EF /* BehaviorSubject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C2486F75744B1FC4A37CD9456E933D8 /* BehaviorSubject.swift */; }; - 2F9649BA714818478F47344BE7E08151 /* Lock.swift in Sources */ = {isa = PBXBuildFile; fileRef = E49206FA7A03E65E86919B0D459CE145 /* Lock.swift */; }; - 303E0C92168D1B45A96EB56FA114AAB4 /* RxCollectionViewDataSourceProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CB38A7C83A94843D8DAF65E964D744 /* RxCollectionViewDataSourceProxy.swift */; }; - 3147DCDF7BD5EF6A09CCEA02DA51C1E1 /* ConcurrentMainScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BECC5023B1D8885F941AFAB93B43EB /* ConcurrentMainScheduler.swift */; }; - 319CD48B3F0943B0194D7EBE836C3B2A /* Dematerialize.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12D504CEC3F2DA1041E43AFAE3A3CE89 /* Dematerialize.swift */; }; - 3204DA02231F4CCBAA8C0B6EF0627B0A /* PriorityQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AB367DA9D4CDE24360F2925BA4C2586 /* PriorityQueue.swift */; }; - 32544C48C4D27B134A181649A10641D1 /* BooleanDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8013AA35BA7A79039E7A97B8CD16095 /* BooleanDisposable.swift */; }; - 33032AD86EECA3E0CCD0C6600B46B387 /* DisposeBag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99BDD186EF36401951391CA36F2BD69D /* DisposeBag.swift */; }; - 33085BE19BC4950FD825D377A0384853 /* Enumerated.swift in Sources */ = {isa = PBXBuildFile; fileRef = AC32F440BB6CD7FAA9A95920E6307107 /* Enumerated.swift */; }; - 330DB3CAEB0F54399D764FC809B6C5ED /* UIStepper+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48C8732A69884F45E5C836FB0D58C7A1 /* UIStepper+Rx.swift */; }; - 33669FD8E09B5B4890F9C8679FDF4C8F /* Platform.Darwin.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2228729E07329BC7A9BAC6C2F232715 /* Platform.Darwin.swift */; }; - 33CAC57AD2FA7C6141056F36E955ECA7 /* Sequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 035E0AE5379C0D0DF641A79DF7AFC5B5 /* Sequence.swift */; }; - 3492924BB6DC68CCAED4C1142E7739A3 /* RxCocoa.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5010F104E06C52D713C0FEA244872C4B /* RxCocoa.swift */; }; - 352FC9B2FA639258CB77E7C0FB5F6840 /* RxPickerViewDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35959D5AA25F9D8D128B66392E2910EC /* RxPickerViewDelegateProxy.swift */; }; - 354917F5BA206895F2F9FCF8FEBF161E /* CombineLatest+Collection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C4249898DAC7D8426ECFEB9568ECE08 /* CombineLatest+Collection.swift */; }; - 37D85D67348816DADADB998A0343A510 /* SingleAsync.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8562E45AECE2A39A478C87F465CA781E /* SingleAsync.swift */; }; - 37F572B1D4C35D5DE1AE90659641C34F /* UIAlertAction+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84BF31B4F35220C06C94D6486C204AE2 /* UIAlertAction+Rx.swift */; }; - 381D280F4516CFFC0BB451CE0C21A21F /* Timer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39C5C966A2E80796DAC4539D2C64490F /* Timer.swift */; }; - 381FF05F8B4F611EE9C2FDBE4457BB89 /* SessionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEE931632251E7215CB2A71E60D0FD55 /* SessionDelegate.swift */; }; - 38970A50544688DDD6557737769CE86C /* UIRefreshControl+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3316846B050A463A0CBDF297D8B28ED3 /* UIRefreshControl+Rx.swift */; }; - 3A04E00DA0A3F78C8F5C9983AFB98874 /* AnonymousObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 808E993F2D6447824333774C0C6EF094 /* AnonymousObserver.swift */; }; - 3BB89BD0995B26D47EDA758A3F566746 /* Optional.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBCBE12D3F58BBE9E47A986996E6BC27 /* Optional.swift */; }; - 3DF06796726197AEE928AEE9C4B0510A /* RxSearchControllerDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14B18705C3C90C8DA76954AF87DFEAFF /* RxSearchControllerDelegateProxy.swift */; }; - 3E120058DF7459A49DD4E35FBE67D133 /* SubscribeOn.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13A19DFD85A5A97950972F5201F6BEDC /* SubscribeOn.swift */; }; - 3E7E4A485F70C759DBC3CF975C4FEA27 /* NSSlider+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22CF210C57601A6AE86C178E90663A6A /* NSSlider+Rx.swift */; }; - 3EABFE825C3FFAF030663555D2C8080F /* UIDatePicker+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83CCEE94FAB38943A2870279FA91DFE3 /* UIDatePicker+Rx.swift */; }; - 41919C08D2C90A4C12791CFC39D51822 /* Multicast.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D09F935DC494553C710F412276A8499 /* Multicast.swift */; }; - 42FF7C3D0686E7AE441F757528BD18B3 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 169AAA422E46B126BBAD577E53742277 /* Foundation.framework */; }; - 439197DD2AAEE0595B8DA4474C4595CA /* BehaviorRelay+Driver.swift in Sources */ = {isa = PBXBuildFile; fileRef = EFD86B77C2B2C4EB905B878E78BAEB49 /* BehaviorRelay+Driver.swift */; }; - 44032D72CBEE71CD817F3DB89CD39322 /* RefCountDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0E33457BFEC7056E08761A33142749B /* RefCountDisposable.swift */; }; - 44B0BF2665B93BA05D05FBE47BEF7B1B /* NSButton+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = BABE3A3C32E1CB864B5DC70654B3671D /* NSButton+Rx.swift */; }; - 45AFB5D51C5929C8AB5858D694572F91 /* RxCocoaRuntime.h in Headers */ = {isa = PBXBuildFile; fileRef = E7AE4D23E0388E575CFC29BEE9137092 /* RxCocoaRuntime.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 45B8CC1C61E7A0BB28CFA8CE7C12FEBC /* MultipartFormData.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8739FB420371A1A2154926841001385 /* MultipartFormData.swift */; }; - 46AA3C4ACC3EF6ECAAA5F5196C9066BF /* MainScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEF73DB487C51BE3B8089E98680DEEE6 /* MainScheduler.swift */; }; - 47FDBBBD2704901588C3A7C56BBC502D /* ServerTrustEvaluation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E7397B9BB16FC5807B0C849884DED48 /* ServerTrustEvaluation.swift */; }; - 4AEC050FA7D5ED52FDA9DF50EA3560DF /* ParameterEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47FFFD359F4E6910FBFA61F227E03B31 /* ParameterEncoder.swift */; }; - 4DAEB64861955FE51DC5DFD39B2A1C1D /* RxTableViewDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4D8EC26F7663976A02C5C91105B1955 /* RxTableViewDelegateProxy.swift */; }; - 4DE13CD610E6B445AA4104D6B3DCA668 /* ScheduledDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 970BA40FE81A997797A75CA0790B616A /* ScheduledDisposable.swift */; }; - 4E3E4CA7B9F25F6BA15964BB1C9BB3E6 /* Do.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8ADD934EFC16C04986525A256FAF54FC /* Do.swift */; }; - 4FBB4DBC2D984EF3D557AEDDCE238777 /* CombineLatest+arity.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5989B02E82DCF650D22F04BEF8CD45 /* CombineLatest+arity.swift */; }; - 519CF3AAEC307B5130BA02E8460DF541 /* _RXObjCRuntime.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B3A97CA5979AE7A4872B044A506709B /* _RXObjCRuntime.m */; }; - 5204D71C84ED0C9D697D1E4AC98E1A8C /* Disposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 386FAD9AC5C475D7BA99FC1A87649B67 /* Disposable.swift */; }; - 5212A728A6EBC318867A0DB2604E2CE2 /* PublishSubject.swift in Sources */ = {isa = PBXBuildFile; fileRef = B376F5D8698FF8188D605CA8DE79020A /* PublishSubject.swift */; }; - 52C0835254BE9A54C26C05E8B7AC7448 /* Bag.swift in Sources */ = {isa = PBXBuildFile; fileRef = A317AB05AFFC477434FBA792F54107C3 /* Bag.swift */; }; - 538FA8C7CAE943F6CA9EDF5040FD1050 /* SchedulerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29C241C94E36BC9D91A93A0A7A171DBD /* SchedulerType.swift */; }; - 53B97F15B060F2EAF36166B73575057B /* Zip+arity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61F51B59B445C72F183D9CD178727B31 /* Zip+arity.swift */; }; - 5441B6F9D99E964B9DEF28E22DA186C3 /* NSObject+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F1740E9CFCA048D3262400BFDF050F4 /* NSObject+Rx.swift */; }; - 564C61571AFF901B24065864742CD15C /* NopDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92E284F02D192F4D40930B6436D1FF91 /* NopDisposable.swift */; }; - 56637F5983C7E3981550490AFD946487 /* RecursiveScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98EA88CC63643B3A84D3750A2A6E4BAD /* RecursiveScheduler.swift */; }; - 57AFC435A3F7C0F0BEB59D98A5BCE035 /* Sample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 910E3E80559F53D4F796EE8F57AA99C8 /* Sample.swift */; }; - 581460068D8BD0691BD67D4A95FF9A8B /* UITextView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C5C5E1306EC265A2A7887CE3A3F9671 /* UITextView+Rx.swift */; }; - 5823BCC5E382DE702FBE07784AF8FC08 /* NotificationCenter+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5180C903E0EECAD555BDF74DDFE1EC53 /* NotificationCenter+Rx.swift */; }; - 593D382A4A7EEE47FDCAA668E5E3189D /* URLSession+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBECBCED3E2BF4E98A2BF45ADA22CE63 /* URLSession+Rx.swift */; }; - 598FFFD4D64B8A54CD141F10274D8F4F /* RxRelay.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83D73284DCEE4FE8C76234DE2ACCD393 /* RxRelay.framework */; }; - 59A6B0D9EEDC697D0013B02572F0FD7F /* Binder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7C09FCBBBE54CC96607AD5FEA3E1BBE /* Binder.swift */; }; - 59ADA960FD6E41FEC7C3ADEAF7620D4C /* UITabBar+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = F2A94F072357E44438225A4EDB084B20 /* UITabBar+Rx.swift */; }; - 5A37C1F7A988064F018E4657DCB9FAF4 /* Repeat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F2C7582BCAF3FDBE0408C5CE66746BE /* Repeat.swift */; }; - 5A3E64F9BF446D6C7EB89D63C9AC8949 /* First.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1751F9AB9C2E25B9A71A82CDE9604A55 /* First.swift */; }; - 5B26550079AB783C657ECDBF80F3713F /* DispatchQueue+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 746ECD0F77098F9DA6B011D51999C74D /* DispatchQueue+Extensions.swift */; }; - 5B65B608F22EB08CAE74F9D57A935665 /* LockOwnerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DFCDEDCDD5FC14895A9DD21AD8A2F2B /* LockOwnerType.swift */; }; - 5B76B6236E5E08CFAD97BEE71AD3E597 /* SwiftSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = B17B623FDAEFC8D30D3F4F29375FDAB5 /* SwiftSupport.swift */; }; - 5CDE9F4B6E5C2CA57B28D5040F03F8CF /* Signal+Subscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBB241B5200E6C6633679983A73E86A8 /* Signal+Subscription.swift */; }; - 5D99DF3D1F09C9650797EF260152C57B /* Map.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C190B94A6B2940D3FB8792AF205241E /* Map.swift */; }; - 5E3605A3BC245596B6DD17BBFCD55765 /* _RX.m in Sources */ = {isa = PBXBuildFile; fileRef = F137248CF855D03E9C99C333CC2EC7C7 /* _RX.m */; }; - 5ECA61563A0B1B4AF3DD8DB33CC5ECC6 /* PrimitiveSequence+Zip+arity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F07902A639D9463D1E12EF99A9B561 /* PrimitiveSequence+Zip+arity.swift */; }; - 62D16ED4F8A216D49CB3BE043A40C057 /* Observable.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD80F9951E58EFC6FB6F971323560447 /* Observable.swift */; }; - 63171E68FC84120462E1CB6447862C71 /* Buffer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96D5C46415477108721579DE2581D8B8 /* Buffer.swift */; }; - 635E24A31EE03543A8FAFE0EC67A85DC /* UIImageView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1512A6A21B4C585CBD85B24F18ECAAB5 /* UIImageView+Rx.swift */; }; - 637E7100E21DDC1CE80B56DB518EAEBA /* UINavigationController+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59F13789F4CF993E4174281BADA9FE5C /* UINavigationController+Rx.swift */; }; - 63CCB311DA2A1B434FB68157555BDE88 /* TakeWhile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AFABBBFA80EA15962031B302097CA32 /* TakeWhile.swift */; }; - 6464287695ECCBB4CA2CB81462BF1178 /* NSImageView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A92861B69C4DDFEE1EE0D9FAC74DC1 /* NSImageView+Rx.swift */; }; - 6467FE4BA8A61320C4A98A4478485ECB /* Deprecated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A2DBFDEF94D9662C5B07A332E73688E /* Deprecated.swift */; }; - 6546D728B69398F93B506845141EBD61 /* EventMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64B2FF80E466BCBACC87D06E77E7DE42 /* EventMonitor.swift */; }; - 666EC5C8356E6D4448A2FE7BEE77AD88 /* RedirectHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63F81B444952A4A8B726B8F7E7F2DCB4 /* RedirectHandler.swift */; }; - 66B26C6CAE737EC21F4BA1F1851B69C5 /* Result+Alamofire.swift in Sources */ = {isa = PBXBuildFile; fileRef = 264FA160F97784840AFDE866D4E3409D /* Result+Alamofire.swift */; }; - 6797FA90BF2145F3575358E2BF49B4F5 /* UIButton+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29A777BD3705A34957AB2A6F52F7C8B9 /* UIButton+Rx.swift */; }; - 680EFD397F3D67F1E6FBD665174A2E4C /* SingleAssignmentDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 722CD18502E18B8FCB01DF7B127ECDBA /* SingleAssignmentDisposable.swift */; }; - 68A9C5850AF89F7E3B8AFEEAE2A97BB2 /* UITextField+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDCD59A387DF8B278151EF546C7219A6 /* UITextField+Rx.swift */; }; - 68EA7E9593CB7E82CFFA7FF9ABB8D2E4 /* SkipWhile.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF24B42CA8FF2095D4128F7C54728014 /* SkipWhile.swift */; }; - 6AE407A4FB6C3D6ADD862CC6E3067A17 /* Session.swift in Sources */ = {isa = PBXBuildFile; fileRef = A569CB8DDCF470136457D1CEF4A37441 /* Session.swift */; }; - 6B2C4592C8E7AB637DCE61146471D15B /* Debounce.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA38E9C97C704EC0F6A501CF4EA1F1D8 /* Debounce.swift */; }; - 6BD8F6FA000B8377364F162C31A4B39A /* ElementAt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D82BAC61F2EC7EFD05AB9698294168C /* ElementAt.swift */; }; - 6C08F6A77889651626583100F560153D /* RequestTaskMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC960F0E19C0206FFA0D32C0374AB02E /* RequestTaskMap.swift */; }; - 6E4891B53E07159C063567FA272AEEE0 /* TakeLast.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD66064D172EAC9E7AF1EEA0B9036F9B /* TakeLast.swift */; }; - 6E54F64E8DA73F4B0B46C216F9F93F63 /* RequestInterceptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C25F1A4546932BF5BD6CDB8F6D03DE9 /* RequestInterceptor.swift */; }; - 6E5FD487F5200FFE41A8590F1C80D6A3 /* UISwitch+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00BFA1AFA8DBDD22DDA9DD08DF848644 /* UISwitch+Rx.swift */; }; - 6E78218B1AF9B5CE8E63F3B03F4ED902 /* BehaviorRelay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73A9D94E1C53404F1C79C9361B4FE031 /* BehaviorRelay.swift */; }; - 716FD05A624B0B9ECB0A8B8019BE000E /* RxTableViewDataSourceType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 248FFF5E776294F366C883410A62F0FC /* RxTableViewDataSourceType.swift */; }; - 72521FC1A240438582D88313DA2F71B3 /* Signal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C6594A8E2D7855C99BD23EBC9EFE4F5 /* Signal.swift */; }; - 72EC2712926E6D28B52360D9AC41668F /* AlamofireExtended.swift in Sources */ = {isa = PBXBuildFile; fileRef = D802C03FC94B91638F7A8452AB0970DE /* AlamofireExtended.swift */; }; - 73D4B8DBAA4775FA576C6E99DA74E9F5 /* ControlProperty+Driver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4569C98C4590D9EC3361D848DCB582C8 /* ControlProperty+Driver.swift */; }; - 741276A465432A0E1E5D3A6DEC2C98C0 /* PublishRelay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7158E03F9F9E66C75E4578F6F0D41BB4 /* PublishRelay.swift */; }; - 747BFC432635738E49B29E86EF568F32 /* UIActivityIndicatorView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6B8C420AAA1BE4BC3151D7D96707BF0 /* UIActivityIndicatorView+Rx.swift */; }; - 74872B2FC64CC6125CCEF48562B0671E /* ControlTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8F3C4D6343FB0C676E369EA9EC36663 /* ControlTarget.swift */; }; - 75ADC8C732AA9E7F4B01FD30C12E601E /* SubscriptionDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 994EB2413C190238B4D314ECB0A2C6E4 /* SubscriptionDisposable.swift */; }; - 760178B71CDA56FA10A78568F286086C /* ObservableConvertibleType+SharedSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B24C8DC7CFE2282E35EB7B1BAFD5AD2 /* ObservableConvertibleType+SharedSequence.swift */; }; - 781E862E3936B81C76DE56A2B73D39DB /* ObservableConvertibleType.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD61E97AA208CB51580A44C98AED1A57 /* ObservableConvertibleType.swift */; }; - 796616B2692253493BC8674B1FB367FE /* RxTableViewDataSourceProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E85F83E3D8DC015C0BB6EE0E366E7F7 /* RxTableViewDataSourceProxy.swift */; }; - 7A00AC4F9139FB78619C8F298F8283B4 /* UIBarButtonItem+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5440CF35EA37D0984E060E233A0AA89 /* UIBarButtonItem+Rx.swift */; }; - 7A93A22BD86309270AC44C644B7501FE /* _RX.h in Headers */ = {isa = PBXBuildFile; fileRef = 4433B551F7F37D4C8EF24EE7E6CEDFD7 /* _RX.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 7B89A3FFC01803E264A95FEC8BC0605C /* RxSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4F5CAC3DFDC297B2C56D647BF7C7813 /* RxSwift.framework */; }; - 7D3DD4A8BB36733BA15868F7FB8C56CE /* Alamofire-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = C669CA7E16725DF7F9C79E88797A2EFC /* Alamofire-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 7D54E58E435DD28C7AF8C3FD4E1A5EEA /* UIView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FE9880124CA212A9F3C74349C1DE066 /* UIView+Rx.swift */; }; - 7D6BE9FF8C03259DC209739719007DA5 /* TailRecursiveSink.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3D61F86484FDA362AEE65D3A0E407BC /* TailRecursiveSink.swift */; }; - 7E0202A48FF79AAE5A19524E46E45DDC /* Completable+AndThen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7F5512735FA9C93F058AB1204177B7 /* Completable+AndThen.swift */; }; - 7FC14CECCDDE62D4D7A2D79D8957B7CB /* DisposeBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A9C779046CE2DFB9920B383771BF3E8 /* DisposeBase.swift */; }; - 805EEDF5A59400ABD8379567AACA849E /* _RXKVOObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = B36F13BFA7EC28D766E2FA035715D267 /* _RXKVOObserver.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 80AA5AEFA71FA484B90D7B0EF7F9198D /* UITabBarController+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63BB583E7867A580C3470AC51FF64304 /* UITabBarController+Rx.swift */; }; - 8117470A6E1CF87DF2049262E34119F3 /* InfiniteSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AE26FCFCEC8888CF9E2D904C2DEA925 /* InfiniteSequence.swift */; }; - 81D3402DE15865EF965E92F16753CC6D /* RetryWhen.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD8044D97D4AC1C614E59023516FABA6 /* RetryWhen.swift */; }; - 820FCC7B141683EE4A1709B30BE2DB31 /* Zip.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F5BD2B31A5F1E29F8CDF82E49560F2C /* Zip.swift */; }; - 83A9D64190846F4F9018E9CF717B0048 /* SynchronizedDisposeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B32163A93EBC883865AD6CDA2D382ECD /* SynchronizedDisposeType.swift */; }; - 85557BB8ADEDB23D463325DE651CF458 /* UIPickerView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1111B7A662732DE1675B573658011958 /* UIPickerView+Rx.swift */; }; - 86F42A02F82E7BF498DD7E39387FC90A /* AtomicInt.swift in Sources */ = {isa = PBXBuildFile; fileRef = F2B1AF1AE00E323A2E2686D324D76D42 /* AtomicInt.swift */; }; - 86FB0771E04ED3CCAF7DB95BA8B3D910 /* SectionedViewDataSourceType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825187DCC64EE46B0EFA0A41454B8172 /* SectionedViewDataSourceType.swift */; }; - 87DA86D77902ACF17437E16E77A0D6E0 /* _RXObjCRuntime.h in Headers */ = {isa = PBXBuildFile; fileRef = FA22C9E930D6202E623EDBBF50205501 /* _RXObjCRuntime.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 89EB2B6FDB58411C933B9913B315BA05 /* RxRelay-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = F781B391DCFF6B77F0E2AF4C6837C1FD /* RxRelay-dummy.m */; }; - 8AA937910F87915DE700CAB6C868689E /* Notifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CEC26A7701127C819179F739A292434 /* Notifications.swift */; }; - 8C1C0B1D783B20B65C19D3BA181A0FDA /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 169AAA422E46B126BBAD577E53742277 /* Foundation.framework */; }; - 8C1EAC997C4FCDF29630D9B6B4A8542A /* RxNavigationControllerDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5F453AE3E9261B221BC01E1E7937973 /* RxNavigationControllerDelegateProxy.swift */; }; - 8C59DBF8BD1589F58183850B7FE67858 /* UIControl+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 695B8FEB2CE2E58AC36323480D088515 /* UIControl+Rx.swift */; }; - 8D347BF3B80C9984DB0930C3F6683A18 /* NSControl+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17C92B3843A03204045F53BC32AE8085 /* NSControl+Rx.swift */; }; - 8DA4CF1E2F19EF6E9B7F00F3A59510A9 /* AnonymousDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 214A58EDDB0F4A08D69BC72243ACE4A8 /* AnonymousDisposable.swift */; }; - 8E34035DE1B50E48C75EBC3D9EF04F33 /* ImmediateSchedulerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C2C0BA6DCCAC653154B4C7C85BFC951 /* ImmediateSchedulerType.swift */; }; - 8EDBBA201C0BDB79134CE1EA5DA331A0 /* ToArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = 724C773201D9539EF9D9CFF6D6513A87 /* ToArray.swift */; }; - 8EFE85C5F1EB7D1C1173AFCEF47DAC45 /* KVORepresentable+Swift.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EDB5B83E7753170C64A678FD75B51C2 /* KVORepresentable+Swift.swift */; }; - 8FFA1171418DCF41A10A00E3DDF91F4D /* Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8E687F68A8DB2E9F866809491177BF6 /* Rx.swift */; }; - 903230A70B77C4891D1AB14C0D5CFB7C /* WKWebView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = B683310889B53BE8E6A34F95BA755E46 /* WKWebView+Rx.swift */; }; - 911448B2EDA2FF880108F77642797A88 /* ResponseSerialization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BC6717EFA577FA1D6989094852AB703 /* ResponseSerialization.swift */; }; - 918AD74EAED7D96246EB3B40FC9A0BFB /* ObserveOn.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC49BC33E21E74FBF76137DA8666F343 /* ObserveOn.swift */; }; - 91B837CE0DCD8EDB300FCDFFA1279162 /* HTTPHeaders.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68CD61BA0DC293FEC7C65FEABFC9CF7B /* HTTPHeaders.swift */; }; - 9210C710EBF1CB237EA930A8A3C09556 /* RxCocoaObjCRuntimeError+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 556A6CF39F72E28DD01FC3C31B0C116D /* RxCocoaObjCRuntimeError+Extensions.swift */; }; - 9264DEB116B5AE0104CBF6D5963808D4 /* Using.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F18C9B7B688EDE42CA6057820E17CF4 /* Using.swift */; }; - 929F5D52DEAA8E60C42A17646768CD76 /* Never.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F67A48D75B65978C9945E4A75695F2A /* Never.swift */; }; - 92A8C17D76CCEC966A1F3BBC9ED21BB8 /* RxPickerViewDataSourceProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71338F1DF2F29A6EE619AF0A7C9C7311 /* RxPickerViewDataSourceProxy.swift */; }; - 93B06FCEA76AF6E623A9E5138ED58F0E /* Maybe.swift in Sources */ = {isa = PBXBuildFile; fileRef = B084E4A57E92EDDCD3161350DB5BE5AA /* Maybe.swift */; }; - 94F00BBF7C98FF9F7C8A50D09013D5F9 /* RxCollectionViewReactiveArrayDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C9BCC3F17727084979A31BEF7947939 /* RxCollectionViewReactiveArrayDataSource.swift */; }; - 94F295D2FA27DD8400B899BFAE5AB365 /* Pods-Darner-dan-uh-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = A4288CA2B164000A29B4CA6754ED4A47 /* Pods-Darner-dan-uh-dummy.m */; }; - 9592A59DA2AB14603C0A164DE99AE989 /* NSTextStorage+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01D78531DC748E29CAE6A300625FE73A /* NSTextStorage+Rx.swift */; }; - 95A903FF7AB1A1BA9D09D37DF81A8AB0 /* _RXDelegateProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 35CD46DE65AF42A722F77B020C46D90C /* _RXDelegateProxy.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 972752F5D0CB130EB55EB4BCDA161A71 /* Cancelable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43EE4AC30D4D78D61696489C29D9CC3E /* Cancelable.swift */; }; - 99A91523EDA858260DE382471FCD2660 /* ShareReplayScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CA936BEB05C9F8DDCA3F8C09F3FD0D /* ShareReplayScope.swift */; }; - 99CFA1A10B374DEB190C746C8FE56328 /* ObservableType+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5BF571F992C56D9D573ED8DC09C4C60 /* ObservableType+Extensions.swift */; }; - 9A2492FB5AAD077758AA999340BFF32C /* UIPageControl+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 390ADDE880682922C795B8C9F7EF4C6B /* UIPageControl+Rx.swift */; }; - 9B1D8A7798D8A6F518FC9AF9725431D0 /* URLConvertible+URLRequestConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = DED7C8308F5FF721B477BAA89146DBD3 /* URLConvertible+URLRequestConvertible.swift */; }; - 9B36BB2683F3628ECD5960E9619EB19B /* Queue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9755430B399C67DC347AC34EB3CB5BB1 /* Queue.swift */; }; - 9BE1AF91C4974E1FBC4A679C4B913CA3 /* DelaySubscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C7FB4FD7CE785118A94BC728E538524 /* DelaySubscription.swift */; }; - 9BE9B1A29DA997E762CFD07F25605A04 /* UISearchController+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91584B212EE8EEDC31D307A6B76CFEF5 /* UISearchController+Rx.swift */; }; - 9C195E01501DDF1FDAC8088D7B220A39 /* Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2053CBA7F32D1B5DD6A732548723F7CA /* Error.swift */; }; - 9C6D19CA62E67E73FF98774FCEA080A1 /* KVORepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C4466009D7802687DC3BAB221CDD73F /* KVORepresentable.swift */; }; - 9D83CCF8474F4053B033BBF3765F7660 /* _RXDelegateProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = E077EDF056ED4CC7D87B68F795366060 /* _RXDelegateProxy.m */; }; - 9D9106710EAC7C6C7FE9E7EC1BC00C35 /* ObservableConvertibleType+Signal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1591824CD4A57EFF831752B2B7707D77 /* ObservableConvertibleType+Signal.swift */; }; - 9DB91E3234D98F8F474CA1B60A4009EE /* ScheduledItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5798BC6E0D346B973EED8805BD8294C5 /* ScheduledItem.swift */; }; - 9FED70D1E1FBFB80E974E999EF732258 /* RetryPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847E8C3BE479BE92FDDC97E5D40D4DCE /* RetryPolicy.swift */; }; - A25F6B7BE0481113031DF749FE9D40C4 /* RxWKNavigationDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5144D49C296E97677FB28CA7B6A74D08 /* RxWKNavigationDelegateProxy.swift */; }; - A2FA5D4CF29A68D435767AF9C7144879 /* ScheduledItemType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F827C8190D1956882FEDB02BF7DA311 /* ScheduledItemType.swift */; }; - A34D9DA66D7917D23B0D62054478683A /* RxSwift-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = C8CBD89F412EBC0575A328F5B8A71350 /* RxSwift-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; - A3947A2A74E8A0C652E26D61F30358BD /* Bag+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 700A4CD2C06E3944CED95A0F3210EDC2 /* Bag+Rx.swift */; }; - A52C7C7156120DBD02B56E8000856270 /* InvocableScheduledItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E09A0E2396C110A208EC13C7433F660 /* InvocableScheduledItem.swift */; }; - A645856411CD83CC21C7D801272669F5 /* Platform.Darwin.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEB60E16D234FEBD84C815DB4B29B409 /* Platform.Darwin.swift */; }; - A69020C6D8D54C6B9967150C4D12C2F0 /* Producer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90E10AF3A7B96FE0920F8B8DE86C4219 /* Producer.swift */; }; - A738C2A39C0150BBA7EA5EC19B95F03E /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0555E02157B458CA4C5B3AE6D65FCD3F /* CFNetwork.framework */; }; - A93533D0C501E2BF125596DB8C36694D /* HistoricalSchedulerTimeConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFB6810C06A88D9886C197FF72A4BFF6 /* HistoricalSchedulerTimeConverter.swift */; }; - AA95D0BECE2FDCB55E0A59A0C52272FF /* Amb.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33861B0287E2C5260CA418BDE89B675D /* Amb.swift */; }; - AB6C5AFFE7748088FC9101D2A569B275 /* WithLatestFrom.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1FA7686F3834AC433C853E5F4A78990 /* WithLatestFrom.swift */; }; - ABA85887A41495358C83CE3F3030EDEA /* CachedResponseHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43A58125D39C8209160D767B9FCD6715 /* CachedResponseHandler.swift */; }; - AE9CD52D79B9E0598327F6ACA67ABAAB /* Debug.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7EBCC7FF0F228A25D24C5FB31329EB64 /* Debug.swift */; }; - B0528F277050656E75ADE1D065FC37B8 /* KVORepresentable+CoreGraphics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BA20BD3717079A8B70018B2E2B847A4 /* KVORepresentable+CoreGraphics.swift */; }; - B27A654EED61328A617C246F39C7EFD2 /* RxTabBarDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 329C2C237E5807C5D2E690EF5670A8FD /* RxTabBarDelegateProxy.swift */; }; - B31EB36681E88930D309731509146D8F /* RecursiveLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32D297EFE0811B032CE8EA6F153CDF2E /* RecursiveLock.swift */; }; - B47CAD0C912E476435BD8CEEC991DE24 /* Delay.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD70AA8FF2276F495F6B026715273D18 /* Delay.swift */; }; - B4A337004B59DD3D71EA08745DC8D798 /* RxCollectionViewDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 986E10F6FB6A0D91ACBD54436DEE367D /* RxCollectionViewDelegateProxy.swift */; }; - B50761B46B6B0DFA58E3A45431FAFD8E /* UISlider+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = C48DD79407F9BCFED2215FF574C4480E /* UISlider+Rx.swift */; }; - B606120F6D64F423657236A2970B2857 /* RxTableViewReactiveArrayDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 185C3CBCE6CB4F1F71D86AE370EA8EA2 /* RxTableViewReactiveArrayDataSource.swift */; }; - B721D47828DBCCEC8579800F3E1686AE /* CombineLatest.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEA3CBC33CA6668F8AA4B50FF68D5182 /* CombineLatest.swift */; }; - B763C21339C457FF6C9F23FCD847C294 /* RxScrollViewDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = A58C9E012BFF1E7FF4FAF4572C0CA7CD /* RxScrollViewDelegateProxy.swift */; }; - B805454BD4733A2BD5D1E9927781C61C /* NSTextField+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1D59A00FC3C9EAA5DFF54F7800DF5A7 /* NSTextField+Rx.swift */; }; - BEB34BE206AA9228BAE5F057274C096D /* Filter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5DB93213D8F24A4193F7FC23804F47B /* Filter.swift */; }; - C1C5B050B55C15103ABC81769551A283 /* Response.swift in Sources */ = {isa = PBXBuildFile; fileRef = A183A6FC3E9F3E14E10154C6FE034A12 /* Response.swift */; }; - C1F1DB6A9CBDE584D09BA1613AAD4F9D /* Alamofire.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD5B005E3CB1E9CBE5F6C8F98D79819A /* Alamofire.swift */; }; - C1F50C3F1C11D610B8B15650CCD4CBDA /* VirtualTimeScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7EEF27C2DCA3ADEB3B8D204BF95F3CEC /* VirtualTimeScheduler.swift */; }; - C2D5D09CEC440A4621B5CAFB67B3A5B5 /* ItemEvents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13DF7EFF2C06C91C70FBB6FDCE714A0A /* ItemEvents.swift */; }; - C4F1F53A9B315A233D2DE4E41BE36840 /* SubjectType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EEB6ACC4990BC62F16F093FC4BC9F70 /* SubjectType.swift */; }; - C5A36BD3A03ACBCEE7AA512E75543F8F /* DispatchQueueConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7F8070F6E169181CC8FF298703849CA /* DispatchQueueConfiguration.swift */; }; - C5A5AEEF77FA6E9297696D7130306BCF /* RxCollectionViewDataSourcePrefetchingProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14F9E1DCBECDDD03F849344E1F7DEB4B /* RxCollectionViewDataSourcePrefetchingProxy.swift */; }; - C6C99FDE5205C027D87F915E19FF5298 /* SwitchIfEmpty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87A259B0B87DE94E12C68F977565F77E /* SwitchIfEmpty.swift */; }; - C6CFA4D8E44B2ECB867560F11166D847 /* RxTabBarControllerDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = A48757BF4BCF0F643D13CB8D15325E28 /* RxTabBarControllerDelegateProxy.swift */; }; - C6D5A4B4028B2C43380C9FA58BD5C8CA /* Alamofire-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 991D2CD16B3194CA4599C283DBE54B90 /* Alamofire-dummy.m */; }; - C6FD0005BA0122FC924F9A47B3A8F940 /* Reactive.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE852069019561008E4F1D17B2D8A82C /* Reactive.swift */; }; - C71B657F060B00AA92C2FEEC8DEDFDD0 /* PrimitiveSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AB20C0696C90368521BC8C5D30941FF /* PrimitiveSequence.swift */; }; - C77BBB1150A4EEBF948F2E32133719F0 /* RxTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12EC4A82840213156D80A772AC628749 /* RxTarget.swift */; }; - C90141C33122A1AB176932C44BB8CE20 /* GroupedObservable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AE97F55029A327A68BA15B8A7E84BE6 /* GroupedObservable.swift */; }; - C92EE1C8771E4BA17872F7B9BF534787 /* RecursiveLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BBBD32E7904C793C4B7CE8BBD493CF4 /* RecursiveLock.swift */; }; - C9FED92878541212DCD20841DBFA48AF /* RxSearchBarDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841FA2717197F3826D2C1BE1E8A19A1B /* RxSearchBarDelegateProxy.swift */; }; - CAEA4361DA6030D11415FBC4FD4C4DF4 /* RxTableViewDataSourcePrefetchingProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C632BE09D9C554BF44A8323190FEC8C8 /* RxTableViewDataSourcePrefetchingProxy.swift */; }; - CAF399B9B0C071AB9DA54EFAB35FA05D /* Catch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E45254E5CC9E0AC1386E062A11CF266 /* Catch.swift */; }; - CB31EE213D63980611F112CDB77E8194 /* Pods-Darner-dan-uh-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 271BA88AC2355AE18AC1B121E0E92300 /* Pods-Darner-dan-uh-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; - CB7A8E096418E09BFC913E24D0AFB9E6 /* Empty.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1C293648167E9015382D1EED1250993 /* Empty.swift */; }; - CB952FD2F737FE25DC95579065296BB6 /* Driver+Subscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD62DE9F4F21A0A1D91A38E27DADD72 /* Driver+Subscription.swift */; }; - CC084A6E3141CBE88D1B65E7FE890CEC /* Timeout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C64D7DFFFAF12902AD0718F6F2F6C6B /* Timeout.swift */; }; - CDCA48093852C8B844059A9684826F30 /* PriorityQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7A2D3F3FB22FE1D134D6E6DC6CF50CE /* PriorityQueue.swift */; }; - CDED438FA5C4771AAAA8E89F7CC5AC58 /* NSTextView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1A80F5DB2A0494A55847777AEE35124 /* NSTextView+Rx.swift */; }; - CE52DEEB5A518D4E80AAD0B32C44493C /* Completable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AB7D69D293E93ED1C08B79BA59670FF /* Completable.swift */; }; - CE90037BF8D1EF3DCBFBC97E56D2701E /* Platform.Linux.swift in Sources */ = {isa = PBXBuildFile; fileRef = B917E5DBB06B2BDB021DDE3F5FA1C7E2 /* Platform.Linux.swift */; }; - CF8EE3746589F5FF68951DBDE74D8E46 /* Deferred.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7D752C895BA6DE13734367372FBE34D /* Deferred.swift */; }; - D03DF75AFE3BE4990305DBC1DDB869F6 /* UICollectionView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C025AFFED9E62D011484129DF62E696 /* UICollectionView+Rx.swift */; }; - D03F1F02DE8606E6057D57866611BEBF /* MultipartUpload.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD24F9D5D6B34277BF30AFF8F36FF456 /* MultipartUpload.swift */; }; - D14066FAE94E304798E43651E5886D13 /* ParameterEncoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = E00EC1055B4D6FC9311F59964E9DBAFE /* ParameterEncoding.swift */; }; - D15DC3BE7C68691D743B1908ABB91E07 /* NSLayoutConstraint+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3596906DE866446245B777C72B463CA7 /* NSLayoutConstraint+Rx.swift */; }; - D1B3D37592824BF1800AF3C0D8577928 /* RxSwift-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = AB4EF579F5A621FEEEB03F3B4B7DDB7B /* RxSwift-dummy.m */; }; - D2F8250DFD8BF901BBCA0E921AA0A7DF /* RxMutableBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4EDD858C4EEB5E289F8FB564D33194C /* RxMutableBox.swift */; }; - D31FC7FDD450C4CDD633ECBAD27C6221 /* URLEncodedFormEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E5D3D875EA46CC50F03F97C512911F0 /* URLEncodedFormEncoder.swift */; }; - D337BCE2FB7C1D595669844BDD9E53BE /* UISegmentedControl+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1946A1418516CE741E8B311BC7C2E91A /* UISegmentedControl+Rx.swift */; }; - D405FD3A5013F19096331DE1545F50CC /* DefaultIfEmpty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 991AB91BD9AFEC0939936D4D91083DA9 /* DefaultIfEmpty.swift */; }; - D40B9D5116DE9A970BE2AAC71D950B8A /* InfiniteSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39428AAD1A8C28477229F95C566692C /* InfiniteSequence.swift */; }; - D437A93503211D776CC61B0A8A8A71F8 /* DelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9B462D6F9C2C32D5DD9210644F9E967 /* DelegateProxy.swift */; }; - D5EAAFB6FAD77A8F0699345149BA3CBB /* URLRequest+Alamofire.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC4BEA2E92ED8D2F5D72FBE3819F6DCD /* URLRequest+Alamofire.swift */; }; - D64EA6E18B6AC4114BE0CB29B70B7739 /* ControlEvent+Driver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91F209C3C5BD5EA95444DC72928A82C5 /* ControlEvent+Driver.swift */; }; - D83C68850F8A3C76DE97A0551A818F31 /* TextInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68D3944E9EFF58CCE1B9DCAB666EDD71 /* TextInput.swift */; }; - D9BA5B238765E5E2D796D47246F748F3 /* UITabBarItem+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671EDE771550EBC0A957B46405BEA906 /* UITabBarItem+Rx.swift */; }; - DAB7CDCB3C855AA0E80989B69201E957 /* TakeUntil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7468EC0CFAB9F0DAE3E4C9ABD87F9835 /* TakeUntil.swift */; }; - DB2A5396B53CD8A93F0043C66018F9C8 /* AsyncLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = B38ABF51BABC1CD386D2BFB4A0F07773 /* AsyncLock.swift */; }; - DB2D57AF81BF92D637AC95F3582CC085 /* RxPickerViewDataSourceType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4D1A4773C251551DBF3256469BDA716E /* RxPickerViewDataSourceType.swift */; }; - DBC8CDB0774E509631269FFBAA2DAFD9 /* ObserverType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4523C7B556A036033B3A5F949125AFC7 /* ObserverType.swift */; }; - DC2BF73B8DE32079B2A5D3EEB325693C /* Single.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8AF8FDF5A19CA461972C062BFC6A2B4 /* Single.swift */; }; - DC627AFC5B585686898B014184AFCABD /* AuthenticationInterceptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 201FBAFD4A9D9FD6A838B9F963C76795 /* AuthenticationInterceptor.swift */; }; - DE951C89A0E4204747920D821A8CA125 /* ReplaySubject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 247F0BADDB1F0001E7029E0B9B69BEEF /* ReplaySubject.swift */; }; - DEE005A7C80140E09224D958FECE2F5D /* AnyObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A6FB965F9F761670F3AE2F6485D5E11 /* AnyObserver.swift */; }; - DF7BB16D5068614BEC61A6AE56676BCE /* Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CC684A247E2C996A5D7B318E5400CD6 /* Event.swift */; }; - E0913C7ACDEE2FF3F5726843D87F0FB0 /* UIApplication+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FE45E4A160BBBF16808F12971CC5A89 /* UIApplication+Rx.swift */; }; - E2485824224974D4F01A4D528FBF54F8 /* ObservableType+PrimitiveSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BDAE5B5F0CEA445E64668F0AE99F0A0 /* ObservableType+PrimitiveSequence.swift */; }; - E271A581E3E779A7E78C930D9FCC1BB3 /* DistinctUntilChanged.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55D718D09D4BA0E6833E730CA280D373 /* DistinctUntilChanged.swift */; }; - E2960331F72C889C85D4875B200AF289 /* UITableView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87A84A65C3F2568A97179656B9AF632F /* UITableView+Rx.swift */; }; - E3B8690153448DB7BB199D4FB8F1E90F /* SchedulerType+SharedSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D3B3309D720B6FF46FCAA66C89D18E8 /* SchedulerType+SharedSequence.swift */; }; - E4EC22E47F93A0B49658C837EDAC1376 /* RxTextStorageDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F93ED208D338D0391C8DAA1B16D9F1B /* RxTextStorageDelegateProxy.swift */; }; - E586EDD4E5F5DDC0B2010E28ED8A9540 /* ConnectableObservableType.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9906331734777309DFC58F7387FF429 /* ConnectableObservableType.swift */; }; - E6E046A2DA04D941708C043BE6EDBE26 /* ConcurrentDispatchQueueScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 895A56F29AE70279A3FEDF60F962626C /* ConcurrentDispatchQueueScheduler.swift */; }; - E71C2CBDF0E79625EF1058383A2CA403 /* RxCollectionViewDataSourceType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79BE01F296E7734CBB0F06D590545AB6 /* RxCollectionViewDataSourceType.swift */; }; - E760665C0AB19104AAE980C29CAA2F76 /* AddRef.swift in Sources */ = {isa = PBXBuildFile; fileRef = E475D56DD17EEA4776F97F15675B7FC9 /* AddRef.swift */; }; - E86B0E0D913346ACDF5F2D69A0A98833 /* DelegateProxyType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48F9D5B73C10CD49B315100BEE5DA548 /* DelegateProxyType.swift */; }; - E87B7B8EAE2A3B1203CCE091B8994D7A /* AsyncSubject.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0937A0C174A8902E89AECBFF3DC0B0A /* AsyncSubject.swift */; }; - E8CA9D201CCD569771BBA7230B4CE86D /* Range.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF2AB4533884DD0CDF831A515C462271 /* Range.swift */; }; - E94C8A4AC49CBF79C160CDF1456F3268 /* ObserverBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE5C65DE35ECFA7A169D5510D5465E3 /* ObserverBase.swift */; }; - E94D94EF789DCBC511115EBC4F6B85C2 /* SharedSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86C1631C4A90FA9150FA3655A6719B66 /* SharedSequence.swift */; }; - E99871F1698413492981F4D5B83ACA55 /* CompositeDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65E6B5B902603AF8C36756D07E7024DB /* CompositeDisposable.swift */; }; - EB188E609BEFB8A628A4747E9B5803F8 /* RxTextViewDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD6F8038569074A1C5850081F2BCC3C8 /* RxTextViewDelegateProxy.swift */; }; - ECAE23D66E9EDF283A168176231FEDBD /* Observable+Bind.swift in Sources */ = {isa = PBXBuildFile; fileRef = B63E4587F295EA0C56BFB2091E93A0E8 /* Observable+Bind.swift */; }; - ED62834CA901D873E8499CCC8E004F99 /* VirtualTimeConverterType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 429F241033F18A4B1C77E5B96EC83B8B /* VirtualTimeConverterType.swift */; }; - ED906ACD2E9F3C6DEA3A0B373A7A59F7 /* UIProgressView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3731D6B5F5645F219064F326F5DBBC0D /* UIProgressView+Rx.swift */; }; - ED96AC28B148B137544A4B56181F2A8D /* Take.swift in Sources */ = {isa = PBXBuildFile; fileRef = 734FC1CAA915693F4537D08A4A8D8268 /* Take.swift */; }; - EDB338DD059F5447DBCF1289E353B2CB /* UIViewController+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3B5DC9315EC4C7837FEE02A29842F21 /* UIViewController+Rx.swift */; }; - EDC93BD7B9262119AE145E4C7A9D0212 /* Request.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9A8EBE1012F49AF81A9AA577843D1B2 /* Request.swift */; }; - EFB73B383EE0B9D00BCD7CA7D84B3395 /* UIGestureRecognizer+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72FB3EEC19F1F948F81C181D6FBFC668 /* UIGestureRecognizer+Rx.swift */; }; - F03680E55059E367B51764AF73D78877 /* SchedulerServices+Emulation.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2132119D8C2BB8C831F159760E17596 /* SchedulerServices+Emulation.swift */; }; - F0F3224FF592F9BA2A044A2FC2BD4CCD /* Validation.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBF95597E8C41B20BE5BD5A60256886A /* Validation.swift */; }; - F0F7F7EB66C233DD559474AFEA7C10DF /* SharedSequence+Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C6DD10F6A9C17A249C1E425DA10B8AF /* SharedSequence+Operators.swift */; }; - F18D13A96958391F1302D458E5EDF2FA /* OperationQueueScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E97525EE22ADCF0B33275E0AD936D9 /* OperationQueueScheduler.swift */; }; - F36EF88B9429864E9ACC6CADC35ACFFF /* InvocableType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E352BDFF2115C51292AB8586490ED568 /* InvocableType.swift */; }; - F3FB4FF17D04C088A943E25CA2CE4C7D /* HistoricalScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77BAE41DE8F15764B25F01E46AFBF15E /* HistoricalScheduler.swift */; }; - F4541139B83E4CE559A87E1FD2484323 /* _RXKVOObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = C78763BE0913F286921ABF4148DBD215 /* _RXKVOObserver.m */; }; - F45A4698016A78D7C3C0E1A8CC28CD2B /* CompactMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = AABC376B1A706EB2C475BA1F3EC6C4B7 /* CompactMap.swift */; }; - F5643E260EB37A5825F38AC065EF3CE6 /* Date+Dispatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAE78A5532DB23CBCA9FCC6ECE84C1ED /* Date+Dispatch.swift */; }; - F65B6B6DC462EA29784F3829E27F3786 /* Scan.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1201972BFD824158C893EEEB86C162B4 /* Scan.swift */; }; - F6B16DC8CADA07287C6A372AC8AD787C /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 169AAA422E46B126BBAD577E53742277 /* Foundation.framework */; }; - F70EF854395CDE981A8336E4FF0310FE /* URLSessionConfiguration+Alamofire.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB3D9A1711AA366FD5F09FEA00DE390C /* URLSessionConfiguration+Alamofire.swift */; }; - F88602DEA5D139BDFF12CEDD838BE081 /* UILabel+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = A58CA2588C08F08FF6CAC6A6FBFB2699 /* UILabel+Rx.swift */; }; - FA9D389454C2CBABD95D657BCE7C3595 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 169AAA422E46B126BBAD577E53742277 /* Foundation.framework */; }; - FB063097DA98E40D353B2ABFD8407226 /* RxSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4F5CAC3DFDC297B2C56D647BF7C7813 /* RxSwift.framework */; }; - FB1F62B2A744B23A349CF8877CF2A09B /* RxPickerViewAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91EACAB565BF2BFEA11F77968AC8DE14 /* RxPickerViewAdapter.swift */; }; - FB5A91DB25CAB3F3830F6BC5A7E88648 /* RxRelay-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = EFE1CB5CD9AB2B1456DF66F04802FB88 /* RxRelay-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; - FC5FC3AD0EDCC97604F56C68B0D5029A /* AsSingle.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBD157BE8BD65CAD1F1FD75AEB41A744 /* AsSingle.swift */; }; - FCB07678FF31509D157300B7DC1240D6 /* KeyPathBinder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78F0A6654B98B62DC64FA1664AD7FACF /* KeyPathBinder.swift */; }; - FD121E214251E5B388161FA787E9399C /* NSObject+Rx+KVORepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBAF82A3A34CD99B5EDF793E626273EE /* NSObject+Rx+KVORepresentable.swift */; }; - FD13BDBEB267F9CB352C4898F0A9ADAF /* Switch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0013B094868C3362596DB752534FA46D /* Switch.swift */; }; - FD71C12495B3C977B34C695E29BE6487 /* ObservableType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46DD6E7421FD83F1CBB2CE3D863ECDC6 /* ObservableType.swift */; }; - FDEA0FDF7F44B7194D7B2C7A99B8F2E5 /* AsMaybe.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0163143A6F2D322EA65C9B165D5E219 /* AsMaybe.swift */; }; - FE38BA94F6CC36847692BD46088FD1E0 /* Materialize.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02BD2CD95E38D6D07BFF1A50CEC190D6 /* Materialize.swift */; }; + 0016AA0031565901037DDB550FF54651 /* Lock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5620DEC10EDB32C938A7BCA68FC4785D /* Lock.swift */; }; + 00C19614038FA2FB5DE63D615E4AF4B9 /* ObservableType+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D60527BC85D168C986AD2CFF1D51998 /* ObservableType+Extensions.swift */; }; + 00C4123FD9546F715751A4FCCD0DC2DF /* HistoricalScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C976161CEA8E0CD52FB77B418D4EDA1 /* HistoricalScheduler.swift */; }; + 00FA1801533D853DDBCE33A57D28D648 /* PublishRelay+Signal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7A5C3E41BA9D9DADDCD330F668DDF2C /* PublishRelay+Signal.swift */; }; + 0108B6FF9CADAB6BC4B784020F3EECFB /* ObservableConvertibleType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 296C69A8DA05E42FC09D7342DEA5E30D /* ObservableConvertibleType.swift */; }; + 013BAC24F7AC722E59517CB110A9E685 /* HTTPMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCAB5D7A477412E48B74F60F519DC73F /* HTTPMethod.swift */; }; + 01483F7977CD82C2E9DD58015E2A0176 /* DisposeBag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2550C023355B7965233A026416E78B0E /* DisposeBag.swift */; }; + 022550CAA9C8BDAAAFA7AE5051910CF7 /* Enumerated.swift in Sources */ = {isa = PBXBuildFile; fileRef = B15981EDF03C1DC3630AEB39AB9743D4 /* Enumerated.swift */; }; + 029771921593A90D3A2120AAF9B8480E /* First.swift in Sources */ = {isa = PBXBuildFile; fileRef = C98B5E2E7BE8BD9F769092DB3824B607 /* First.swift */; }; + 02C64A705AFBB72766D93EC1EF5CD60C /* UIScrollView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5CA30B727DEEFA619FD1BBCFB85F1C /* UIScrollView+Rx.swift */; }; + 02CC843A3A5A9267FAD5C95335914738 /* RLMUpdateResult.h in Headers */ = {isa = PBXBuildFile; fileRef = FEF1973B4E9C40CAAAB341CD3C57C779 /* RLMUpdateResult.h */; }; + 03A244E509AF9D417267A56CCFFCB618 /* RealmSwift-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 0A69D6A299ACFC1ACBA8B6D05065F9B0 /* RealmSwift-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 04291E11FB888F5E49E3DE64AA4FABEA /* BehaviorSubject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07EDFC981426B815ACDAA00D3F9F3621 /* BehaviorSubject.swift */; }; + 042C3858E9EC93DECE415071DE0FB0EC /* PrimitiveSequence+Zip+arity.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA76328C537A503C1B77311D0A2C3533 /* PrimitiveSequence+Zip+arity.swift */; }; + 04BF7123DC74735A133F921FA96DD396 /* Deferred.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74979024C8AA2EBCEA8080A78F40EEBF /* Deferred.swift */; }; + 0525A9617675846B3F73BE5FB01EC5BB /* SwitchIfEmpty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36BF8A2B8D6FDF8C2D4039E82ED313B0 /* SwitchIfEmpty.swift */; }; + 058D11863C2D23349FCB3B416FC906CA /* RLMArray.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 2792D1140DA9A6D5A0AE6C7D26CE34DE /* RLMArray.h */; }; + 05A30A07F8C117BD7C39CA6B30467926 /* RLMConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = BA487887F86C2E5E0C2C260131CD673E /* RLMConstants.h */; }; + 05AB3D293B53F3DD1CF4079C346CC4DC /* Bag+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3D619D046F8DE72E051111E696902B4 /* Bag+Rx.swift */; }; + 0603EE49571AF2F3E368BBED1EC7EA03 /* shared_realm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4FA07826EC4D168DA6EC97F9164EA43F /* shared_realm.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 060971B9618A74DBF249CFC67C837936 /* ScheduledDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23131B8059FE945B73FC34E46F907CD3 /* ScheduledDisposable.swift */; }; + 06364C498350A28E887B7AEAADF536DA /* RLMMongoClient.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = A59FC8CE00F882551C57698AA53BD31E /* RLMMongoClient.h */; }; + 06504FFE7AB5C57B2E1626C35E42023A /* ControlEvent+Signal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 784FD3E1244F1A96A68DBAACA9AACFED /* ControlEvent+Signal.swift */; }; + 073D5880E07C42312556418DF3AE7DCB /* Range.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91D0991D750AE18A29982329B999FEDF /* Range.swift */; }; + 079ACFF0C3235A0036F810A41748F4E5 /* RLMObjectSchema_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = D53FF47C70573D21E73A4729008A809E /* RLMObjectSchema_Private.h */; }; + 079C94706B1DD67CBBBEAE3E93D3A68A /* NSError+RLMSync.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = EE3FF4B388652B33DDD06D2496327330 /* NSError+RLMSync.h */; }; + 07D48815D96656AFEDF8BF96FAEC5072 /* RetryWhen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97432F3721A1295916E9EE9A63DF61E6 /* RetryWhen.swift */; }; + 07DC2E90E5A497D6D74DAC6DEFA59184 /* RLMApp.mm in Sources */ = {isa = PBXBuildFile; fileRef = AA3127E6EA50E54BE683A4640BA3B1B5 /* RLMApp.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 08C80374C02F106D2071840C9FD56F52 /* HistoricalSchedulerTimeConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93E8A674D112A59F350E4FA5585AB904 /* HistoricalSchedulerTimeConverter.swift */; }; + 0954FFE9B7C7DE29B6333DB198731A2F /* Decimal128.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56071D6A7FAAD47EDEE69ABCC81232D0 /* Decimal128.swift */; }; + 0A15F6D793421163A92E18ED9E911F87 /* Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = F350DB4C798D0F260C3AE1891ECEEAF6 /* Logging.swift */; }; + 0A1849775CF90D514963187D3A771CF8 /* Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC3611FA4C931ADB12C3874BD2CF9CA1 /* Combine.swift */; }; + 0A42BD548A8D5A0800D7CDD82B41EFF0 /* UINavigationItem+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = B55A44F27CEFEDAA349EA939F261EBAB /* UINavigationItem+Rx.swift */; }; + 0A900DF17E3B64F08AF673E9A0DDD697 /* OperationQueue+Alamofire.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B2E877567298339EF627B1FF714AE0C /* OperationQueue+Alamofire.swift */; }; + 0AA03F782CE96EA724D4508E7312DDBB /* Do.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7018E4C3E8A75A113B688D25BC4EAE63 /* Do.swift */; }; + 0AA0F6F5C08A1CF24E8F821530A80B35 /* Platform.Darwin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42BC5BAEE68B463D825B57F887FED7E2 /* Platform.Darwin.swift */; }; + 0C2AEEA5C30032AF2F9EC02C0128ED13 /* ControlEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C970CE56C0F1DBB25C6F1EF915C69BA7 /* ControlEvent.swift */; }; + 0C8541A37D210B0733A638DA526922A9 /* BinaryDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7365074ECE61B11E251379CA978A43A5 /* BinaryDisposable.swift */; }; + 0CE4DB3675E51900B206B8EF3A222AF6 /* Empty.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCB6E9B1FB99D7F09E19DB476EDAE289 /* Empty.swift */; }; + 0D33FDF6B374AD0343214C16D30DDCDD /* Take.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A45083FC7449764AF1103A0342E595 /* Take.swift */; }; + 0E385F3601A33770B0F4FC24D17CC469 /* DelaySubscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 006BF5370268B8E8C77AC37824764B9A /* DelaySubscription.swift */; }; + 0F5C8237D37574BDF4B202D4C54FD84A /* RLMBSON.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2EC0428FE529F2A45EE29C2AAD2A467C /* RLMBSON.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 0FBB33BA94590A8B92E6C7CECE0C598E /* RLMAPIKeyAuth.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 02AC92A155B36A82731B0043B39919A6 /* RLMAPIKeyAuth.h */; }; + 0FEC9640238E07A55D59D17C435A5403 /* RLMPushClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 72842ABA9A87A415D9DA5339DCC9B4BD /* RLMPushClient.h */; }; + 1208E81DA8B532D0646D627B50290EB6 /* AFError.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5D1E68D8A1529F9E5FE1179FF21A6A8 /* AFError.swift */; }; + 12D1D8022F0ADA477ACEEAFCAC837CC7 /* Debounce.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13116BBDD71E1181921DE495E7CDA6BC /* Debounce.swift */; }; + 12F2C75009C7EA2AC378A96FC5A0F7B5 /* RLMBSON.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 0AD4B936BBEA39E12AF6795CED6E9EBA /* RLMBSON.h */; }; + 132A24458581E09588803195819CE5BD /* RLMOptionalBase.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = ACC8191ACD24F00F9C2FE8AFEBFFE08B /* RLMOptionalBase.h */; }; + 13500A001014B83E39A6F69782E84BE3 /* DispatchQueue+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99D459801D0303FB7E4BE5D22AD2AB46 /* DispatchQueue+Extensions.swift */; }; + 13E9FFB9979FC3330603A9F299BD7233 /* RLMSyncUtil_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = C3B7CA57C3CC37B2B5613266C1C279A1 /* RLMSyncUtil_Private.h */; }; + 144B84C01342DD588EE98169B133057B /* NSView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BE4CA9CBC1AD20B27FCF3C637CEC001 /* NSView+Rx.swift */; }; + 1510FD50EA8543B9CEA250B66CFF6D01 /* RealmConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F68B8830F1AF80F4EA87E62B55CD11F /* RealmConfiguration.swift */; }; + 15D0D8EE39393B4628502414BD95C248 /* NSObject+Rx+RawRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9C21DE52F2543B4CBA30DFA7D153125 /* NSObject+Rx+RawRepresentable.swift */; }; + 1606DD80E17C3C3F5EF57010FF2F2283 /* RLMSwiftSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = E8A86E54BF1F17E2E4F94C724E812FF5 /* RLMSwiftSupport.m */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 16F6617A19B669D4EA139CE3BCEDDD09 /* list.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6781794A3C328F78F4B8FD5954B94C05 /* list.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 1710FFF89E963E5DC286A412749506A0 /* RLMObjectBase_Dynamic.h in Headers */ = {isa = PBXBuildFile; fileRef = 66EDB9DF199CC9BF81C564719B0E75AC /* RLMObjectBase_Dynamic.h */; }; + 1751F4D5E808044F5256F9D215C05B55 /* RLMRealmConfiguration.mm in Sources */ = {isa = PBXBuildFile; fileRef = B3ECE590EC23040201BA4796C26E4E8F /* RLMRealmConfiguration.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 178044E8590E008952687280FAC7A3B7 /* RLMMongoCollection.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B667C049F3C637F0B9FBA40721F2DCA /* RLMMongoCollection.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 17B9CEBBD5764D362F71128009E4469A /* RxCocoa-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = EB9D165744F522C3327959949201497A /* RxCocoa-dummy.m */; }; + 18647A26267C25CCA0A69980F0361B1C /* RLMAPIKeyAuth.mm in Sources */ = {isa = PBXBuildFile; fileRef = C9F7414E32FE518A8A46C0FEA75BF241 /* RLMAPIKeyAuth.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 18947EB8E832B0DE78FDFFA72FC91E82 /* LockOwnerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC9BCB20DF73819810C2E781C03CA3F5 /* LockOwnerType.swift */; }; + 18E51599DD624389FA38167F927EBDBD /* RxSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4524CEDB98A45F635C925EEFC4AC4D3A /* RxSwift.framework */; }; + 1923AA0E1C547281C5310C62475BB01D /* Buffer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A40596A661F48EEFADF158E97613659 /* Buffer.swift */; }; + 19D605A3233499828FB6B790869F3E9C /* NetworkReachabilityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C21D1AD327A53F52AF328CF9FE041331 /* NetworkReachabilityManager.swift */; }; + 19E834C227A83A88B934BAC1D912DACF /* RLMArray.mm in Sources */ = {isa = PBXBuildFile; fileRef = 35B19D09D0DB2E94A7249C68294BD24E /* RLMArray.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 1B054049CA45D1D34ADD6FCD32E93A14 /* RLMObject_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 57D26DE88762BD941DD60CB00B72DA3D /* RLMObject_Private.h */; }; + 1B77E002CB8E1A101F7126393905D01F /* RxSwift-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 202EAEE640EB38B4F0DFDFD11149CDB4 /* RxSwift-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1CDC24596F1E0A53B36850A1B64B3F34 /* Timer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C493112951F78B37A5FADF7CD6C5ADE6 /* Timer.swift */; }; + 1D9700FF1D0B3A8088CAD38D4A17C0B8 /* RLMRealmConfiguration+Sync.h in Headers */ = {isa = PBXBuildFile; fileRef = 24BE49CFC9CEDC6E3FB1D1D9519FFB6D /* RLMRealmConfiguration+Sync.h */; }; + 1E4EEDD5D7E13356500F9A828204E08D /* RxRelay-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = C2A30AA03471E53D83530069F50267BB /* RxRelay-dummy.m */; }; + 1E6693A5E343846D3A8D19D736658252 /* RLMListBase.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 1C8B3A7FA064FA49FA28D62F6971AD96 /* RLMListBase.h */; }; + 1E88822153E6359EF32E90F306FB9A3B /* RLMAccessor.mm in Sources */ = {isa = PBXBuildFile; fileRef = D03BC09ABD830E4801045FC998EF817E /* RLMAccessor.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 1F6B55D049CA4A0F17091F158365273E /* SharedSequence+Operators+arity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E291AE3C1521D154766FC3F863C0556 /* SharedSequence+Operators+arity.swift */; }; + 20B5E5B3607D6CFBBD6F058031FA2090 /* RLMObjectId.h in Headers */ = {isa = PBXBuildFile; fileRef = 48E379072BB61DABCB5FDA0E8A8E8EB9 /* RLMObjectId.h */; }; + 20F284C3211D8E1E1BF87C624BDA657E /* RLMResults.h in Headers */ = {isa = PBXBuildFile; fileRef = BE07BE828DE8E46170E7B5BA08E44997 /* RLMResults.h */; }; + 212EDC48B68107BEA9247F3464CE696E /* StringEncoding+Alamofire.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DB882D96AE746E55CFCDEEA459DA375 /* StringEncoding+Alamofire.swift */; }; + 218C14EAE5AA31C30314AE0289B732A0 /* Protected.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45A889D4629D068E1484C1D3DF16D952 /* Protected.swift */; }; + 23198C37125F7D48363439FDED535895 /* RLMEmbeddedObject.mm in Sources */ = {isa = PBXBuildFile; fileRef = 71A6EDA338F7DA1AA89C3FAF02FBB03B /* RLMEmbeddedObject.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 23A4EF746AB64504DEB5EFDBA5450492 /* RxCocoa-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B83B53F912C1DDF4F1CDD642DFB2F3D /* RxCocoa-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 23F3E10A4DBB9834978661796429B354 /* network_reachability_observer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9C10C065206C7FD92976DAF5D1A6E328 /* network_reachability_observer.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 249F7A7872239AF311B195CC27BC3051 /* ObserverBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 355631D0FA9773D3CBAD76E466F848DE /* ObserverBase.swift */; }; + 2533166320ACEE9728B4F16958FC90F8 /* UISearchBar+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29043CE1FADE4EECB264248CA6136275 /* UISearchBar+Rx.swift */; }; + 2550B408EF306E05ED36C6AAB6837BF1 /* ControlProperty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 723F15F9375F2B593537ECFA203122C1 /* ControlProperty.swift */; }; + 2592EAA1FF58939571C426109D21E5A5 /* RefCountDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7386464B12C9B9D5D45B6DB16A6EE443 /* RefCountDisposable.swift */; }; + 262B533DDE9925F5ADFEC7EFD95697FA /* placeholder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3F3E96D01CCFEFD7A748E4B5C5D839D8 /* placeholder.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 266D487710C4475F9E508F2BECE80CD2 /* transact_log_handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6DBD72C6356BDA4CBF5FFA393F9D6B9E /* transact_log_handler.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 27C1FD437952EC44DA722CA3E38D4F39 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3C3AF2E791EE67E3DF385C1781D769A1 /* Foundation.framework */; }; + 27E37AE40D404DFA7A4B0FE122789204 /* Driver.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB985A53F39481FA23B528D7486A0188 /* Driver.swift */; }; + 27E59A11A2743B0595CDE3A08675EAE1 /* DispatchQueue+Alamofire.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA9C81E6BB6A6F3847C6095D3138A200 /* DispatchQueue+Alamofire.swift */; }; + 280BF82393448B0CD8049ED6F681169D /* BooleanDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5025DCDB5381F0BAF26FFB5E92DAB4E /* BooleanDisposable.swift */; }; + 28FEE3F61E1275C9E2E82FE7A97915D5 /* ObservableConvertibleType+Driver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54304BCBA467BC5A9BADBDEAAEC497B7 /* ObservableConvertibleType+Driver.swift */; }; + 29609EB2017138C87F03CAD2376A8DF6 /* SubscriptionDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3CCF36EE801B8EF56E263EAD2E92A08 /* SubscriptionDisposable.swift */; }; + 299DC3F31727763F334045CDF53A4188 /* DefaultIfEmpty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FBE3C34D8D3B16941AB50B4CC5848B1 /* DefaultIfEmpty.swift */; }; + 2A6BCB44D6A52ED857FCB3857A1611DE /* RLMObjectBase.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 6924294AB88A4FA6537B15BA0B6F297D /* RLMObjectBase.h */; }; + 2A8FD3A693CCE3F0B20522C1DD4F82B3 /* RxCocoa.h in Headers */ = {isa = PBXBuildFile; fileRef = 1047C1ADAC0CEC50E0BD02F90744FF8F /* RxCocoa.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2C4BE39B7FBF43196B82140493093D41 /* RLMMongoClient.h in Headers */ = {isa = PBXBuildFile; fileRef = A59FC8CE00F882551C57698AA53BD31E /* RLMMongoClient.h */; }; + 2D476996F278959C1EBDEC64F4E904D8 /* Timeout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B5470E42687026564FABF072383156A /* Timeout.swift */; }; + 2D4A41728C9E40252BFA4AFD7D5C4D5B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3C3AF2E791EE67E3DF385C1781D769A1 /* Foundation.framework */; }; + 2D544742288315C957F9C5AF2EB78663 /* Deprecated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E9AA4AE06C1A4752179DC22A2DA027C /* Deprecated.swift */; }; + 2D58DDCB6077DE2D2A5FF49C89C88FF0 /* Zip+arity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 645DF232325867ABB538CC52A0A2A677 /* Zip+arity.swift */; }; + 2E92A4050BE7F15D17D28B27CD7CDE8A /* system_configuration.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 620007ED9E8C608CA8206880D8995253 /* system_configuration.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 2EF232DF8C8C17CF8E9EF17A38284F07 /* Reactive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81A4B883DE20BA52DBECF0CE87117416 /* Reactive.swift */; }; + 2F2F1DFB33A8277A4606E3255191AC19 /* RLMSchema.h in Headers */ = {isa = PBXBuildFile; fileRef = D1E961D09AA076899B1338AB10A23759 /* RLMSchema.h */; }; + 2F496C7787E50D612CE4F988FE7AAE5E /* Dematerialize.swift in Sources */ = {isa = PBXBuildFile; fileRef = 462749C51F01BD979C5B7601F7EDCB60 /* Dematerialize.swift */; }; + 2F865C3E487EBDF4F476813284BB5F81 /* RLMPlatform.h in Headers */ = {isa = PBXBuildFile; fileRef = F8216BA641FC62DCBDFC9C0268B56873 /* RLMPlatform.h */; }; + 2FCE7C367D4CD8660C8A29D02B3FA7A7 /* RLMObjectSchema.mm in Sources */ = {isa = PBXBuildFile; fileRef = BE62C08E4BA287B456905415665C63B3 /* RLMObjectSchema.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 303E0C92168D1B45A96EB56FA114AAB4 /* RxCollectionViewDataSourceProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 673B530043EE97D068D4854830529D8F /* RxCollectionViewDataSourceProxy.swift */; }; + 3052C14D4057BD71F1B253466C07C554 /* RLMSyncUtil_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = C3B7CA57C3CC37B2B5613266C1C279A1 /* RLMSyncUtil_Private.h */; }; + 30EB41114FFEBF43058708FDD2A1FDED /* RLMObject.mm in Sources */ = {isa = PBXBuildFile; fileRef = A72D1251AA1B04F052725F5E84FA7BF6 /* RLMObject.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 31E4B1E07CDE81B5A2A2B108976159D0 /* PrimitiveSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97C0C3568B5022C6BB1A43D26687A849 /* PrimitiveSequence.swift */; }; + 3289A76CF193BFE03721AF5CFF61BDDF /* RxAlamofire-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 8BD9325336D6BFDFCEDBD5E891C35801 /* RxAlamofire-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 330DB3CAEB0F54399D764FC809B6C5ED /* UIStepper+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = AC703B02DE4D059FEC238525C3FDB6E5 /* UIStepper+Rx.swift */; }; + 33390E01D7EB4E3564907513AD16D565 /* ScheduledItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65A1C3236E061F091E6E42FC717B46DB /* ScheduledItem.swift */; }; + 33A759C846F948BF190307977D280B6F /* RLMCollection_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 880083C6631CCDD9FCFB3D3742A37D59 /* RLMCollection_Private.h */; }; + 346E93481655EF0192EAB2E4F1C6060B /* RLMApp.h in Headers */ = {isa = PBXBuildFile; fileRef = DA3598979CE772D50E44DD120ED96A26 /* RLMApp.h */; }; + 3492924BB6DC68CCAED4C1142E7739A3 /* RxCocoa.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B27C2C39ABC4A9CFFDF48A71687A545 /* RxCocoa.swift */; }; + 34A809F2EFE03CCD28E205805C749FE4 /* object_changeset.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E6B16B29794E989049ED056119609AD2 /* object_changeset.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 352FC9B2FA639258CB77E7C0FB5F6840 /* RxPickerViewDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FCF57E40DC0EEE76170EA7566F7A93D /* RxPickerViewDelegateProxy.swift */; }; + 35C06A684501F663EE30584A1C521A63 /* Date+Dispatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4BA811ABA1EEBC0D4084E3469D31939 /* Date+Dispatch.swift */; }; + 360B866D93BDDC8884DA633371E80B22 /* RLMFindOneAndModifyOptions.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = C0233CB52B3C3FD4DF91769E2264AF71 /* RLMFindOneAndModifyOptions.h */; }; + 362CBF15761DA90CE183B818C1F4CBE2 /* RLMUser.h in Headers */ = {isa = PBXBuildFile; fileRef = A653A9A03EC868233496EB1538F067D2 /* RLMUser.h */; }; + 3655E896EC942A91908C3E6C2FF44830 /* object_store.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 123A19C0627E923D071BEE6553C1E5FA /* object_store.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 36AD49B08BDA824B92108187E7637D4B /* RLMDecimal128.h in Headers */ = {isa = PBXBuildFile; fileRef = 597BC46EC61C37E53FF2B9A3DFDD76CC /* RLMDecimal128.h */; }; + 36E7A944CC80CA15996E3B3BCDA9A334 /* SingleAssignmentDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0B9E37063F2A18ADE927C78193C3C17 /* SingleAssignmentDisposable.swift */; }; + 37F572B1D4C35D5DE1AE90659641C34F /* UIAlertAction+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCE49DA992BF8ABA11EE69E00DB44AED /* UIAlertAction+Rx.swift */; }; + 381FF05F8B4F611EE9C2FDBE4457BB89 /* SessionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAE53A746F752DD65ED349FBDF528401 /* SessionDelegate.swift */; }; + 38970A50544688DDD6557737769CE86C /* UIRefreshControl+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = F66800F860EEF91C7FD4EE6DAF26617E /* UIRefreshControl+Rx.swift */; }; + 38AA5C81B840EB73613085FA590D387A /* DispatchQueueConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5346001597BAFBB0875B82142214C534 /* DispatchQueueConfiguration.swift */; }; + 391AE2E1933A03748D21A9711DE5E32A /* RLMOptionalBase.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = ACC8191ACD24F00F9C2FE8AFEBFFE08B /* RLMOptionalBase.h */; }; + 39BEC8314726206A28B069A3A9908EB8 /* RLMArray_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 6008D806F7FE06FEE6315C1A586CBE38 /* RLMArray_Private.h */; }; + 3A147160AC0E2C5D9235AB146A408B05 /* ConcurrentDispatchQueueScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6155D234BBD32E52148B0991435CB0E5 /* ConcurrentDispatchQueueScheduler.swift */; }; + 3B08FAAEA2A8318BFD49EF5D29C8B4D5 /* RLMRealmConfiguration_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 78BD15A38C1C2292CA446D8971F118FE /* RLMRealmConfiguration_Private.h */; }; + 3B16B1FA9F291577F7A38D26AA4072E3 /* results_notifier.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4ADCB6FD187409DE26C251F11D5BB1BC /* results_notifier.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 3B6D2A9BD94A099667066E9733925D55 /* GroupBy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A784BB19543BE7255AA56FA7E88E1E0 /* GroupBy.swift */; }; + 3B7DC5D2B66F25F12674A8DEF1F39D56 /* ShareReplayScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F38E046E0CD2CB36147067CD98085F7 /* ShareReplayScope.swift */; }; + 3B8507630F8F598F244F3E99B25E1ECF /* RLMSyncSession.h in Headers */ = {isa = PBXBuildFile; fileRef = 99D287487AD77AFB75AE28B736B355DE /* RLMSyncSession.h */; }; + 3BA050EA7B1B3936903B9CF1C69F9A58 /* CompactMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31099800731F7C7C9E93FCD519007B12 /* CompactMap.swift */; }; + 3BAC7D2129E214B646F9726B82ACBCBD /* external_commit_helper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0A113A1381D58B977ABC03AF0C169267 /* external_commit_helper.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 3BC7E8B18CC01924EA304D1E351289CA /* Disposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E3D87CB1399F7F29B712144448C62F /* Disposable.swift */; }; + 3BE1B2274ADA3803F49BF1C18AC27C1D /* RLMCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = 339215A49D0EE00F18DAD73C85C8CB04 /* RLMCollection.h */; }; + 3C26765F8D546F45BD5742BA408E4AC9 /* RLMSyncConfiguration_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = E5A7027385985B7AE9F3DCD243487913 /* RLMSyncConfiguration_Private.h */; }; + 3DF06796726197AEE928AEE9C4B0510A /* RxSearchControllerDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = A06041313ED286E457B40CA0D4F4555E /* RxSearchControllerDelegateProxy.swift */; }; + 3E3E4FA86DBC2FF9B83337344365DED6 /* TakeWhile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68C58BEBFF4071BC2F983B1A9DCAFED4 /* TakeWhile.swift */; }; + 3E3E80C55D3CA6345AEC7BC6612870A8 /* RLMSchema_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 7FEB4D9BA45A0D280A2E12721EDDE69A /* RLMSchema_Private.h */; }; + 3E44A8350E62AA3BD996582DCEBB231D /* RLMRealmConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 30B878398E136A1052ECEC59EB9A252D /* RLMRealmConfiguration.h */; }; + 3E5888DBBB86DD9A7DB40B66D5D3F6C4 /* InvocableType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57DDCE1EB82077DFA8196D502BE48F31 /* InvocableType.swift */; }; + 3E7E4A485F70C759DBC3CF975C4FEA27 /* NSSlider+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25160B7A5A95101435E2C635A22B4B66 /* NSSlider+Rx.swift */; }; + 3EABFE825C3FFAF030663555D2C8080F /* UIDatePicker+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A46F5C2B8DA96C883B9042D339476E0 /* UIDatePicker+Rx.swift */; }; + 3FAABBFB4027D2DCA706441B19BDADC6 /* RLMNetworkTransport.h in Headers */ = {isa = PBXBuildFile; fileRef = 888D23E446A07C3A3365606FF924FBDA /* RLMNetworkTransport.h */; }; + 4007D6404DFD7B75ABC694A2C5169D54 /* Migration.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE7B05FF864BAFF2C284FC3444530D77 /* Migration.swift */; }; + 425BB7C9815A5326C554A139D99522B0 /* AnonymousDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD289ADC86E68CB5843E0F3E137F584F /* AnonymousDisposable.swift */; }; + 439197DD2AAEE0595B8DA4474C4595CA /* BehaviorRelay+Driver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17B9A7F92B5A3E3A3F255E74F08E50FA /* BehaviorRelay+Driver.swift */; }; + 44B0BF2665B93BA05D05FBE47BEF7B1B /* NSButton+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5119D72B27B8C09312A82E4774AB6C96 /* NSButton+Rx.swift */; }; + 44B27CAB9BD2757B9E25BDA500D280C5 /* RLMBSON.h in Headers */ = {isa = PBXBuildFile; fileRef = 0AD4B936BBEA39E12AF6795CED6E9EBA /* RLMBSON.h */; }; + 44B6F5708A1CE9EE9BEB29866102A469 /* RLMFindOptions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 29622D1F2C8710735FC606C6C7AB068C /* RLMFindOptions.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 45AFB5D51C5929C8AB5858D694572F91 /* RxCocoaRuntime.h in Headers */ = {isa = PBXBuildFile; fileRef = 83DE5521B45742BFD64A13767CBCF9B6 /* RxCocoaRuntime.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 45B8CC1C61E7A0BB28CFA8CE7C12FEBC /* MultipartFormData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24A78EE46C9AB6747F7EAE6E3FDA5DD3 /* MultipartFormData.swift */; }; + 46B81D9973FAC783A65A54B616A846C5 /* Throttle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3735D6A2DD9E0153CCC36C2C9EB50C64 /* Throttle.swift */; }; + 476D5F33E25386C60D6BD75C4FA97C67 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3C3AF2E791EE67E3DF385C1781D769A1 /* Foundation.framework */; }; + 478ECC8504F31C605CF07FBC245A7CFF /* Repeat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 886B2C07DFF2C711F399CC43936EAAE6 /* Repeat.swift */; }; + 47FDBBBD2704901588C3A7C56BBC502D /* ServerTrustEvaluation.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9CCD49060C94F7804A9AC7735C7092F /* ServerTrustEvaluation.swift */; }; + 484F15D31F05819E5E3FC3127405B114 /* async_open_task.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E396837EA8B140BEE2C9712CA5D7C855 /* async_open_task.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 48D9CD209B48FA979CE03D682AE1EFDB /* Amb.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21346E0C05D36D3AD36B91ACB9011DD0 /* Amb.swift */; }; + 4955084D6408D4EB955FB42512C45E7E /* AnyObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = E40B4BC9B3ADB2F167F2CD1BADA00C3B /* AnyObserver.swift */; }; + 49A989318D26BD0E6FD80A91B8F1486C /* RLMNetworkTransport.mm in Sources */ = {isa = PBXBuildFile; fileRef = EB4E75C2A8E07889C7E2FF8D4BF35FD9 /* RLMNetworkTransport.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 4A7BE4972B1BB13FEE90F5D6561C8A68 /* Optional.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0414807C36F0D262CF9B76EFEB7C975B /* Optional.swift */; }; + 4ACE3228A19503457AB5531F4E7F6584 /* RLMObjectBase_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 37D024D0F04AAD55C5660DD29517DE6C /* RLMObjectBase_Private.h */; }; + 4AEC050FA7D5ED52FDA9DF50EA3560DF /* ParameterEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DC72A276813FE5860E1E696B9AB591D /* ParameterEncoder.swift */; }; + 4C7CA14C1636AFACC3B4DC7F57A8CB4F /* RecursiveScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D59A9F196D2018A996B8B5D4092D628 /* RecursiveScheduler.swift */; }; + 4CBE7E174AF7FEE6949C6B5C18CA86F9 /* Delay.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7B4151FE9541C0467D4D77981FA35F1 /* Delay.swift */; }; + 4DAEB64861955FE51DC5DFD39B2A1C1D /* RxTableViewDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18421398E99489371ED0FFD97473558 /* RxTableViewDelegateProxy.swift */; }; + 4E2397162787DDCC0EB80D8B41B4015F /* Platform.Linux.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF9A0FF08CFBC930B36000A057A774A9 /* Platform.Linux.swift */; }; + 4E72EBF6BB344291A468CC1F94F2C618 /* SwiftSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = C10DC21EBAD81BA7D22A5EA5F096D256 /* SwiftSupport.swift */; }; + 4EE685A7178F6ABC51658C07200BDF40 /* RLMThreadSafeReference.h in Headers */ = {isa = PBXBuildFile; fileRef = 01E829750D016D1BB8739C7D6C8B7E1C /* RLMThreadSafeReference.h */; }; + 4FF9983736B6CADBBF88AA045F521356 /* ObjectSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507E063CA30A2126D999BD8DD729A4FD /* ObjectSchema.swift */; }; + 50747D518C1C4C1FB8738CBDF820D2E4 /* DistinctUntilChanged.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A3C70D050B1B4B178ADA00B9AA4F6AA /* DistinctUntilChanged.swift */; }; + 519CF3AAEC307B5130BA02E8460DF541 /* _RXObjCRuntime.m in Sources */ = {isa = PBXBuildFile; fileRef = 11A904EC64DFA23BCEB1F41261404EC4 /* _RXObjCRuntime.m */; }; + 51BDB454EA5B0F00C57B88F0B0926043 /* Map.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F594796D37FA8E4181B6C9837866D3C /* Map.swift */; }; + 51C4A45A24282CA38D96E659DBB731EC /* SubjectType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7DD046180099B4434D80E9C4EB641390 /* SubjectType.swift */; }; + 52AB2A253CD2210540A142AE0EE9A15D /* RLMObjectStore.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = ACD3F71760CCCD9557A8FF00B70177A6 /* RLMObjectStore.h */; }; + 52B827057310BA50188CD872748D8EDE /* RLMSchema.mm in Sources */ = {isa = PBXBuildFile; fileRef = BA44B6692F790A5D43E3F201979ED665 /* RLMSchema.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 52C0835254BE9A54C26C05E8B7AC7448 /* Bag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79A8CC9EDAA7DFCB1E18EC681B2E22B5 /* Bag.swift */; }; + 53BB3BDA11BACEF71112399E01E8FBFD /* EmbeddedObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C227BE1AC1012FDEA2508280A710B85 /* EmbeddedObject.swift */; }; + 53D578268DF2CDD69DB114B286526A86 /* RLMObjectBase_Dynamic.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 66EDB9DF199CC9BF81C564719B0E75AC /* RLMObjectBase_Dynamic.h */; }; + 5441B6F9D99E964B9DEF28E22DA186C3 /* NSObject+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9353D0C358A0729BB1BEBEE191E85F7D /* NSObject+Rx.swift */; }; + 552F8ED0C209B54D73234389B1932AF6 /* BSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6510CD41689DBE8602E63A8D32D93B2 /* BSON.swift */; }; + 5549FE5C6E943FCBC92F17C64766A6F2 /* Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38ACC5B4987910374BEBC50EBEC37F85 /* Combine.swift */; }; + 558E5FFD90EBBB90A9BD5F6DBB55B225 /* CombineLatest+arity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 663782B983674097667AA655877DE251 /* CombineLatest+arity.swift */; }; + 55D00154D47F4F10F15AF209AD0DF687 /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6422EAD5E456128AF6EF8B6214E9EB6 /* App.swift */; }; + 5693ED494E0695D33945FE54D5B5D675 /* RLMListBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C8B3A7FA064FA49FA28D62F6971AD96 /* RLMListBase.h */; }; + 576E58F745809FE5EA79AF979F7CB959 /* RLMMongoClient.mm in Sources */ = {isa = PBXBuildFile; fileRef = 36A621775AD2772E5FEEDCE7B4C00609 /* RLMMongoClient.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 578CA2B081756A519BC26FC24375866D /* Observable+Bind.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3792EC9BB21CD2D5F7B80FB23B95039E /* Observable+Bind.swift */; }; + 581460068D8BD0691BD67D4A95FF9A8B /* UITextView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8635041539346B94338CE166995E9AC /* UITextView+Rx.swift */; }; + 5823BCC5E382DE702FBE07784AF8FC08 /* NotificationCenter+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6410892B86384E401E39178B508F47B7 /* NotificationCenter+Rx.swift */; }; + 589BC47EBB7DBE6F853F1800E67E431D /* RxAlamofire-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 77F0820D4FCD444B8F0423461352022F /* RxAlamofire-dummy.m */; }; + 58C84DC22DCFA32BC2C40603F2515323 /* remote_mongo_client.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 79CA8D74CEF50C0C13559089D0DEA8A3 /* remote_mongo_client.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 58DEB0E372F1D566ACA2DE6B11ED5158 /* RLMMigration.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 1C16195CFF5969D14EC6DEA689F73205 /* RLMMigration.h */; }; + 593D382A4A7EEE47FDCAA668E5E3189D /* URLSession+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6EF4F2B170D864CB87EB954D73D92566 /* URLSession+Rx.swift */; }; + 598FFFD4D64B8A54CD141F10274D8F4F /* RxRelay.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2678655DA16D1C91C49D41DFDA5870FA /* RxRelay.framework */; }; + 59A6B0D9EEDC697D0013B02572F0FD7F /* Binder.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6F55429E4F5A3684B1B610EEB9CBC83 /* Binder.swift */; }; + 59ADA960FD6E41FEC7C3ADEAF7620D4C /* UITabBar+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B1917E6A743DBE3D87B9043CACA8435 /* UITabBar+Rx.swift */; }; + 5AC65D32099C396B5D4EF9125BB7649D /* ConnectableObservableType.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFCE456C658E2F0004F7194F0677A751 /* ConnectableObservableType.swift */; }; + 5B26550079AB783C657ECDBF80F3713F /* DispatchQueue+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2C742FC85CDE50CD28E5956F0ADDB74 /* DispatchQueue+Extensions.swift */; }; + 5B2D4557AB2074A39773DB270E6C3DDB /* RLMFindOneAndModifyOptions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 00A74A3256B9E1379A4DD01AD0BC8511 /* RLMFindOneAndModifyOptions.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 5B4067B84E6CB07830DE450A584651ED /* TailRecursiveSink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7917278D67C732EA8824D2F598180959 /* TailRecursiveSink.swift */; }; + 5B88D22C3A0626D6BA8351DEEDB36B02 /* Pods-Darner-dan-uh-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = A4288CA2B164000A29B4CA6754ED4A47 /* Pods-Darner-dan-uh-dummy.m */; }; + 5C6CD6EC458C64C129D7460EB2228935 /* RLMProperty_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = E1B03021B1EFA35F821B99376BEAB3E5 /* RLMProperty_Private.h */; }; + 5C724AD09CAAE87E18B82180F589C91C /* Sequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0217DDBDC78233930E7B2D4B10A4EF00 /* Sequence.swift */; }; + 5CB1FBEC190E2884EE2375A8384C6B21 /* RLMSyncConfiguration_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = E5A7027385985B7AE9F3DCD243487913 /* RLMSyncConfiguration_Private.h */; }; + 5CDE9F4B6E5C2CA57B28D5040F03F8CF /* Signal+Subscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 724255BC9B7D55EC976790CCFA597FD3 /* Signal+Subscription.swift */; }; + 5D2B7FABE62E81EF77EEA1B8674C94F0 /* RLMObject_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 57D26DE88762BD941DD60CB00B72DA3D /* RLMObject_Private.h */; }; + 5D8E7BE5D7BDAB74C246233E8C1B778D /* Cancelable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A83EEE7FF87AE4434072CD2E879BAB8 /* Cancelable.swift */; }; + 5D99E2CB87F0128C877A251BE5FEB7FC /* schema.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B0076057252637CB1FC2A28D7CE35B90 /* schema.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 5E3605A3BC245596B6DD17BBFCD55765 /* _RX.m in Sources */ = {isa = PBXBuildFile; fileRef = 52C941DCDB3F6B0C1A675A2389D157F8 /* _RX.m */; }; + 5E3CDC31679301E98CA6E49DFA37CC63 /* ObjectId.swift in Sources */ = {isa = PBXBuildFile; fileRef = 392210D1A703D4FBF3F414E4EEA4B01C /* ObjectId.swift */; }; + 5F9857A5481F669FF3A03F175D5FB7F0 /* RLMSyncSession.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 99D287487AD77AFB75AE28B736B355DE /* RLMSyncSession.h */; }; + 5FC8192C811F9B629ECE5FACD378266F /* RLMRealm+Sync.h in Headers */ = {isa = PBXBuildFile; fileRef = 84E405EFB78E63F9D2F57CA86CA6BC4D /* RLMRealm+Sync.h */; }; + 601BF4A1BE00CCD3E7DF72E06D546534 /* RLMObjectStore.mm in Sources */ = {isa = PBXBuildFile; fileRef = A21415F38D7146BDCAFA9B3D201988C6 /* RLMObjectStore.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 606F2310EC8680F89C422DF6B3AA250F /* Realm.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 8D5D2EE19CA67D347686A2E578910C66 /* Realm.h */; }; + 6108B62490C1C0715783C7CF562B07A7 /* bson.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D336EE10741FE93C320CD500327840F5 /* bson.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 62D4000E5DD961FF8259F3C6BE1910B8 /* RLMArray.h in Headers */ = {isa = PBXBuildFile; fileRef = 2792D1140DA9A6D5A0AE6C7D26CE34DE /* RLMArray.h */; }; + 635E24A31EE03543A8FAFE0EC67A85DC /* UIImageView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82371E956C3016CE2FAB26325FA8263C /* UIImageView+Rx.swift */; }; + 637E7100E21DDC1CE80B56DB518EAEBA /* UINavigationController+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62417B7C7ED038B5F8F43B05FAD2BFE4 /* UINavigationController+Rx.swift */; }; + 642E161B02B38B6D4C18373D2C37D573 /* RLMProperty.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5E4DC26BFD994975A4452321FEE2E86D /* RLMProperty.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 6464287695ECCBB4CA2CB81462BF1178 /* NSImageView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46F0BDEBDA102A8F380230089E3DF83A /* NSImageView+Rx.swift */; }; + 6467FE4BA8A61320C4A98A4478485ECB /* Deprecated.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4CCB369D05C229C176B9F89E63D0202 /* Deprecated.swift */; }; + 64A68FDD7E4FF7FE7BDED7EE918A8B25 /* RLMSyncManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9131396FAB541FDAB151AB74DBB27C00 /* RLMSyncManager.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 6546D728B69398F93B506845141EBD61 /* EventMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC46534386377743676587034A95CBB9 /* EventMonitor.swift */; }; + 666EC5C8356E6D4448A2FE7BEE77AD88 /* RedirectHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 672BD61565B17E3649CB5C53F72C117C /* RedirectHandler.swift */; }; + 66903C58DF7B49405B034C65DEDF7ABD /* VirtualTimeScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5BEE546D9C98D268006E154C4DC5116 /* VirtualTimeScheduler.swift */; }; + 66B26C6CAE737EC21F4BA1F1851B69C5 /* Result+Alamofire.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2034C81E59E1F1EF6E36D917E0936861 /* Result+Alamofire.swift */; }; + 6797FA90BF2145F3575358E2BF49B4F5 /* UIButton+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = E34C1373861581DDF0256BE646DCE7B7 /* UIButton+Rx.swift */; }; + 680A5E8F4B218F13EF981C79A59DF96D /* sync_file.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3845E9FA4FDBDCE093112D811EA05B6 /* sync_file.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 685FFE938626A3F4FDF08226915706E5 /* RLMFindOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 45B647ABF0A00004F68914CBADFB5B27 /* RLMFindOptions.h */; }; + 68A9C5850AF89F7E3B8AFEEAE2A97BB2 /* UITextField+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EC5F0B44C2299F90E6115EA3E9D09A1 /* UITextField+Rx.swift */; }; + 68D2FE7DB60E1387107B50F571744BB0 /* Realm.h in Headers */ = {isa = PBXBuildFile; fileRef = 8D5D2EE19CA67D347686A2E578910C66 /* Realm.h */; }; + 690740100450EF9008CB489899165B38 /* RLMObject.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 1353548A4397B700D6C86BF0E496F8C3 /* RLMObject.h */; }; + 6907E511281A1585862FA580BA1AA27A /* RLMClassInfo.mm in Sources */ = {isa = PBXBuildFile; fileRef = 97114D5DB038834C71DF6D35894881E3 /* RLMClassInfo.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 698B1407BF56F779E3425902C9A49628 /* RLMRealm_Dynamic.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 474B55CB2CC0E9BAE21E4A0D1DD8D50A /* RLMRealm_Dynamic.h */; }; + 69E8F762D62563EF01CE5B68227D6515 /* Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF497AEA1642B013BDE723091AD4EDB7 /* Event.swift */; }; + 6AE407A4FB6C3D6ADD862CC6E3067A17 /* Session.swift in Sources */ = {isa = PBXBuildFile; fileRef = EF1E92FCED708D7E4565A3867B965CEA /* Session.swift */; }; + 6C08F6A77889651626583100F560153D /* RequestTaskMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EA417896E98F2FA28958FEFBBFAC5B2 /* RequestTaskMap.swift */; }; + 6C1EAB2CC7E9E6E109B45355419D8960 /* Aliases.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3DFF0752CD021478CF09DE2604A4F00 /* Aliases.swift */; }; + 6CE2A7E2B7213E955EF438FDAA4C1398 /* RLMRealm_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = A54DEEC664B55294338630DE37A09A15 /* RLMRealm_Private.h */; }; + 6D419CC34E321A9F0BC9A16E44593339 /* RLMObservation.mm in Sources */ = {isa = PBXBuildFile; fileRef = B28FC641132526433C317123A996D97C /* RLMObservation.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 6E157DD0AEA68E24821522D8996E1050 /* Schema.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4D35DDC112BDC5FFC671470DD73ECC07 /* Schema.swift */; }; + 6E54F64E8DA73F4B0B46C216F9F93F63 /* RequestInterceptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D6E0185990293F9B45806EBD2A593FF /* RequestInterceptor.swift */; }; + 6E5FD487F5200FFE41A8590F1C80D6A3 /* UISwitch+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39CD0793FF148ED71A50FF908326D1C /* UISwitch+Rx.swift */; }; + 6E98C877F675547622B217F5A0C6C7F1 /* RLMSchema.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = D1E961D09AA076899B1338AB10A23759 /* RLMSchema.h */; }; + 6F6BF6CBBAFEEB5A51F6AB50D96D751F /* Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7DFB8251965F74E154260AC1B1C118 /* Util.swift */; }; + 6FD6FB33CA60E3EEAC02743F81B2A795 /* RLMResults_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = A53B942D095FBCA857D477D52867F35B /* RLMResults_Private.h */; }; + 6FFE3D1B499EB10FBEF54B11B6914EEA /* object_notifier.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFD3A4F8CD51D3B9F9B303137A7D436D /* object_notifier.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 702DE8BBD6D168F3809535BE3F9C3045 /* RLMCredentials.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 6652A6E7278B0F41CBFCE6520A354FC7 /* RLMCredentials.h */; }; + 70D827AB6A89FD2D5D05325E9A8D2036 /* OperationQueueScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A33295D5CA69066CEB503EAD303E41D /* OperationQueueScheduler.swift */; }; + 716FD05A624B0B9ECB0A8B8019BE000E /* RxTableViewDataSourceType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9780DFB1A6645BAF294350731A0D5D12 /* RxTableViewDataSourceType.swift */; }; + 71A3695B1CBA3A936B62EBA9E12D5714 /* NSError+RLMSync.m in Sources */ = {isa = PBXBuildFile; fileRef = 7EFE079604B17211ADC0DBD90895F0F7 /* NSError+RLMSync.m */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 71F53B95BD754FCBAC78A18A75420B73 /* RLMObjectSchema.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = AA0E41562C17ECFEDF9457B13567040C /* RLMObjectSchema.h */; }; + 724492108AD175B06CD238654A682F3F /* Property.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6DA322294286F1B63182F5BBF223970 /* Property.swift */; }; + 72521FC1A240438582D88313DA2F71B3 /* Signal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59D97F87A443456155F519E2A0FCD855 /* Signal.swift */; }; + 7284925E9037C99E8F2EF8B9E3C5097C /* RLMUpdateChecker.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3489ECAB322E95680C288808406928E2 /* RLMUpdateChecker.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 729CF267488A10754F1E249B4E5DE1AE /* RLMManagedArray.mm in Sources */ = {isa = PBXBuildFile; fileRef = BBFE582250E3905047D7584AABB79C71 /* RLMManagedArray.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 72EC2712926E6D28B52360D9AC41668F /* AlamofireExtended.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9DAA9230E36A2125FEA32C5242589513 /* AlamofireExtended.swift */; }; + 73413AE360E854E9F9C08B8829C3C1C4 /* RLMUserAPIKey.h in Headers */ = {isa = PBXBuildFile; fileRef = E8C296B43EC37369C8F90E4070E1A3AC /* RLMUserAPIKey.h */; }; + 7372C0C23D5BA126DD35CB42A6B7975B /* ThreadSafeReference.swift in Sources */ = {isa = PBXBuildFile; fileRef = 058AEEE4D4897A46CF0584F64E3439FF /* ThreadSafeReference.swift */; }; + 73D4B8DBAA4775FA576C6E99DA74E9F5 /* ControlProperty+Driver.swift in Sources */ = {isa = PBXBuildFile; fileRef = E976DC771B75E8F4C938E082D2DC67E9 /* ControlProperty+Driver.swift */; }; + 73F87077A3D9144B369905812C38AC55 /* ImmediateSchedulerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F1A25FE11E235D26A2DF9E9B0C5F486 /* ImmediateSchedulerType.swift */; }; + 747BFC432635738E49B29E86EF568F32 /* UIActivityIndicatorView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FFE744FD97312727A9E1589CD8DBE63 /* UIActivityIndicatorView+Rx.swift */; }; + 74872B2FC64CC6125CCEF48562B0671E /* ControlTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55667AE78EBF92BF3FD083D92F3F038E /* ControlTarget.swift */; }; + 760178B71CDA56FA10A78568F286086C /* ObservableConvertibleType+SharedSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 321F4B543D57E15D74C5F63616BD9783 /* ObservableConvertibleType+SharedSequence.swift */; }; + 76C493AB7CC762FD68D29C8A099824B5 /* Just.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15832563E5BD805727075DD666DFCC6C /* Just.swift */; }; + 78A9DFDD190D31400114C1E6981B8728 /* RLMUtil.mm in Sources */ = {isa = PBXBuildFile; fileRef = 514EDB50B37C0BA31EE0FF3E4DB2C0FC /* RLMUtil.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 78ADB328BD29F62221BF79CEB2A89C81 /* Create.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BEF15345C60B26DE20F2B3F14A965C5 /* Create.swift */; }; + 7941FAFEEF08562B4C9B608235E9F187 /* RLMUserAPIKey.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = E8C296B43EC37369C8F90E4070E1A3AC /* RLMUserAPIKey.h */; }; + 796616B2692253493BC8674B1FB367FE /* RxTableViewDataSourceProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7079AEAB9A6E700D8AF5363DF851A2B /* RxTableViewDataSourceProxy.swift */; }; + 7995E0CD758104708892EC53E508A900 /* realm_coordinator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2E3BFA2B1FE0ED598F6CD11830FCC6EA /* realm_coordinator.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 79CB31FA3A1B23D44A0A0471E9C2EE3B /* index_set.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8A193A9805AD36F6923C1094E275C8F3 /* index_set.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 79DCC8A5ED66BF9DAA3ABF7253E79A44 /* SerialDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5D3ACF1D878E195BDF9F514B113B776 /* SerialDisposable.swift */; }; + 79E9EE217D63D5047BEFF84619151822 /* InfiniteSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1809FC8B4516DAD5F0624F299B5D42D /* InfiniteSequence.swift */; }; + 7A00AC4F9139FB78619C8F298F8283B4 /* UIBarButtonItem+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = A61255D6036F7ACBE0D1DD5F407E59A6 /* UIBarButtonItem+Rx.swift */; }; + 7A4301A07887232A5D3C87FD2FE85CBA /* ObjectiveCSupport+BSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15B15F53FD84C0A717006B124E115B1C /* ObjectiveCSupport+BSON.swift */; }; + 7A7706AEA3478A3267331216D8264490 /* RLMProviderClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 9412756A303D90418C6D9386101C3738 /* RLMProviderClient.h */; }; + 7A93A22BD86309270AC44C644B7501FE /* _RX.h in Headers */ = {isa = PBXBuildFile; fileRef = 19BA186E169315ABC1A14BB2D6C4B102 /* _RX.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7AA2AFAB93B7DE3211F77A7B3FE073B9 /* RLMCredentials.h in Headers */ = {isa = PBXBuildFile; fileRef = 6652A6E7278B0F41CBFCE6520A354FC7 /* RLMCredentials.h */; }; + 7AC2030996D338C027D2A864AC00806F /* object_schema.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 97E523BCD01E85E993214379AEB68DE6 /* object_schema.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 7AD20C0DC5EC36C37F5557432449B972 /* SynchronizedUnsubscribeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F568642989B09534F4E2CF34ADE834D /* SynchronizedUnsubscribeType.swift */; }; + 7B89A3FFC01803E264A95FEC8BC0605C /* RxSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4524CEDB98A45F635C925EEFC4AC4D3A /* RxSwift.framework */; }; + 7BFF67A9816CAACFEA8C9D58D6B7A4AA /* RLMObjectSchema.h in Headers */ = {isa = PBXBuildFile; fileRef = AA0E41562C17ECFEDF9457B13567040C /* RLMObjectSchema.h */; }; + 7C2436D7801191C2D662E3A0F8B63C14 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3C3AF2E791EE67E3DF385C1781D769A1 /* Foundation.framework */; }; + 7C5164249B7B15A1F1CBDD7662DE62E5 /* RLMMigration.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C16195CFF5969D14EC6DEA689F73205 /* RLMMigration.h */; }; + 7D034C0991497FAA18B16BD219918364 /* RLMObjectBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 6924294AB88A4FA6537B15BA0B6F297D /* RLMObjectBase.h */; }; + 7D0A23F4B6E8A0EEF7E2F53E708CE535 /* RLMSyncConfiguration.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 6B7A5B0F7FA13D2ED0C0C194C5E8EECB /* RLMSyncConfiguration.h */; }; + 7D3DD4A8BB36733BA15868F7FB8C56CE /* Alamofire-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A1F51107743C21D53321F2E4C3C2B12 /* Alamofire-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7D54E58E435DD28C7AF8C3FD4E1A5EEA /* UIView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53EAC9C5F32183C09D621EB078E77FB8 /* UIView+Rx.swift */; }; + 7DD47F7CB7EF38A8097DDA5EE0DE5260 /* SubscribeOn.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27C2257CED81A269B4F3CFD395A737F8 /* SubscribeOn.swift */; }; + 7E978945DB721518C002B6B1C4153EC1 /* Realm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01249979DC8733446D96910BD960244A /* Realm.swift */; }; + 7EC4129725587E781EF3F79E63AB40EC /* AsyncSubject.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1697E1FF125ED99D1216B93E66EAF5B /* AsyncSubject.swift */; }; + 7EF7523471466693BAC8D062665C5739 /* ReplaySubject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1EA27B0FA2BCDEE2E68302FE74F36B0F /* ReplaySubject.swift */; }; + 7F9ED1AB9D2DBAF3372A76755CBFCA36 /* SkipWhile.swift in Sources */ = {isa = PBXBuildFile; fileRef = C359882BC848E9114C2412C4A30DF333 /* SkipWhile.swift */; }; + 805EEDF5A59400ABD8379567AACA849E /* _RXKVOObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B812574628875C8E875DEF8AC3C3B14 /* _RXKVOObserver.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 80A444704CE5CE018DA62ADC894EF15D /* RLMMongoCollection.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 747A3C76800A1F6EC0D6086DFC8CB10E /* RLMMongoCollection.h */; }; + 80AA5AEFA71FA484B90D7B0EF7F9198D /* UITabBarController+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4D13E474693D288FA9DFD047070BE0C4 /* UITabBarController+Rx.swift */; }; + 80F4387CB339E32E867FC3FD5D06EDC3 /* generic_network_transport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 72A2153FA40633D4FF37728672DFCC9C /* generic_network_transport.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 8117470A6E1CF87DF2049262E34119F3 /* InfiniteSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19615B9A1BDAE31426AE13F76B0863B /* InfiniteSequence.swift */; }; + 81892F5B2F07DC6BC0835CEF849DF4D4 /* Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = D76B0D404FF9222A46B821BC2AEC07E3 /* Error.swift */; }; + 8379CE8ADB710D5E66BA7034FD91C106 /* AsyncLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC071B2000C8A95778E4A22701CB8FEC /* AsyncLock.swift */; }; + 83B7E3B66F98454A70D50243B06C642F /* PublishSubject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51733B99E1E51A063736971961F48AF0 /* PublishSubject.swift */; }; + 841E48251F31B1D543566E3A13865ACD /* RLMResults.mm in Sources */ = {isa = PBXBuildFile; fileRef = 23B95E3E4BB5C2C0F727D6DCAA4EFD16 /* RLMResults.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 849425BFC2B04B4F257995418BF94E56 /* Observable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E43F537772E258AF502F38A512641D1 /* Observable.swift */; }; + 85557BB8ADEDB23D463325DE651CF458 /* UIPickerView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E5630F16244E3A4DB87FBDF960B6315 /* UIPickerView+Rx.swift */; }; + 857D651808499F8B24D5EDE50D147551 /* RLMObjectId.mm in Sources */ = {isa = PBXBuildFile; fileRef = 44D3FFDDA0AB5DE8F05DECEEBDEB12AF /* RLMObjectId.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 86FB0771E04ED3CCAF7DB95BA8B3D910 /* SectionedViewDataSourceType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 099B959E823B66AD38AAE961201FBEE2 /* SectionedViewDataSourceType.swift */; }; + 87DA86D77902ACF17437E16E77A0D6E0 /* _RXObjCRuntime.h in Headers */ = {isa = PBXBuildFile; fileRef = EC2DBA6FA3B5F0017EAA6CDA39A7EB73 /* _RXObjCRuntime.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 881C70481B46015D67ADA02E19FEF6E1 /* RecursiveLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B0E4DBE82AB38A449D35BA4C6CF1CF /* RecursiveLock.swift */; }; + 8830BDFD242FDAECB9C82C0B3AC7780C /* RLMOptionalBase.h in Headers */ = {isa = PBXBuildFile; fileRef = ACC8191ACD24F00F9C2FE8AFEBFFE08B /* RLMOptionalBase.h */; }; + 883D5FBBA006E6B1614CD8B08853A8D2 /* ElementAt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A3A47252A95931ECB57904A7424A230 /* ElementAt.swift */; }; + 889CB56B5E9CF3A71E4A91509F741D73 /* ObserveOn.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77AF92F12F598B9BEED3DFFCDE50EAC8 /* ObserveOn.swift */; }; + 89A413D8ADFD0197CEB23799710A0BE7 /* keychain_helper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AC464F34523709BD1E60BA27CDE8842 /* keychain_helper.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 89E2087ECB337C076F1ED6924E050CD6 /* RLMRealm.h in Headers */ = {isa = PBXBuildFile; fileRef = 59497FB083F1C96E811BF0ADD11511B9 /* RLMRealm.h */; }; + 8AA937910F87915DE700CAB6C868689E /* Notifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7C3A5B6C8097F3302E2D59329A8090B /* Notifications.swift */; }; + 8AE4D206A91C3C6926A30EEA746825E4 /* RLMProviderClient.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 9412756A303D90418C6D9386101C3738 /* RLMProviderClient.h */; }; + 8B95E16BD1E45AD2AD5FADA674641F58 /* results.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 712C52F8298ACFE9974537269740BA0D /* results.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 8BB7DB661CCE73DCD3AD00A9B0281C70 /* RLMCredentials.mm in Sources */ = {isa = PBXBuildFile; fileRef = 73C10FBD152E2E4CC495ABBFFDA46BF0 /* RLMCredentials.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 8BC4D5D2027568EF154309C4C1834682 /* RLMProperty.h in Headers */ = {isa = PBXBuildFile; fileRef = 2AE4ED8FA170DF993930A077F70FA6E7 /* RLMProperty.h */; }; + 8BC5AA1E6AD1AB6DC4B9D729B4FA51E0 /* Switch.swift in Sources */ = {isa = PBXBuildFile; fileRef = F440813566CE4FEBB85A775215C2B1C1 /* Switch.swift */; }; + 8BEF4FB2B3B83B4294C51BEAA865A2E7 /* binding_callback_thread_observer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FC0213C64A67607536CA92B3B9EDC152 /* binding_callback_thread_observer.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 8C1EAC997C4FCDF29630D9B6B4A8542A /* RxNavigationControllerDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09A35B0CB777BBD88B9DEF06B2BCD249 /* RxNavigationControllerDelegateProxy.swift */; }; + 8C59DBF8BD1589F58183850B7FE67858 /* UIControl+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AD199BA92F23A99AF5C9029FFE852F6 /* UIControl+Rx.swift */; }; + 8CC41E6981CFDE74C31F6BCA8365363C /* RealmSwift-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 0EFA3387D6930CFB27424B1C2E421920 /* RealmSwift-dummy.m */; }; + 8CC77BA86B1597344C9804F1CCE6DB91 /* RLMPlatform.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = F8216BA641FC62DCBDFC9C0268B56873 /* RLMPlatform.h */; }; + 8CD9C9A4B73AA40DA804E9D351A356D4 /* RLMOptionalBase.mm in Sources */ = {isa = PBXBuildFile; fileRef = EECDA48CF4FF1C4C110AF794275ED748 /* RLMOptionalBase.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 8D19635341502D13EB61E1C8F54ECB62 /* remote_mongo_collection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BDCACDC74AD6B5FDD41F5741D751047B /* remote_mongo_collection.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 8D347BF3B80C9984DB0930C3F6683A18 /* NSControl+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64A231448882D94B15129D5A86DDAA8 /* NSControl+Rx.swift */; }; + 8D7DBC4316F288B12023F9C8BF0721FF /* RLMRealm_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = A54DEEC664B55294338630DE37A09A15 /* RLMRealm_Private.h */; }; + 8E9DCE0300CB6B885CB0B0848660CDB4 /* RLMEmailPasswordAuth.mm in Sources */ = {isa = PBXBuildFile; fileRef = C25F0805D73DBCBD7D42D8A9FA10F93A /* RLMEmailPasswordAuth.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 8EFE85C5F1EB7D1C1173AFCEF47DAC45 /* KVORepresentable+Swift.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09E025DA5339A8DFF424471D99726054 /* KVORepresentable+Swift.swift */; }; + 8F10537A5EE0F53AA7F12A197A35561D /* sync_metadata.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6A6DFD2E3086F70BABF4D552F3F82567 /* sync_metadata.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 8FEC9AAFEC18ECC0FFA72C6FB5344CF2 /* Realm.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FD872F1EDC128CFFAD6F841A90F6AF /* Realm.framework */; }; + 903230A70B77C4891D1AB14C0D5CFB7C /* WKWebView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E2F3BC87F104DB09900DB492F6B2079 /* WKWebView+Rx.swift */; }; + 90D60900D03D9D9C7CEA26432FDA23E1 /* collection_notifications.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B443A7D6ADC2F4D60D93FC877D5DBE0A /* collection_notifications.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 911448B2EDA2FF880108F77642797A88 /* ResponseSerialization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 089F8F00402B7AD96A67301E78DE0707 /* ResponseSerialization.swift */; }; + 916174DBE8D667BEE3774A286F22AF48 /* push_client.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 685C0AD8CD4FEC498B803EBEAB9D460C /* push_client.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 91B837CE0DCD8EDB300FCDFFA1279162 /* HTTPHeaders.swift in Sources */ = {isa = PBXBuildFile; fileRef = 395BA47D1C6A5F1B244D5486B0BE5279 /* HTTPHeaders.swift */; }; + 91D00124917562F52641A33E63D781BE /* AtomicInt.swift in Sources */ = {isa = PBXBuildFile; fileRef = B67CCC5A38EEFC7FF284A0D814489035 /* AtomicInt.swift */; }; + 91FC0BDA4438ADFD21EEE604C67107AB /* RLMFindOptions.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 45B647ABF0A00004F68914CBADFB5B27 /* RLMFindOptions.h */; }; + 9210C710EBF1CB237EA930A8A3C09556 /* RxCocoaObjCRuntimeError+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE580AFDE74A4970B85874EF92F68E55 /* RxCocoaObjCRuntimeError+Extensions.swift */; }; + 921D26E614D2A43E6751CD5FF0DEBD75 /* RLMAccessor.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = CDEFA4D6E74CA20A41AD1D24A53B544D /* RLMAccessor.h */; }; + 92722A376625A1F7149AA703E0408894 /* Catch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27B03A18EA69A32F4FCD8E7A5D342674 /* Catch.swift */; }; + 92A8C17D76CCEC966A1F3BBC9ED21BB8 /* RxPickerViewDataSourceProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = E829B940061EA02DBFC78ACD6DC4908A /* RxPickerViewDataSourceProxy.swift */; }; + 9331460E161ADBC85F891527849EC282 /* ObserverType.swift in Sources */ = {isa = PBXBuildFile; fileRef = A38454798CDA8D34D056C8B5E0BA22C1 /* ObserverType.swift */; }; + 933D4526196380D5F0A886A9717E7DE3 /* RLMUpdateResult.mm in Sources */ = {isa = PBXBuildFile; fileRef = B02FFA9C7277B2B22A3A03CCE21A1F17 /* RLMUpdateResult.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 934E48A9D5A7C869FA3AF497C904B83B /* collection_notifier.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1F013734C88EBE1D69DEAD484ECADACE /* collection_notifier.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 93864538C6745E5AEF7FDB0743305ADF /* ObjectiveCSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 035A8B85F74A119913219BDD87EEBCFB /* ObjectiveCSupport.swift */; }; + 93D01020E99D083DEF43CA8B1B0DBD57 /* RLMFindOneAndModifyOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = C0233CB52B3C3FD4DF91769E2264AF71 /* RLMFindOneAndModifyOptions.h */; }; + 94F00BBF7C98FF9F7C8A50D09013D5F9 /* RxCollectionViewReactiveArrayDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 518DC531B255B88E40E5651418722E86 /* RxCollectionViewReactiveArrayDataSource.swift */; }; + 9592A59DA2AB14603C0A164DE99AE989 /* NSTextStorage+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94DFF8110F6D1F6DD68850F236420519 /* NSTextStorage+Rx.swift */; }; + 95A903FF7AB1A1BA9D09D37DF81A8AB0 /* _RXDelegateProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = ECF4A10D2278E7683FAF28C4118469C9 /* _RXDelegateProxy.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 95ADC069FEDA015B200EC2CF279BD27A /* list_notifier.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0D8B391ECFBBB1D945E878B3A2DB5B1C /* list_notifier.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 9791DC9559CFAF714A92BACF5B13FEF4 /* Debug.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75901C59B7444C2042CFE3AE5FD1990D /* Debug.swift */; }; + 9A2492FB5AAD077758AA999340BFF32C /* UIPageControl+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9981BCDBEBC277C4997CD0A9C283BF05 /* UIPageControl+Rx.swift */; }; + 9AB126DB8D28FE4AB79405C7381E741F /* Object.swift in Sources */ = {isa = PBXBuildFile; fileRef = A73ACA6C4773FFAEE78D2D3064620C3C /* Object.swift */; }; + 9B0C27309D7AA03EC0B4B74C637F728E /* AsSingle.swift in Sources */ = {isa = PBXBuildFile; fileRef = E83B6C534733423F02985C506A911F49 /* AsSingle.swift */; }; + 9B1D8A7798D8A6F518FC9AF9725431D0 /* URLConvertible+URLRequestConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = A65BD2C9DED18F75BF3E55EDDE4E56DE /* URLConvertible+URLRequestConvertible.swift */; }; + 9B36BB2683F3628ECD5960E9619EB19B /* Queue.swift in Sources */ = {isa = PBXBuildFile; fileRef = A163402F2A974483FDCA5F628E8E8AFE /* Queue.swift */; }; + 9B3A432265AF41500704ADBCB9C99DEF /* RLMListBase.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 1C8B3A7FA064FA49FA28D62F6971AD96 /* RLMListBase.h */; }; + 9BE9B1A29DA997E762CFD07F25605A04 /* UISearchController+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCFFD2140D45F12ABBE22FD0596DACF9 /* UISearchController+Rx.swift */; }; + 9C4DD39A83D74041F03638E274B8BFD4 /* RxRelay-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 99F09ED9AD8D1B90AEBBEB42D6F5C9E4 /* RxRelay-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9C6D19CA62E67E73FF98774FCEA080A1 /* KVORepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CB0323D0C93433A2A590C992D5B2C75 /* KVORepresentable.swift */; }; + 9D00BC8AB11B42F866B0C935D4F0782A /* SingleAsync.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CD4CA3CDAD3FB75BCFEA79F132F3357 /* SingleAsync.swift */; }; + 9D30F00BD5CDA6D4DAC0715BF9A657AE /* Completable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1427066B3F5B6E4ED399EB45CD534C6A /* Completable.swift */; }; + 9D7C342E2385A7BD0961AD94EF2DB544 /* VirtualTimeConverterType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9C9E72E22DF33D178D158F6A4918D07 /* VirtualTimeConverterType.swift */; }; + 9D83CCF8474F4053B033BBF3765F7660 /* _RXDelegateProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = A54BC7BDCBA78BF1EC20099D31AA1404 /* _RXDelegateProxy.m */; }; + 9D9106710EAC7C6C7FE9E7EC1BC00C35 /* ObservableConvertibleType+Signal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E1356395FE392C74DC067DC515B2E84 /* ObservableConvertibleType+Signal.swift */; }; + 9DC377BA787CE5DD877D77390EB6AA4E /* RLMSyncSession.mm in Sources */ = {isa = PBXBuildFile; fileRef = A5BC3FDB21CAE5641FA35481DB4757A8 /* RLMSyncSession.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 9DF8C6A435E81BF8787790DFECC08411 /* Producer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BF79B957BC253B9F9F622E3DA26AEE /* Producer.swift */; }; + 9E4DBAD6AF431F668F94E956E92C908A /* RxSwift-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 398354D20FA08BCFAF261A15A601B056 /* RxSwift-dummy.m */; }; + 9EA4DDCE4B1E859C86D5541DE1C89293 /* RLMMongoDatabase.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = F0AB722C3C0CD69B263401F5156BCE96 /* RLMMongoDatabase.h */; }; + 9F2C5F100F306A6B3AC4F959485D60C6 /* DisposeBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35E1C5A9B4B09EE53C0486B10DCAB3D9 /* DisposeBase.swift */; }; + 9FCF8D3AA301D89BC32C6023A0A5C21B /* RLMThreadSafeReference.mm in Sources */ = {isa = PBXBuildFile; fileRef = B1DC237BF5D2B86D015539248B204916 /* RLMThreadSafeReference.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 9FED70D1E1FBFB80E974E999EF732258 /* RetryPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDFE63997FF8C1AE2617A1BC92C4E1BE /* RetryPolicy.swift */; }; + A0F1126772F27032CB6A8E387F6412FC /* RLMObjectId.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 48E379072BB61DABCB5FDA0E8A8E8EB9 /* RLMObjectId.h */; }; + A13343AD34EAF3769BB9B1BD249687CB /* MongoClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = C04721533F2879C525420717BB0FEFAA /* MongoClient.swift */; }; + A25F6B7BE0481113031DF749FE9D40C4 /* RxWKNavigationDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F3DC0EA3882AAC0C73433CD4667975C /* RxWKNavigationDelegateProxy.swift */; }; + A37330602381FBF8EBA947F042E5D3FD /* RxAlamofire.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B754E74CA288E296A9522650713612D /* RxAlamofire.swift */; }; + A3F211F51254914790080A6E804A9D60 /* RLMRealmUtil.mm in Sources */ = {isa = PBXBuildFile; fileRef = 73459032C7AED3F87C065F092BFDC3ED /* RLMRealmUtil.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + A4103D4B6E809B607DAD34B0723B4733 /* SchedulerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = CFF30630BEEB8097918CA55E8575BDF1 /* SchedulerType.swift */; }; + A60C4E1E2F7572919C180B47A0F29287 /* ConcurrentMainScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = F32BA08422C23AB8697543BF4EE4A6EF /* ConcurrentMainScheduler.swift */; }; + A62F3672E29207515DEF358DD3F6633E /* NSError+RLMSync.h in Headers */ = {isa = PBXBuildFile; fileRef = EE3FF4B388652B33DDD06D2496327330 /* NSError+RLMSync.h */; }; + A645856411CD83CC21C7D801272669F5 /* Platform.Darwin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 299B1BEACD3DC873914E50E57C3E4F43 /* Platform.Darwin.swift */; }; + A6B6A8ED7B80DC2A06E62E2E84907C78 /* GroupedObservable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8D3CD52C0F4520B98B15311A415FF67 /* GroupedObservable.swift */; }; + A6D7397F93EA53BAEB5EB3ABFC95EC42 /* RLMObjectBase_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 37D024D0F04AAD55C5660DD29517DE6C /* RLMObjectBase_Private.h */; }; + A746788821047E64C8BD4E9D87C9B625 /* PriorityQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51B7DF99F44018B800FB12ACED5FF6DD /* PriorityQueue.swift */; }; + A79FB31B60D9705E762A82DD6AB4AB9B /* Merge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36B0CAA1E7547C748296D9FF14B3A8F9 /* Merge.swift */; }; + A82149A817A79D292769BD47679567E5 /* app_credentials.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A43E908FDEB66EAF5CDC0C08CA8F2E9D /* app_credentials.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + A83C1EF6EB6B1905C8A79502DC061B8C /* RLMCollection.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 339215A49D0EE00F18DAD73C85C8CB04 /* RLMCollection.h */; }; + A848EF9FFBA3FDA9CC5119C087592FEA /* RLMListBase.mm in Sources */ = {isa = PBXBuildFile; fileRef = E9FE377B8B9D00BE6088A6D9BBE2CD67 /* RLMListBase.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + A89453604B902774519EC42E6316C985 /* BehaviorRelay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A9EAA3A3F0ADEAA5CA9017D7A367920 /* BehaviorRelay.swift */; }; + A8FF5A60B4CF0B1CAA86AC209A6E01EA /* Alamofire.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 768B96ADE27F4305ED123B2603C54787 /* Alamofire.framework */; }; + A9357EBC2D7A15D3E3891A27CC8FE8CA /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3C3AF2E791EE67E3DF385C1781D769A1 /* Foundation.framework */; }; + A9C7B29D4878F1690BBE3F8195CF0313 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BA07F30960653B557BD112DFE0FA2FD /* CFNetwork.framework */; }; + A9D470B9CF9F652DD29828BD75A5CFB2 /* SortDescriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B556D760F8D3AEE8A5F67DCDA5CEBF /* SortDescriptor.swift */; }; + AB1F6B3296C144585DDCBCCABB6D9343 /* RLMQueryUtil.mm in Sources */ = {isa = PBXBuildFile; fileRef = 444FCF6395FE1FD628DE5A8E7D80B3E5 /* RLMQueryUtil.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + ABA85887A41495358C83CE3F3030EDEA /* CachedResponseHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9DF5D58B19C6C63A65143A3E6532029F /* CachedResponseHandler.swift */; }; + AC04774171C794FC6EE3572948B35189 /* RLMNetworkTransport.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 888D23E446A07C3A3365606FF924FBDA /* RLMNetworkTransport.h */; }; + AF6D1FFF733DF2F1D2AF703D850832E6 /* SynchronizedOnType.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91049B03ECD97F4BA7F35F3BEA12C2C /* SynchronizedOnType.swift */; }; + B0528F277050656E75ADE1D065FC37B8 /* KVORepresentable+CoreGraphics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78BF537112F36CF990F71AF86E97C406 /* KVORepresentable+CoreGraphics.swift */; }; + B17EE6534DB2F9BE4C7F022EFC577F6E /* AddRef.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A99B37E50B6E39B7CD160179B1048DF /* AddRef.swift */; }; + B27A654EED61328A617C246F39C7EFD2 /* RxTabBarDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DE3CA5A0A2191AE9FDC8035DA6936DC /* RxTabBarDelegateProxy.swift */; }; + B28296A50EB5B5B7742072F953004A7B /* Never.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73A9A3EEEFC050E309B1CF7BB6B34EFE /* Never.swift */; }; + B2B69A6518DA17ACF150F815F7C2332C /* Optional.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7778D9E3B0FE3705C43E723A322774A /* Optional.swift */; }; + B32DD267C91411A347168A5F47EFDE15 /* RLMPushClient.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 72842ABA9A87A415D9DA5339DCC9B4BD /* RLMPushClient.h */; }; + B435FA7C9BD453EBB6B51256E5B64F11 /* RLMProviderClient.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2EFFF14B7584C9C947179DA2BC659A44 /* RLMProviderClient.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + B4A337004B59DD3D71EA08745DC8D798 /* RxCollectionViewDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D244D7B1DC3CBCF25A32DD82D7F612D /* RxCollectionViewDelegateProxy.swift */; }; + B4F5580D3DFD4A2376B8897262380FA6 /* Concat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E2548ECC06C74EA7204E04959046038 /* Concat.swift */; }; + B50761B46B6B0DFA58E3A45431FAFD8E /* UISlider+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = B148AEF0FF207D58212857BDEAE15A60 /* UISlider+Rx.swift */; }; + B569012D3FF00C015F0C5ADDB20B04F4 /* CombineLatest+Collection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 434FC690A867299DE9E7360140680714 /* CombineLatest+Collection.swift */; }; + B606120F6D64F423657236A2970B2857 /* RxTableViewReactiveArrayDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8429204616E055CBD82FD738DC17DB1 /* RxTableViewReactiveArrayDataSource.swift */; }; + B607A65D5E7BE4266BF64B5DA40016CC /* ObjectiveCSupport+Sync.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9645FC628D296BC5A54B036A9DF35F9F /* ObjectiveCSupport+Sync.swift */; }; + B675A06F34FA4D0B0BE9BDFE839B5B02 /* RxSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4524CEDB98A45F635C925EEFC4AC4D3A /* RxSwift.framework */; }; + B68444C69EC1FEC73B45800AC2441E1D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3C3AF2E791EE67E3DF385C1781D769A1 /* Foundation.framework */; }; + B685BE07C94C5F5B95B29A52C9B6C18C /* RLMMongoDatabase.h in Headers */ = {isa = PBXBuildFile; fileRef = F0AB722C3C0CD69B263401F5156BCE96 /* RLMMongoDatabase.h */; }; + B6D36B8C8627159F88D54CA56BD9F892 /* ObservableType+PrimitiveSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7606F0023754B879718D8B9541F4BF15 /* ObservableType+PrimitiveSequence.swift */; }; + B763C21339C457FF6C9F23FCD847C294 /* RxScrollViewDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62459D303A3950966A418BDE2EF5E9D /* RxScrollViewDelegateProxy.swift */; }; + B773E038954146A469A44710FE287988 /* app_utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6EC00D8A01B8A46996F24C44D7E9AEB /* app_utils.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + B797F6D52FDB1E40D50FD6EBEA92BCEA /* Results.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1968A5FAFECDCC7C761C774AF269DD2F /* Results.swift */; }; + B7BE18598E8D81B5BC8CFD2542CDE8AC /* weak_realm_notifier.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90520370565051AB89C191544C3D53CE /* weak_realm_notifier.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + B7D97D56253496C380B8814779679641 /* sync_user.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83D5D07DBB1E6BEFC0FA713727BD7111 /* sync_user.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + B805454BD4733A2BD5D1E9927781C61C /* NSTextField+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A0F60CC9D52B64D82BCC6F7CD12FAD /* NSTextField+Rx.swift */; }; + B89076FEF8EC003AC980CF918B9D20C6 /* TakeUntil.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA1E5A489614197B059BD7EF0B219DC0 /* TakeUntil.swift */; }; + B8E6E280D60598D2495DF9B150792294 /* Scan.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9324A6849331CB03EC6A65F1D0181040 /* Scan.swift */; }; + BA34DCC8F9F4D3FE007D7D4B83646F2B /* Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7C1743DFA2101E0EEF4044DFE0AF806 /* Error.swift */; }; + BAA015FE03F9938E2BDAF8750F8A0E60 /* ScheduledItemType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EB4FFCEC0440FD27F0D6CAFED9F09BF /* ScheduledItemType.swift */; }; + BB4A976D04B8FC213E343AB9762058ED /* scheduler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2BD4FCE00CFCBE8E98C06E5C3A0495E7 /* scheduler.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + BC68C6F8F90A12E99320DDB0B48544CD /* SwiftVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3EAA1E9622A8BD4F96A0A7C126C124E /* SwiftVersion.swift */; }; + BD0FA67EC1C87F22197C5D52A722C5EC /* RLMRealmConfiguration.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 30B878398E136A1052ECEC59EB9A252D /* RLMRealmConfiguration.h */; }; + BD981502B63CA6245CDA8ED2975F73C5 /* AnonymousObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43628ED44C9AA3D3503458B602E82696 /* AnonymousObserver.swift */; }; + C096DCFF1DF830B2FBDE80D30EA3BA51 /* SkipUntil.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF0BD4151C0E4A0190952BFF69D011D9 /* SkipUntil.swift */; }; + C097D309A6C5250C1932A9F8AA9EC5AA /* List.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38BCA73981CA09129A31DC7B76307E1D /* List.swift */; }; + C0FA5CDF1CE99093FF0694BDF834069C /* Zip+Collection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2574918564F0C7583E08ECC28A77617E /* Zip+Collection.swift */; }; + C1C5B050B55C15103ABC81769551A283 /* Response.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7BDFC60B45FCC326C52B21834773793 /* Response.swift */; }; + C1F1DB6A9CBDE584D09BA1613AAD4F9D /* Alamofire.swift in Sources */ = {isa = PBXBuildFile; fileRef = E08C704F7CD7533F4E2B2A0B74F8A786 /* Alamofire.swift */; }; + C23BA015C29D1BD3F7E22641CD999AAB /* WithLatestFrom.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F88EF52999F2464E771FC2D673E42B7 /* WithLatestFrom.swift */; }; + C2D5D09CEC440A4621B5CAFB67B3A5B5 /* ItemEvents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EC3085A93400F8B25DEC31B6BB987E8 /* ItemEvents.swift */; }; + C36DA24C3370C592CB56A246D60D4FD9 /* RealmCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CD2BC359B1E50F0F0731770BCA42949 /* RealmCollection.swift */; }; + C4CDBA56D41744888750D08124E04B9E /* LinkingObjects.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDC4582D4D70B00FB4390B77B2D1AAF2 /* LinkingObjects.swift */; }; + C5A5AEEF77FA6E9297696D7130306BCF /* RxCollectionViewDataSourcePrefetchingProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 624F02C1F26E3F4651425171FAEE3170 /* RxCollectionViewDataSourcePrefetchingProxy.swift */; }; + C5A893D1945A3A0DD752D8FB3EDA2612 /* RLMArray_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 6008D806F7FE06FEE6315C1A586CBE38 /* RLMArray_Private.h */; }; + C6CFA4D8E44B2ECB867560F11166D847 /* RxTabBarControllerDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B39675E53AC002A88BF4E125C3B555A /* RxTabBarControllerDelegateProxy.swift */; }; + C6D5A4B4028B2C43380C9FA58BD5C8CA /* Alamofire-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = A8BFDC432C055B3060BC610A590B6D65 /* Alamofire-dummy.m */; }; + C7390ACBF2CEE2475250D982924AD5EF /* Skip.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D3E3CC8D7E1F0271CFA0868904F5EC8 /* Skip.swift */; }; + C77BBB1150A4EEBF948F2E32133719F0 /* RxTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D0F36C487638509F0A7E3BC5B96C2C /* RxTarget.swift */; }; + C9173647F028584F2E41255AAD3494AA /* Window.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61DF4B6E4DF859118106BF282B06A33C /* Window.swift */; }; + C92EE1C8771E4BA17872F7B9BF534787 /* RecursiveLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F212D9E7E87950A9A19CF27D66D6E11 /* RecursiveLock.swift */; }; + C9FED92878541212DCD20841DBFA48AF /* RxSearchBarDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DCFD52DE80EE3972E9D0E88FE4F085 /* RxSearchBarDelegateProxy.swift */; }; + CAEA4361DA6030D11415FBC4FD4C4DF4 /* RxTableViewDataSourcePrefetchingProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D7711C205CBF6BCA6CC225854D7D96E /* RxTableViewDataSourcePrefetchingProxy.swift */; }; + CB0D0F5EFA558F6F88DF7413F90059D8 /* RLMEmbeddedObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 21154A52CE37F60FB2E8149FB1B840DF /* RLMEmbeddedObject.h */; }; + CB87669275CD6B778DF7BF1E65B44541 /* RLMRealm_Dynamic.h in Headers */ = {isa = PBXBuildFile; fileRef = 474B55CB2CC0E9BAE21E4A0D1DD8D50A /* RLMRealm_Dynamic.h */; }; + CB952FD2F737FE25DC95579065296BB6 /* Driver+Subscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = B724B3052D7141BAB931AD7DDA4BE476 /* Driver+Subscription.swift */; }; + CBF5210B66B6E2BB31EB10649B3C688D /* sync_session.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6D933CEA78AFF25F8238B2086E0141E /* sync_session.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + CC027472DC55A3C8DA9590A2F643D5AB /* RLMProperty.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 2AE4ED8FA170DF993930A077F70FA6E7 /* RLMProperty.h */; }; + CCAA35935527C95DC8E75C9BB246776A /* RLMThreadSafeReference.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 01E829750D016D1BB8739C7D6C8B7E1C /* RLMThreadSafeReference.h */; }; + CD3D3D27D37B7B9B0001FD398284717F /* RLMPushClient.mm in Sources */ = {isa = PBXBuildFile; fileRef = E6BDE8A8A7F672F687F13615707178F2 /* RLMPushClient.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + CD73C8E467BB51A2989CB40BB7552EE8 /* RLMUpdateResult.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = FEF1973B4E9C40CAAAB341CD3C57C779 /* RLMUpdateResult.h */; }; + CD7EE17531481812A65BDE3B634BE875 /* InvocableScheduledItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4425212D91422CC722267318D089C54F /* InvocableScheduledItem.swift */; }; + CDCA48093852C8B844059A9684826F30 /* PriorityQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D616E8A716D3275DEDB55B9E7F3FDA20 /* PriorityQueue.swift */; }; + CDED438FA5C4771AAAA8E89F7CC5AC58 /* NSTextView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9568E57C0E585A32EE7E2863AD45A12 /* NSTextView+Rx.swift */; }; + CE90037BF8D1EF3DCBFBC97E56D2701E /* Platform.Linux.swift in Sources */ = {isa = PBXBuildFile; fileRef = D71A83BE43E28CBF5D49703E7B114BA2 /* Platform.Linux.swift */; }; + CF51770D45D6F6BB54BF6A00A52E12AE /* RLMRealm+Sync.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 84E405EFB78E63F9D2F57CA86CA6BC4D /* RLMRealm+Sync.h */; }; + CFD83F343EE1D966D873AA35362A2459 /* Single.swift in Sources */ = {isa = PBXBuildFile; fileRef = A159B91671189A11B7F92DC40A3B59E4 /* Single.swift */; }; + CFEA3F101DE538F84287DC4A0850310D /* RLMRealmConfiguration+Sync.mm in Sources */ = {isa = PBXBuildFile; fileRef = 869B025D18E382BEA868469B62E768EF /* RLMRealmConfiguration+Sync.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + D03DF75AFE3BE4990305DBC1DDB869F6 /* UICollectionView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A2612662E1FE096C9556E86ED4BC8C0 /* UICollectionView+Rx.swift */; }; + D03F1F02DE8606E6057D57866611BEBF /* MultipartUpload.swift in Sources */ = {isa = PBXBuildFile; fileRef = 528B9C2D3C3B86EDE0CF0FCD180ADD76 /* MultipartUpload.swift */; }; + D0764E3E0F0BFAB09CB05BFAE0A02C48 /* RLMObjectSchema_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = D53FF47C70573D21E73A4729008A809E /* RLMObjectSchema_Private.h */; }; + D0B4E40C0F861DBC1FE63272EC95444A /* RLMPredicateUtil.mm in Sources */ = {isa = PBXBuildFile; fileRef = FBAEE5BB4EA38C59A455590BED8D03F0 /* RLMPredicateUtil.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + D0DD7B89F7D44FC9C89C6011FFC678FA /* RLMAnalytics.mm in Sources */ = {isa = PBXBuildFile; fileRef = F0506E6B74E3BA42E9372DEE4243E6E5 /* RLMAnalytics.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + D101E2DDD33C5BDEE06582F7BBE87973 /* RLMResults.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = BE07BE828DE8E46170E7B5BA08E44997 /* RLMResults.h */; }; + D1335F3A26D985B2FD280505F3773779 /* RLMEmailPasswordAuth.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 64C4A169FCD8C606185D6CB50AE9ADF6 /* RLMEmailPasswordAuth.h */; }; + D14066FAE94E304798E43651E5886D13 /* ParameterEncoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10B64935EC02FE6B379CB2F93E79814A /* ParameterEncoding.swift */; }; + D15DC3BE7C68691D743B1908ABB91E07 /* NSLayoutConstraint+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63D68E55920A869C800D56FD98EC9C81 /* NSLayoutConstraint+Rx.swift */; }; + D1AD996716AF2C4C0A0FFDEB20CB76D6 /* SynchronizedDisposeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07911509368876C1EB24C2947E4CAA2 /* SynchronizedDisposeType.swift */; }; + D20C13087EB9EB20752977D28868A504 /* RLMSyncManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A659C5B4905F50CF069CBEC4BA23D5A /* RLMSyncManager.h */; }; + D31FC7FDD450C4CDD633ECBAD27C6221 /* URLEncodedFormEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A8BDABAB4E71F301AF4556EADC00F11 /* URLEncodedFormEncoder.swift */; }; + D337BCE2FB7C1D595669844BDD9E53BE /* UISegmentedControl+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43BBDAB01E88E016FDB56CAE0E18D1AB /* UISegmentedControl+Rx.swift */; }; + D3473A57080E70B88DA22CCCE335DCE2 /* CombineLatest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5EA93CB577014200856DD7108C1B0220 /* CombineLatest.swift */; }; + D437A93503211D776CC61B0A8A8A71F8 /* DelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = F61EBC120DB0824119271C50578D5E34 /* DelegateProxy.swift */; }; + D440B41F87F5C037A0BA851C26231AFD /* Realm-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 172C400CF391EDD3C0F55DA942FFD7AA /* Realm-dummy.m */; }; + D4C7B6A1541F75250C3983CE364604A9 /* RxMutableBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6E3240C5482DA163A54D2D6674527F8 /* RxMutableBox.swift */; }; + D51D0DFE7C3BCDE4221D5B3260E00224 /* RLMAccessor.h in Headers */ = {isa = PBXBuildFile; fileRef = CDEFA4D6E74CA20A41AD1D24A53B544D /* RLMAccessor.h */; }; + D5EAAFB6FAD77A8F0699345149BA3CBB /* URLRequest+Alamofire.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5BB9F8C6B4BDAC5D8317DFF3602B0F7 /* URLRequest+Alamofire.swift */; }; + D61D564476EF739873DD9EBDE8416963 /* RLMMigration.mm in Sources */ = {isa = PBXBuildFile; fileRef = 07156FB16C3FAFFC2E1D0A15BDC44256 /* RLMMigration.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + D64EA6E18B6AC4114BE0CB29B70B7739 /* ControlEvent+Driver.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0CD33ADC2C6492EFB2A1C9865747647 /* ControlEvent+Driver.swift */; }; + D791B0382F720B8C4B5D553908009673 /* collection_change_builder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C7AFF87F4881919AEDE31682621C65 /* collection_change_builder.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + D7E10DB3ABF6114CF827674F0043A39F /* RLMRealm.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 59497FB083F1C96E811BF0ADD11511B9 /* RLMRealm.h */; }; + D7E1E91CC797E5D4A1B6F0359FAD7297 /* Multicast.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B5C59F9DE41D9B01A435F7BF7BD1E26 /* Multicast.swift */; }; + D83C68850F8A3C76DE97A0551A818F31 /* TextInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF9E866F54DE7EC41EC272983D1A5357 /* TextInput.swift */; }; + D9BA5B238765E5E2D796D47246F748F3 /* UITabBarItem+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = B11C58CFC4921C01B180D0818D31F1CE /* UITabBarItem+Rx.swift */; }; + DA535FB04CFB9C4F62208DFD228EDBF4 /* RLMObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 1353548A4397B700D6C86BF0E496F8C3 /* RLMObject.h */; }; + DB2D57AF81BF92D637AC95F3582CC085 /* RxPickerViewDataSourceType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62D4533872082639E49CC2D812CCA9FF /* RxPickerViewDataSourceType.swift */; }; + DBA19C2B1420E4D0A8852A0434F364F4 /* ToArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DAB14E2B6EDB1F43829CF2AB53CC4A1 /* ToArray.swift */; }; + DBB377F541B3603F9BA9606A1DB64DD0 /* Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = D78FEDFFFE184B705D7E7C191AACECED /* Rx.swift */; }; + DC627AFC5B585686898B014184AFCABD /* AuthenticationInterceptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7488D788771D2CF319A3829C4B15900 /* AuthenticationInterceptor.swift */; }; + DD5E8C7164EA60B7D90933D5F16E7490 /* app.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7FF061165F98F4381C924039DC3469FB /* app.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + DD9C3275C29D5DEE7DF59E9F3C81E789 /* RLMConstants.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = BA487887F86C2E5E0C2C260131CD673E /* RLMConstants.h */; }; + DF574F8C2AF6A72F3406A273FAC49FF5 /* RLMApp.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = DA3598979CE772D50E44DD120ED96A26 /* RLMApp.h */; }; + DF74E6BDCDDA6B216A8A8FD19E53880E /* RLMDecimal128.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 597BC46EC61C37E53FF2B9A3DFDD76CC /* RLMDecimal128.h */; }; + DFF0EA52B9AC62085891FC48C2ABACE0 /* Zip.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1015A80CA0CD30BE28E2D2A3C0F657AB /* Zip.swift */; }; + E00573EE63B4E0BEA8288B4660ED1AB3 /* object.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 357BCD5C989B4B1386A6534171E16B6B /* object.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + E00E7BF9489CA487E2C1FB8A178D0CE5 /* Bag.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7520BC1DB4FCDDDD0D2A161F23A099E /* Bag.swift */; }; + E07DDEA75EBEB870754939AC1A90CD2B /* RLMUser.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = A653A9A03EC868233496EB1538F067D2 /* RLMUser.h */; }; + E0913C7ACDEE2FF3F5726843D87F0FB0 /* UIApplication+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0691AAD52FD34400A3BF78A3A24A58B3 /* UIApplication+Rx.swift */; }; + E0DFE59E5EA05F8B9676024BE9601A20 /* RLMEmbeddedObject.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 21154A52CE37F60FB2E8149FB1B840DF /* RLMEmbeddedObject.h */; }; + E15573FC708D5EDC5AAB6AF8B6831C09 /* Pods-Darner-dan-uh-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 271BA88AC2355AE18AC1B121E0E92300 /* Pods-Darner-dan-uh-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E1AF1FE47E95F9A724ACA36136445D60 /* RLMSyncUtil.mm in Sources */ = {isa = PBXBuildFile; fileRef = 6A6C8E21EBFBFFCDA1933049C170A78C /* RLMSyncUtil.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + E1CF74AE8957B40E91B844413D6066C2 /* RLMProperty_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = E1B03021B1EFA35F821B99376BEAB3E5 /* RLMProperty_Private.h */; }; + E23C04D2B3D8A4F5C4DBB96B5A07C9CC /* uuid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8D9F194E31435BDE8CF3925BAFF22F43 /* uuid.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + E261648E916D34916F2F63D857C9A77B /* regular_expression.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 651FA28CF0389AA0022093E86CDC588E /* regular_expression.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + E2960331F72C889C85D4875B200AF289 /* UITableView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8438E4076B74C43E8903AF30E833AD3F /* UITableView+Rx.swift */; }; + E3B8690153448DB7BB199D4FB8F1E90F /* SchedulerType+SharedSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22C6AE88E774A68F4D2348DE664A96A9 /* SchedulerType+SharedSequence.swift */; }; + E3DF652CDC2438967B655D3ED5BE83CE /* RLMRealm.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8E98590E803C6C2C41CAE017D38F9FFE /* RLMRealm.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + E4EC22E47F93A0B49658C837EDAC1376 /* RxTextStorageDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D0180CFE946C46EF8AF4737A4DFAD94 /* RxTextStorageDelegateProxy.swift */; }; + E515A33E15D267644599D92FFF01C153 /* RLMObjectBase.mm in Sources */ = {isa = PBXBuildFile; fileRef = 27B99BE284348A1148EC9971A44FE17A /* RLMObjectBase.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + E54A0D88D0C4F20184E9098E69D1DC68 /* RLMResults_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = A53B942D095FBCA857D477D52867F35B /* RLMResults_Private.h */; }; + E5A6D595C7534D56FEAD28CE551D9F52 /* RLMEmailPasswordAuth.h in Headers */ = {isa = PBXBuildFile; fileRef = 64C4A169FCD8C606185D6CB50AE9ADF6 /* RLMEmailPasswordAuth.h */; }; + E66AE676C6BE74CC63FFE2FEEB560BAE /* Materialize.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82266C25BBCBD86647BC2B7923D2B33A /* Materialize.swift */; }; + E71C2CBDF0E79625EF1058383A2CA403 /* RxCollectionViewDataSourceType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C2045674F4DE6D2F4B178A9AC7E39BB /* RxCollectionViewDataSourceType.swift */; }; + E7831E2B385EBB25849E550A74CD0167 /* RLMRealmConfiguration_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 78BD15A38C1C2292CA446D8971F118FE /* RLMRealmConfiguration_Private.h */; }; + E82171EB33337F99847E03EEAB85B001 /* Filter.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAB5C19EDDB71F30C96CF216AEB6881D /* Filter.swift */; }; + E84407680552F606BCF100C93E99C5B8 /* RLMSchema_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 7FEB4D9BA45A0D280A2E12721EDDE69A /* RLMSchema_Private.h */; }; + E86B0E0D913346ACDF5F2D69A0A98833 /* DelegateProxyType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F9470706D8F36E200A0E14D91125B4E /* DelegateProxyType.swift */; }; + E88BAAFE9AB16EBDB9F5CEA497F966A9 /* Maybe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66AEF1F18BB09CFF26081204A5716BAB /* Maybe.swift */; }; + E89494624801F6FE431482E5678CFC81 /* RLMRealmConfiguration+Sync.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 24BE49CFC9CEDC6E3FB1D1D9519FFB6D /* RLMRealmConfiguration+Sync.h */; }; + E90526ABB1CD5261FDE755DD77D0C4D3 /* RLMAPIKeyAuth.h in Headers */ = {isa = PBXBuildFile; fileRef = 02AC92A155B36A82731B0043B39919A6 /* RLMAPIKeyAuth.h */; }; + E94D94EF789DCBC511115EBC4F6B85C2 /* SharedSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4B9ABAE1767714182046DFA8A95ADB3 /* SharedSequence.swift */; }; + EAA258B8E03F55639960CA88385E4714 /* MainScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = F937B33AB2349728EAEBE30B14ACC732 /* MainScheduler.swift */; }; + EACA770276C17263B13712AE21C51C62 /* RLMUser.mm in Sources */ = {isa = PBXBuildFile; fileRef = CB6BD43736BD0C82C82EF813563DF749 /* RLMUser.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + EACFEE3517A5D770813C785F4FB2EAAE /* PublishRelay.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4BBBF627F4F3772693F6C60F062DC8D /* PublishRelay.swift */; }; + EB188E609BEFB8A628A4747E9B5803F8 /* RxTextViewDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E317DE1BFFB70C4D5832975F2922B01 /* RxTextViewDelegateProxy.swift */; }; + EB29A867ADAF5659E0C48E5C4D8A450A /* Sync.swift in Sources */ = {isa = PBXBuildFile; fileRef = 697BC47AE64E2A2BC38671AAD282C4A4 /* Sync.swift */; }; + EC25AC8D0A5DCEC1CED82C041B9DD003 /* Sink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17329B719AEDE982C87AEB16E07F81DB /* Sink.swift */; }; + EC2C05D6ADBA912231F8410FA423231B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3C3AF2E791EE67E3DF385C1781D769A1 /* Foundation.framework */; }; + ECAE23D66E9EDF283A168176231FEDBD /* Observable+Bind.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA516D24BB56BA4C75C278EF40971A4A /* Observable+Bind.swift */; }; + ED3E0C98F7B39EF67FA8EDC302E94528 /* NopDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3A38977C4921EC3D67E5DC9A87F1E46 /* NopDisposable.swift */; }; + ED8EADDDCEC970199FC8CF2E8F70ACEA /* RLMSyncManager.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 2A659C5B4905F50CF069CBEC4BA23D5A /* RLMSyncManager.h */; }; + ED906ACD2E9F3C6DEA3A0B373A7A59F7 /* UIProgressView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1D7A021E82ABD94264468585CA188F2 /* UIProgressView+Rx.swift */; }; + EDAF0F759F933084FC54F9CFF660E5CB /* Disposables.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273D1C710EAED20857E1D3D9F2D58709 /* Disposables.swift */; }; + EDB338DD059F5447DBCF1289E353B2CB /* UIViewController+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4837AB0A4DF18729E0F0A4791CE14A1F /* UIViewController+Rx.swift */; }; + EDC93BD7B9262119AE145E4C7A9D0212 /* Request.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5EF5469A5815CD32CD6EDDCE7D18638E /* Request.swift */; }; + EE1C2E504E036D334BDE2EBBE58452D8 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3C3AF2E791EE67E3DF385C1781D769A1 /* Foundation.framework */; }; + EE6252936D0BC4DF4016D58AEDDCE2BA /* Queue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3888EEE9DD9958C44FE1090A609BF16F /* Queue.swift */; }; + EF379606D0834B984BBE54F532B2E2AC /* Sample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71C7AD37453C1150D3F33183FFB649B4 /* Sample.swift */; }; + EF8315A2DB22F71F180696A79E9FF10A /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42A4B9682D6833BEBF451FE680D4EAF3 /* Security.framework */; }; + EF8F15A02A01B3F72D709C006C92C5AF /* ObservableType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54CA22C46BEA679028DABD5E41774F7D /* ObservableType.swift */; }; + EFB73B383EE0B9D00BCD7CA7D84B3395 /* UIGestureRecognizer+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3AD1821877DA40E0007A480B71794B6 /* UIGestureRecognizer+Rx.swift */; }; + F01DFDF2060AB810B670CCB76AAEA85F /* RLMCollection.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0E90F43735FD12DCC9A88FD5186FF829 /* RLMCollection.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + F0BAF3ADF3EFB71158582B96DE71369B /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C11273D45259641CB6C9E72C2CF25B0 /* Errors.swift */; }; + F0F3224FF592F9BA2A044A2FC2BD4CCD /* Validation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0FFAF63ACD970F79684D7C896D99C860 /* Validation.swift */; }; + F0F7F7EB66C233DD559474AFEA7C10DF /* SharedSequence+Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE3831D5F8E37757EFBABC495A6FBCA7 /* SharedSequence+Operators.swift */; }; + F177DDB062A8B87A9B598A36B5E9B27F /* SerialDispatchQueueScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2191E9AE1CD599F32FC4A21A9D0518C /* SerialDispatchQueueScheduler.swift */; }; + F1B409D1BE71BBB170395E9121F0C67A /* RLMDecimal128.mm in Sources */ = {isa = PBXBuildFile; fileRef = CF42A2B7D6A7DE5BFD6EF860E0F25DAC /* RLMDecimal128.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + F1D0CF365F1C0EBBB9BE8D3B246AEA82 /* Completable+AndThen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7D8A38AE011A373694F41430F9242A03 /* Completable+AndThen.swift */; }; + F2343D5AA1F53A22738D26788BFAEE74 /* Using.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCFCAF09367C94F7CDBFE09DBB92CF09 /* Using.swift */; }; + F2CF55CAEDDD01EF9B402D0E3E0121DF /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDF43D98B673E5BD269472020316C22D /* Utils.swift */; }; + F2D2857797DF878132BA4026511F95D1 /* RLMSyncUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = C3B988408D8F0CA517A4AEEF864A7269 /* RLMSyncUtil.h */; }; + F3B9DB19F608BFC873563494E3314EC9 /* TakeLast.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBBFBD808747A32ABC0A9D48272095C /* TakeLast.swift */; }; + F3F7760BFC76C0A414395ED3DF1E6C90 /* RLMRealm+Sync.mm in Sources */ = {isa = PBXBuildFile; fileRef = A5FF27F873A36ADC87621F49D7A03109 /* RLMRealm+Sync.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + F427DF803EE73A3582492EB0161E0D8B /* thread_safe_reference.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C286E268C8D65C8396BF5333623B2BD8 /* thread_safe_reference.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + F4541139B83E4CE559A87E1FD2484323 /* _RXKVOObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 40B6058E10D64C4CDA4C4003E5F09318 /* _RXKVOObserver.m */; }; + F47689A031D0C57D3F9C93EB43854C7D /* sync_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1942CCAEE67C1D9C588B1197A0D9C2C8 /* sync_manager.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + F59A8162BEEDFF3B08D72F884E8C55FA /* RLMMongoCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = 747A3C76800A1F6EC0D6086DFC8CB10E /* RLMMongoCollection.h */; }; + F5AF9CF0B558FCD45C0DBFED149299EB /* RLMSyncConfiguration.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0E96D5A2409E16D07F6C178C89CA716A /* RLMSyncConfiguration.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + F612FD4FD9711510D62CDA9D9173AB72 /* Reduce.swift in Sources */ = {isa = PBXBuildFile; fileRef = 661DBD2189C578AADB4AD2ABECB572D6 /* Reduce.swift */; }; + F63BBD21E5DDFAB3973E0905D2301869 /* RLMConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = FB9B48285BCCDF74DAAC90326D85758F /* RLMConstants.m */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + F70EF854395CDE981A8336E4FF0310FE /* URLSessionConfiguration+Alamofire.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEE52232218966D95056A2B60A630CB3 /* URLSessionConfiguration+Alamofire.swift */; }; + F72A6848430F0D0900D4917EB5E08F60 /* AsMaybe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49F9716687BE37F18CD9BFE6A52FD2DA /* AsMaybe.swift */; }; + F7AE89A62372E2CD0D50D4F51A2923EE /* RLMObjectStore.h in Headers */ = {isa = PBXBuildFile; fileRef = ACD3F71760CCCD9557A8FF00B70177A6 /* RLMObjectStore.h */; }; + F820ACC051D239EF5BDE2C0FFF724196 /* remote_mongo_database.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD78931CCDDC97455EC35D57F5094C62 /* remote_mongo_database.cpp */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + F88602DEA5D139BDFF12CEDD838BE081 /* UILabel+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0A2AA962931BB09A9089FEC7D8A1E30 /* UILabel+Rx.swift */; }; + F9DEBDD0C6E5A2B7C90988C387E30CE3 /* CompositeDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D09D63DDBDEBE7C181B504886AC7819C /* CompositeDisposable.swift */; }; + F9E078483BA3FB0B5E8FDDD1F2C9B87E /* SchedulerServices+Emulation.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8FBEFAD40A3F50A73E9886A885DED2A /* SchedulerServices+Emulation.swift */; }; + FA10D52355237A25809F33035D187DAA /* RLMSyncUtil.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = C3B988408D8F0CA517A4AEEF864A7269 /* RLMSyncUtil.h */; }; + FA65E7A4D9D79B661920AC61E8663358 /* RLMSyncConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B7A5B0F7FA13D2ED0C0C194C5E8EECB /* RLMSyncConfiguration.h */; }; + FABEE77ACBAE6140333658A06BAF49E4 /* RLMCollection_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 880083C6631CCDD9FCFB3D3742A37D59 /* RLMCollection_Private.h */; }; + FB1F62B2A744B23A349CF8877CF2A09B /* RxPickerViewAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6659B577E42EF97A5FDF4BC0E77791C7 /* RxPickerViewAdapter.swift */; }; + FC136B129F9CD401CA9639D078B07967 /* Generate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98FB87ECA069BA6F525BE852477801F8 /* Generate.swift */; }; + FC674115A5CC3B1735233CDF98DBE616 /* StartWith.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7199CFB5B8CAFD358110536A33C227A4 /* StartWith.swift */; }; + FC7C7F9AB5C91F3E3B8E0A7AA9B4D223 /* RLMUserAPIKey.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1B0DAB86A5C35706335569585D6C0D74 /* RLMUserAPIKey.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.1.1\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + FCB07678FF31509D157300B7DC1240D6 /* KeyPathBinder.swift in Sources */ = {isa = PBXBuildFile; fileRef = D57411E3F5D1FE6F06C45BB8BE6ABAE9 /* KeyPathBinder.swift */; }; + FD121E214251E5B388161FA787E9399C /* NSObject+Rx+KVORepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D859A8A88C5A84E3E4AD9AD9B6B463C /* NSObject+Rx+KVORepresentable.swift */; }; + FD1FE0BE94202EE309BB5D85BDB3932D /* CurrentThreadScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE0507016D5F581EF3C0C205AAD4AAE3 /* CurrentThreadScheduler.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - 0F29B0C278670D8504AE57CE51EDBEF2 /* PBXContainerItemProxy */ = { + 07CCD94A97AF52489B095244FDBCCF6F /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; proxyType = 1; remoteGlobalIDString = EA9EA43B3B503823EE36C60D9C8A865F; remoteInfo = RxSwift; }; - 2ACF9674D82BFF1D31495413FF50DD23 /* PBXContainerItemProxy */ = { + 10E08D2D9480E949307AAED1C22C172D /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; proxyType = 1; remoteGlobalIDString = 4622BFEF3DC16E8BD15EEFC30D4D0084; remoteInfo = RxRelay; }; - 5F944B86754F6074923728E863E11840 /* PBXContainerItemProxy */ = { + 1860554BFE11E0F943E72F51F6001D91 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = EA9EA43B3B503823EE36C60D9C8A865F; + remoteInfo = RxSwift; + }; + 37927C6512BF1AF789EE56F26221F00D /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; proxyType = 1; remoteGlobalIDString = 7AD0C6DCDC9CEC8A3C7C10C7FEE07BE6; remoteInfo = RxCocoa; }; - 9C8C0873E0DB0190AD72C7AB067FC73A /* PBXContainerItemProxy */ = { + 55E20394D134B6C22391AACE5AF71D79 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; proxyType = 1; - remoteGlobalIDString = EAAA1AD3A8A1B59AB91319EE40752C6D; - remoteInfo = Alamofire; + remoteGlobalIDString = EA9EA43B3B503823EE36C60D9C8A865F; + remoteInfo = RxSwift; }; - BA7FBAFE7939C99EF033DB4127174511 /* PBXContainerItemProxy */ = { + 5EC2F6106AC9F6038CAF0BBA5729514B /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; proxyType = 1; - remoteGlobalIDString = 4622BFEF3DC16E8BD15EEFC30D4D0084; - remoteInfo = RxRelay; + remoteGlobalIDString = EAAA1AD3A8A1B59AB91319EE40752C6D; + remoteInfo = Alamofire; }; - D1377C6C3472BDAF4F1B0D7E86628961 /* PBXContainerItemProxy */ = { + 6B62F56D7627ECEE34134CBFF73B04A5 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; proxyType = 1; remoteGlobalIDString = EA9EA43B3B503823EE36C60D9C8A865F; remoteInfo = RxSwift; }; - E620670CEAC0FC8F38E8C50FAD755209 /* PBXContainerItemProxy */ = { + 7D9D933408532C30D0AD861AA38D722A /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; proxyType = 1; - remoteGlobalIDString = EA9EA43B3B503823EE36C60D9C8A865F; - remoteInfo = RxSwift; + remoteGlobalIDString = EAAA1AD3A8A1B59AB91319EE40752C6D; + remoteInfo = Alamofire; + }; + AB59AD30498E5E7F449A847BB4852D68 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 68494F30B4A13F8E5E88BCCAEC25B0A4; + remoteInfo = Realm; + }; + D656BA3D22E65ED3E91BD14EA3C0CE93 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 782725687624F8665247B84AB581BEB1; + remoteInfo = RealmSwift; + }; + E37A364E9D6514056B0B960F4A08AA28 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 1A538A5499B1706F0983D6826042657B; + remoteInfo = RxAlamofire; + }; + E66902C7B3AE87F045AE703402362FBB /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 4622BFEF3DC16E8BD15EEFC30D4D0084; + remoteInfo = RxRelay; + }; + F95C4147E772E613A5678E1753EC880D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 68494F30B4A13F8E5E88BCCAEC25B0A4; + remoteInfo = Realm; }; /* End PBXContainerItemProxy section */ +/* Begin PBXCopyFilesBuildPhase section */ + 99CD59F39DEDC66A21E7D0F56129F344 /* Copy . Private Headers */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "$(PRIVATE_HEADERS_FOLDER_PATH)/."; + dstSubfolderSpec = 16; + files = ( + 921D26E614D2A43E6751CD5FF0DEBD75 /* RLMAccessor.h in Copy . Private Headers */, + C5A893D1945A3A0DD752D8FB3EDA2612 /* RLMArray_Private.h in Copy . Private Headers */, + 33A759C846F948BF190307977D280B6F /* RLMCollection_Private.h in Copy . Private Headers */, + 1E6693A5E343846D3A8D19D736658252 /* RLMListBase.h in Copy . Private Headers */, + 5D2B7FABE62E81EF77EEA1B8674C94F0 /* RLMObject_Private.h in Copy . Private Headers */, + 4ACE3228A19503457AB5531F4E7F6584 /* RLMObjectBase_Private.h in Copy . Private Headers */, + 079ACFF0C3235A0036F810A41748F4E5 /* RLMObjectSchema_Private.h in Copy . Private Headers */, + 52AB2A253CD2210540A142AE0EE9A15D /* RLMObjectStore.h in Copy . Private Headers */, + 132A24458581E09588803195819CE5BD /* RLMOptionalBase.h in Copy . Private Headers */, + E1CF74AE8957B40E91B844413D6066C2 /* RLMProperty_Private.h in Copy . Private Headers */, + 6CE2A7E2B7213E955EF438FDAA4C1398 /* RLMRealm_Private.h in Copy . Private Headers */, + 3B08FAAEA2A8318BFD49EF5D29C8B4D5 /* RLMRealmConfiguration_Private.h in Copy . Private Headers */, + E54A0D88D0C4F20184E9098E69D1DC68 /* RLMResults_Private.h in Copy . Private Headers */, + 3E3E80C55D3CA6345AEC7BC6612870A8 /* RLMSchema_Private.h in Copy . Private Headers */, + 5CB1FBEC190E2884EE2375A8384C6B21 /* RLMSyncConfiguration_Private.h in Copy . Private Headers */, + 3052C14D4057BD71F1B253466C07C554 /* RLMSyncUtil_Private.h in Copy . Private Headers */, + ); + name = "Copy . Private Headers"; + runOnlyForDeploymentPostprocessing = 0; + }; + AACC4BE359EF2DF8E9DBBCB9DF2A6A67 /* Copy . Public Headers */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "$(PUBLIC_HEADERS_FOLDER_PATH)/."; + dstSubfolderSpec = 16; + files = ( + 079C94706B1DD67CBBBEAE3E93D3A68A /* NSError+RLMSync.h in Copy . Public Headers */, + 606F2310EC8680F89C422DF6B3AA250F /* Realm.h in Copy . Public Headers */, + 0FBB33BA94590A8B92E6C7CECE0C598E /* RLMAPIKeyAuth.h in Copy . Public Headers */, + DF574F8C2AF6A72F3406A273FAC49FF5 /* RLMApp.h in Copy . Public Headers */, + 058D11863C2D23349FCB3B416FC906CA /* RLMArray.h in Copy . Public Headers */, + 12F2C75009C7EA2AC378A96FC5A0F7B5 /* RLMBSON.h in Copy . Public Headers */, + A83C1EF6EB6B1905C8A79502DC061B8C /* RLMCollection.h in Copy . Public Headers */, + DD9C3275C29D5DEE7DF59E9F3C81E789 /* RLMConstants.h in Copy . Public Headers */, + 702DE8BBD6D168F3809535BE3F9C3045 /* RLMCredentials.h in Copy . Public Headers */, + DF74E6BDCDDA6B216A8A8FD19E53880E /* RLMDecimal128.h in Copy . Public Headers */, + D1335F3A26D985B2FD280505F3773779 /* RLMEmailPasswordAuth.h in Copy . Public Headers */, + E0DFE59E5EA05F8B9676024BE9601A20 /* RLMEmbeddedObject.h in Copy . Public Headers */, + 360B866D93BDDC8884DA633371E80B22 /* RLMFindOneAndModifyOptions.h in Copy . Public Headers */, + 91FC0BDA4438ADFD21EEE604C67107AB /* RLMFindOptions.h in Copy . Public Headers */, + 9B3A432265AF41500704ADBCB9C99DEF /* RLMListBase.h in Copy . Public Headers */, + 58DEB0E372F1D566ACA2DE6B11ED5158 /* RLMMigration.h in Copy . Public Headers */, + 06364C498350A28E887B7AEAADF536DA /* RLMMongoClient.h in Copy . Public Headers */, + 80A444704CE5CE018DA62ADC894EF15D /* RLMMongoCollection.h in Copy . Public Headers */, + 9EA4DDCE4B1E859C86D5541DE1C89293 /* RLMMongoDatabase.h in Copy . Public Headers */, + AC04774171C794FC6EE3572948B35189 /* RLMNetworkTransport.h in Copy . Public Headers */, + 690740100450EF9008CB489899165B38 /* RLMObject.h in Copy . Public Headers */, + 2A6BCB44D6A52ED857FCB3857A1611DE /* RLMObjectBase.h in Copy . Public Headers */, + 53D578268DF2CDD69DB114B286526A86 /* RLMObjectBase_Dynamic.h in Copy . Public Headers */, + A0F1126772F27032CB6A8E387F6412FC /* RLMObjectId.h in Copy . Public Headers */, + 71F53B95BD754FCBAC78A18A75420B73 /* RLMObjectSchema.h in Copy . Public Headers */, + 391AE2E1933A03748D21A9711DE5E32A /* RLMOptionalBase.h in Copy . Public Headers */, + 8CC77BA86B1597344C9804F1CCE6DB91 /* RLMPlatform.h in Copy . Public Headers */, + CC027472DC55A3C8DA9590A2F643D5AB /* RLMProperty.h in Copy . Public Headers */, + 8AE4D206A91C3C6926A30EEA746825E4 /* RLMProviderClient.h in Copy . Public Headers */, + B32DD267C91411A347168A5F47EFDE15 /* RLMPushClient.h in Copy . Public Headers */, + CF51770D45D6F6BB54BF6A00A52E12AE /* RLMRealm+Sync.h in Copy . Public Headers */, + D7E10DB3ABF6114CF827674F0043A39F /* RLMRealm.h in Copy . Public Headers */, + 698B1407BF56F779E3425902C9A49628 /* RLMRealm_Dynamic.h in Copy . Public Headers */, + E89494624801F6FE431482E5678CFC81 /* RLMRealmConfiguration+Sync.h in Copy . Public Headers */, + BD0FA67EC1C87F22197C5D52A722C5EC /* RLMRealmConfiguration.h in Copy . Public Headers */, + D101E2DDD33C5BDEE06582F7BBE87973 /* RLMResults.h in Copy . Public Headers */, + 6E98C877F675547622B217F5A0C6C7F1 /* RLMSchema.h in Copy . Public Headers */, + 7D0A23F4B6E8A0EEF7E2F53E708CE535 /* RLMSyncConfiguration.h in Copy . Public Headers */, + ED8EADDDCEC970199FC8CF2E8F70ACEA /* RLMSyncManager.h in Copy . Public Headers */, + 5F9857A5481F669FF3A03F175D5FB7F0 /* RLMSyncSession.h in Copy . Public Headers */, + FA10D52355237A25809F33035D187DAA /* RLMSyncUtil.h in Copy . Public Headers */, + CCAA35935527C95DC8E75C9BB246776A /* RLMThreadSafeReference.h in Copy . Public Headers */, + CD73C8E467BB51A2989CB40BB7552EE8 /* RLMUpdateResult.h in Copy . Public Headers */, + E07DDEA75EBEB870754939AC1A90CD2B /* RLMUser.h in Copy . Public Headers */, + 7941FAFEEF08562B4C9B608235E9F187 /* RLMUserAPIKey.h in Copy . Public Headers */, + ); + name = "Copy . Public Headers"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + /* Begin PBXFileReference section */ - 0013B094868C3362596DB752534FA46D /* Switch.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Switch.swift; path = RxSwift/Observables/Switch.swift; sourceTree = ""; }; - 00BFA1AFA8DBDD22DDA9DD08DF848644 /* UISwitch+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UISwitch+Rx.swift"; path = "RxCocoa/iOS/UISwitch+Rx.swift"; sourceTree = ""; }; - 01D78531DC748E29CAE6A300625FE73A /* NSTextStorage+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSTextStorage+Rx.swift"; path = "RxCocoa/iOS/NSTextStorage+Rx.swift"; sourceTree = ""; }; - 02BD2CD95E38D6D07BFF1A50CEC190D6 /* Materialize.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Materialize.swift; path = RxSwift/Observables/Materialize.swift; sourceTree = ""; }; - 035E0AE5379C0D0DF641A79DF7AFC5B5 /* Sequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Sequence.swift; path = RxSwift/Observables/Sequence.swift; sourceTree = ""; }; - 04C814DE3552E1C0885EB29AE5F93775 /* Window.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Window.swift; path = RxSwift/Observables/Window.swift; sourceTree = ""; }; - 0555E02157B458CA4C5B3AE6D65FCD3F /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.2.sdk/System/Library/Frameworks/CFNetwork.framework; sourceTree = DEVELOPER_DIR; }; - 0672041CFD2E8E368862BC23B86B5FC6 /* Skip.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Skip.swift; path = RxSwift/Observables/Skip.swift; sourceTree = ""; }; - 08877CA69F0BFBF0E65E49E70100C379 /* DispatchQueue+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "DispatchQueue+Extensions.swift"; path = "Platform/DispatchQueue+Extensions.swift"; sourceTree = ""; }; - 0A7EABE903FA94A1A4C7BCE0C7FA3792 /* Throttle.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Throttle.swift; path = RxSwift/Observables/Throttle.swift; sourceTree = ""; }; - 0C4466009D7802687DC3BAB221CDD73F /* KVORepresentable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = KVORepresentable.swift; path = RxCocoa/Foundation/KVORepresentable.swift; sourceTree = ""; }; - 0D82BAC61F2EC7EFD05AB9698294168C /* ElementAt.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ElementAt.swift; path = RxSwift/Observables/ElementAt.swift; sourceTree = ""; }; - 0E85F83E3D8DC015C0BB6EE0E366E7F7 /* RxTableViewDataSourceProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTableViewDataSourceProxy.swift; path = RxCocoa/iOS/Proxies/RxTableViewDataSourceProxy.swift; sourceTree = ""; }; - 0EE5C65DE35ECFA7A169D5510D5465E3 /* ObserverBase.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObserverBase.swift; path = RxSwift/Observers/ObserverBase.swift; sourceTree = ""; }; - 0F67A48D75B65978C9945E4A75695F2A /* Never.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Never.swift; path = RxSwift/Observables/Never.swift; sourceTree = ""; }; - 0F93ED208D338D0391C8DAA1B16D9F1B /* RxTextStorageDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTextStorageDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxTextStorageDelegateProxy.swift; sourceTree = ""; }; - 1111B7A662732DE1675B573658011958 /* UIPickerView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIPickerView+Rx.swift"; path = "RxCocoa/iOS/UIPickerView+Rx.swift"; sourceTree = ""; }; - 1201972BFD824158C893EEEB86C162B4 /* Scan.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Scan.swift; path = RxSwift/Observables/Scan.swift; sourceTree = ""; }; - 12D504CEC3F2DA1041E43AFAE3A3CE89 /* Dematerialize.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Dematerialize.swift; path = RxSwift/Observables/Dematerialize.swift; sourceTree = ""; }; - 12E97525EE22ADCF0B33275E0AD936D9 /* OperationQueueScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = OperationQueueScheduler.swift; path = RxSwift/Schedulers/OperationQueueScheduler.swift; sourceTree = ""; }; - 12EC4A82840213156D80A772AC628749 /* RxTarget.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTarget.swift; path = RxCocoa/Common/RxTarget.swift; sourceTree = ""; }; - 13A19DFD85A5A97950972F5201F6BEDC /* SubscribeOn.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SubscribeOn.swift; path = RxSwift/Observables/SubscribeOn.swift; sourceTree = ""; }; - 13DF7EFF2C06C91C70FBB6FDCE714A0A /* ItemEvents.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ItemEvents.swift; path = RxCocoa/iOS/Events/ItemEvents.swift; sourceTree = ""; }; - 144449BF4EA97422477E85516C12E4BD /* Utils.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Utils.swift; path = RxRelay/Utils.swift; sourceTree = ""; }; - 14B18705C3C90C8DA76954AF87DFEAFF /* RxSearchControllerDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxSearchControllerDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxSearchControllerDelegateProxy.swift; sourceTree = ""; }; - 14F9E1DCBECDDD03F849344E1F7DEB4B /* RxCollectionViewDataSourcePrefetchingProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxCollectionViewDataSourcePrefetchingProxy.swift; path = RxCocoa/iOS/Proxies/RxCollectionViewDataSourcePrefetchingProxy.swift; sourceTree = ""; }; - 1512A6A21B4C585CBD85B24F18ECAAB5 /* UIImageView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIImageView+Rx.swift"; path = "RxCocoa/iOS/UIImageView+Rx.swift"; sourceTree = ""; }; - 1591824CD4A57EFF831752B2B7707D77 /* ObservableConvertibleType+Signal.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ObservableConvertibleType+Signal.swift"; path = "RxCocoa/Traits/Signal/ObservableConvertibleType+Signal.swift"; sourceTree = ""; }; - 169AAA422E46B126BBAD577E53742277 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.2.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; - 1751F9AB9C2E25B9A71A82CDE9604A55 /* First.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = First.swift; path = RxSwift/Observables/First.swift; sourceTree = ""; }; - 17612A8C6862BA406B34D6804B974582 /* SkipUntil.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SkipUntil.swift; path = RxSwift/Observables/SkipUntil.swift; sourceTree = ""; }; - 17C92B3843A03204045F53BC32AE8085 /* NSControl+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSControl+Rx.swift"; path = "RxCocoa/macOS/NSControl+Rx.swift"; sourceTree = ""; }; - 185C3CBCE6CB4F1F71D86AE370EA8EA2 /* RxTableViewReactiveArrayDataSource.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTableViewReactiveArrayDataSource.swift; path = RxCocoa/iOS/DataSources/RxTableViewReactiveArrayDataSource.swift; sourceTree = ""; }; - 1918212E050BE431A6831619552F853A /* RxRelay-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RxRelay-prefix.pch"; sourceTree = ""; }; - 1946A1418516CE741E8B311BC7C2E91A /* UISegmentedControl+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UISegmentedControl+Rx.swift"; path = "RxCocoa/iOS/UISegmentedControl+Rx.swift"; sourceTree = ""; }; - 194A03463DA0EA64C8D837D89C6AE963 /* ObservableConvertibleType+Driver.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ObservableConvertibleType+Driver.swift"; path = "RxCocoa/Traits/Driver/ObservableConvertibleType+Driver.swift"; sourceTree = ""; }; - 1A95BD137A895FECF14F78F441F63293 /* RxSwift.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = RxSwift.modulemap; sourceTree = ""; }; - 1A9C779046CE2DFB9920B383771BF3E8 /* DisposeBase.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DisposeBase.swift; path = RxSwift/Disposables/DisposeBase.swift; sourceTree = ""; }; - 1C4249898DAC7D8426ECFEB9568ECE08 /* CombineLatest+Collection.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "CombineLatest+Collection.swift"; path = "RxSwift/Observables/CombineLatest+Collection.swift"; sourceTree = ""; }; - 1D7F5512735FA9C93F058AB1204177B7 /* Completable+AndThen.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Completable+AndThen.swift"; path = "RxSwift/Traits/Completable+AndThen.swift"; sourceTree = ""; }; - 1DBBEBCD60ACE2D70FF6C9BCDA9AE8D3 /* RxSwift-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "RxSwift-Info.plist"; sourceTree = ""; }; - 1DC46D98E3D4A6854B4D3ACD807CDFE2 /* RxSwift.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = RxSwift.debug.xcconfig; sourceTree = ""; }; - 1EEF839E1B9A94BD94894E8610B796B2 /* SharedSequence+Operators+arity.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "SharedSequence+Operators+arity.swift"; path = "RxCocoa/Traits/SharedSequence/SharedSequence+Operators+arity.swift"; sourceTree = ""; }; - 1F18C9B7B688EDE42CA6057820E17CF4 /* Using.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Using.swift; path = RxSwift/Observables/Using.swift; sourceTree = ""; }; - 201FBAFD4A9D9FD6A838B9F963C76795 /* AuthenticationInterceptor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AuthenticationInterceptor.swift; path = Source/AuthenticationInterceptor.swift; sourceTree = ""; }; - 2053CBA7F32D1B5DD6A732548723F7CA /* Error.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Error.swift; path = RxSwift/Observables/Error.swift; sourceTree = ""; }; - 214A58EDDB0F4A08D69BC72243ACE4A8 /* AnonymousDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AnonymousDisposable.swift; path = RxSwift/Disposables/AnonymousDisposable.swift; sourceTree = ""; }; - 2159023945A21C8A29D239741B1B810E /* UINavigationItem+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UINavigationItem+Rx.swift"; path = "RxCocoa/iOS/UINavigationItem+Rx.swift"; sourceTree = ""; }; - 225CD57AAC4DAEE8605668C406DE44C3 /* ControlProperty.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ControlProperty.swift; path = RxCocoa/Traits/ControlProperty.swift; sourceTree = ""; }; - 22CF210C57601A6AE86C178E90663A6A /* NSSlider+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSSlider+Rx.swift"; path = "RxCocoa/macOS/NSSlider+Rx.swift"; sourceTree = ""; }; - 247F0BADDB1F0001E7029E0B9B69BEEF /* ReplaySubject.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ReplaySubject.swift; path = RxSwift/Subjects/ReplaySubject.swift; sourceTree = ""; }; - 248FFF5E776294F366C883410A62F0FC /* RxTableViewDataSourceType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTableViewDataSourceType.swift; path = RxCocoa/iOS/Protocols/RxTableViewDataSourceType.swift; sourceTree = ""; }; - 24C9AE967D758E6AB98C25E5D66EE0A2 /* ControlEvent.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ControlEvent.swift; path = RxCocoa/Traits/ControlEvent.swift; sourceTree = ""; }; - 2647AC98C4E44EA259D099263375ABA1 /* Generate.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Generate.swift; path = RxSwift/Observables/Generate.swift; sourceTree = ""; }; - 264FA160F97784840AFDE866D4E3409D /* Result+Alamofire.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Result+Alamofire.swift"; path = "Source/Result+Alamofire.swift"; sourceTree = ""; }; - 2671F655EE04D6C0885DE056312A4A03 /* HTTPMethod.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HTTPMethod.swift; path = Source/HTTPMethod.swift; sourceTree = ""; }; + 006BF5370268B8E8C77AC37824764B9A /* DelaySubscription.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DelaySubscription.swift; path = RxSwift/Observables/DelaySubscription.swift; sourceTree = ""; }; + 00A74A3256B9E1379A4DD01AD0BC8511 /* RLMFindOneAndModifyOptions.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMFindOneAndModifyOptions.mm; path = Realm/RLMFindOneAndModifyOptions.mm; sourceTree = ""; }; + 01249979DC8733446D96910BD960244A /* Realm.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Realm.swift; path = RealmSwift/Realm.swift; sourceTree = ""; }; + 01E829750D016D1BB8739C7D6C8B7E1C /* RLMThreadSafeReference.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMThreadSafeReference.h; path = include/RLMThreadSafeReference.h; sourceTree = ""; }; + 0217DDBDC78233930E7B2D4B10A4EF00 /* Sequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Sequence.swift; path = RxSwift/Observables/Sequence.swift; sourceTree = ""; }; + 02AC92A155B36A82731B0043B39919A6 /* RLMAPIKeyAuth.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMAPIKeyAuth.h; path = include/RLMAPIKeyAuth.h; sourceTree = ""; }; + 035A8B85F74A119913219BDD87EEBCFB /* ObjectiveCSupport.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObjectiveCSupport.swift; path = RealmSwift/ObjectiveCSupport.swift; sourceTree = ""; }; + 0414807C36F0D262CF9B76EFEB7C975B /* Optional.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Optional.swift; path = RxSwift/Observables/Optional.swift; sourceTree = ""; }; + 058AEEE4D4897A46CF0584F64E3439FF /* ThreadSafeReference.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ThreadSafeReference.swift; path = RealmSwift/ThreadSafeReference.swift; sourceTree = ""; }; + 06451B56A62C8C7862514E9B02C54DCB /* RxAlamofire-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RxAlamofire-prefix.pch"; sourceTree = ""; }; + 0691AAD52FD34400A3BF78A3A24A58B3 /* UIApplication+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIApplication+Rx.swift"; path = "RxCocoa/iOS/UIApplication+Rx.swift"; sourceTree = ""; }; + 07156FB16C3FAFFC2E1D0A15BDC44256 /* RLMMigration.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMMigration.mm; path = Realm/RLMMigration.mm; sourceTree = ""; }; + 07EDFC981426B815ACDAA00D3F9F3621 /* BehaviorSubject.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BehaviorSubject.swift; path = RxSwift/Subjects/BehaviorSubject.swift; sourceTree = ""; }; + 089F8F00402B7AD96A67301E78DE0707 /* ResponseSerialization.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ResponseSerialization.swift; path = Source/ResponseSerialization.swift; sourceTree = ""; }; + 099B959E823B66AD38AAE961201FBEE2 /* SectionedViewDataSourceType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SectionedViewDataSourceType.swift; path = RxCocoa/Common/SectionedViewDataSourceType.swift; sourceTree = ""; }; + 09A35B0CB777BBD88B9DEF06B2BCD249 /* RxNavigationControllerDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxNavigationControllerDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxNavigationControllerDelegateProxy.swift; sourceTree = ""; }; + 09D0F36C487638509F0A7E3BC5B96C2C /* RxTarget.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTarget.swift; path = RxCocoa/Common/RxTarget.swift; sourceTree = ""; }; + 09E025DA5339A8DFF424471D99726054 /* KVORepresentable+Swift.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "KVORepresentable+Swift.swift"; path = "RxCocoa/Foundation/KVORepresentable+Swift.swift"; sourceTree = ""; }; + 0A113A1381D58B977ABC03AF0C169267 /* external_commit_helper.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = external_commit_helper.cpp; path = Realm/ObjectStore/src/impl/apple/external_commit_helper.cpp; sourceTree = ""; }; + 0A69D6A299ACFC1ACBA8B6D05065F9B0 /* RealmSwift-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RealmSwift-umbrella.h"; sourceTree = ""; }; + 0AD4B936BBEA39E12AF6795CED6E9EBA /* RLMBSON.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMBSON.h; path = include/RLMBSON.h; sourceTree = ""; }; + 0B812574628875C8E875DEF8AC3C3B14 /* _RXKVOObserver.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = _RXKVOObserver.h; path = RxCocoa/Runtime/include/_RXKVOObserver.h; sourceTree = ""; }; + 0BA872B8A6E73C01CAEEF644283CAADE /* RealmSwift.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = RealmSwift.modulemap; sourceTree = ""; }; + 0D6E0185990293F9B45806EBD2A593FF /* RequestInterceptor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RequestInterceptor.swift; path = Source/RequestInterceptor.swift; sourceTree = ""; }; + 0D8B391ECFBBB1D945E878B3A2DB5B1C /* list_notifier.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = list_notifier.cpp; path = Realm/ObjectStore/src/impl/list_notifier.cpp; sourceTree = ""; }; + 0E90F43735FD12DCC9A88FD5186FF829 /* RLMCollection.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMCollection.mm; path = Realm/RLMCollection.mm; sourceTree = ""; }; + 0E96D5A2409E16D07F6C178C89CA716A /* RLMSyncConfiguration.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMSyncConfiguration.mm; path = Realm/RLMSyncConfiguration.mm; sourceTree = ""; }; + 0EBBFBD808747A32ABC0A9D48272095C /* TakeLast.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TakeLast.swift; path = RxSwift/Observables/TakeLast.swift; sourceTree = ""; }; + 0EFA3387D6930CFB27424B1C2E421920 /* RealmSwift-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "RealmSwift-dummy.m"; sourceTree = ""; }; + 0F212D9E7E87950A9A19CF27D66D6E11 /* RecursiveLock.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RecursiveLock.swift; path = Platform/RecursiveLock.swift; sourceTree = ""; }; + 0F38E046E0CD2CB36147067CD98085F7 /* ShareReplayScope.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ShareReplayScope.swift; path = RxSwift/Observables/ShareReplayScope.swift; sourceTree = ""; }; + 0F568642989B09534F4E2CF34ADE834D /* SynchronizedUnsubscribeType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SynchronizedUnsubscribeType.swift; path = RxSwift/Concurrency/SynchronizedUnsubscribeType.swift; sourceTree = ""; }; + 0FFAF63ACD970F79684D7C896D99C860 /* Validation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Validation.swift; path = Source/Validation.swift; sourceTree = ""; }; + 1015A80CA0CD30BE28E2D2A3C0F657AB /* Zip.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Zip.swift; path = RxSwift/Observables/Zip.swift; sourceTree = ""; }; + 1047C1ADAC0CEC50E0BD02F90744FF8F /* RxCocoa.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RxCocoa.h; path = RxCocoa/RxCocoa.h; sourceTree = ""; }; + 10B64935EC02FE6B379CB2F93E79814A /* ParameterEncoding.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ParameterEncoding.swift; path = Source/ParameterEncoding.swift; sourceTree = ""; }; + 11A904EC64DFA23BCEB1F41261404EC4 /* _RXObjCRuntime.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = _RXObjCRuntime.m; path = RxCocoa/Runtime/_RXObjCRuntime.m; sourceTree = ""; }; + 123A19C0627E923D071BEE6553C1E5FA /* object_store.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = object_store.cpp; path = Realm/ObjectStore/src/object_store.cpp; sourceTree = ""; }; + 13116BBDD71E1181921DE495E7CDA6BC /* Debounce.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Debounce.swift; path = RxSwift/Observables/Debounce.swift; sourceTree = ""; }; + 1353548A4397B700D6C86BF0E496F8C3 /* RLMObject.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMObject.h; path = include/RLMObject.h; sourceTree = ""; }; + 1427066B3F5B6E4ED399EB45CD534C6A /* Completable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Completable.swift; path = RxSwift/Traits/Completable.swift; sourceTree = ""; }; + 154052D7E94D80A2BCB9C64AAF2548E2 /* RxCocoa-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "RxCocoa-Info.plist"; sourceTree = ""; }; + 15832563E5BD805727075DD666DFCC6C /* Just.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Just.swift; path = RxSwift/Observables/Just.swift; sourceTree = ""; }; + 15B15F53FD84C0A717006B124E115B1C /* ObjectiveCSupport+BSON.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ObjectiveCSupport+BSON.swift"; path = "RealmSwift/ObjectiveCSupport+BSON.swift"; sourceTree = ""; }; + 172C400CF391EDD3C0F55DA942FFD7AA /* Realm-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Realm-dummy.m"; sourceTree = ""; }; + 17329B719AEDE982C87AEB16E07F81DB /* Sink.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Sink.swift; path = RxSwift/Observables/Sink.swift; sourceTree = ""; }; + 17B9A7F92B5A3E3A3F255E74F08E50FA /* BehaviorRelay+Driver.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "BehaviorRelay+Driver.swift"; path = "RxCocoa/Traits/Driver/BehaviorRelay+Driver.swift"; sourceTree = ""; }; + 1942CCAEE67C1D9C588B1197A0D9C2C8 /* sync_manager.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = sync_manager.cpp; path = Realm/ObjectStore/src/sync/sync_manager.cpp; sourceTree = ""; }; + 1968A5FAFECDCC7C761C774AF269DD2F /* Results.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Results.swift; path = RealmSwift/Results.swift; sourceTree = ""; }; + 19BA186E169315ABC1A14BB2D6C4B102 /* _RX.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = _RX.h; path = RxCocoa/Runtime/include/_RX.h; sourceTree = ""; }; + 1A33295D5CA69066CEB503EAD303E41D /* OperationQueueScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = OperationQueueScheduler.swift; path = RxSwift/Schedulers/OperationQueueScheduler.swift; sourceTree = ""; }; + 1A8BDABAB4E71F301AF4556EADC00F11 /* URLEncodedFormEncoder.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = URLEncodedFormEncoder.swift; path = Source/URLEncodedFormEncoder.swift; sourceTree = ""; }; + 1AC464F34523709BD1E60BA27CDE8842 /* keychain_helper.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = keychain_helper.cpp; path = Realm/ObjectStore/src/impl/apple/keychain_helper.cpp; sourceTree = ""; }; + 1B0DAB86A5C35706335569585D6C0D74 /* RLMUserAPIKey.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMUserAPIKey.mm; path = Realm/RLMUserAPIKey.mm; sourceTree = ""; }; + 1BBAA07630A36165CB5BFE215FF727E2 /* RxSwift.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = RxSwift.release.xcconfig; sourceTree = ""; }; + 1C16195CFF5969D14EC6DEA689F73205 /* RLMMigration.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMMigration.h; path = include/RLMMigration.h; sourceTree = ""; }; + 1C8B3A7FA064FA49FA28D62F6971AD96 /* RLMListBase.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMListBase.h; path = include/RLMListBase.h; sourceTree = ""; }; + 1C976161CEA8E0CD52FB77B418D4EDA1 /* HistoricalScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HistoricalScheduler.swift; path = RxSwift/Schedulers/HistoricalScheduler.swift; sourceTree = ""; }; + 1CD2BC359B1E50F0F0731770BCA42949 /* RealmCollection.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RealmCollection.swift; path = RealmSwift/RealmCollection.swift; sourceTree = ""; }; + 1CD4CA3CDAD3FB75BCFEA79F132F3357 /* SingleAsync.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SingleAsync.swift; path = RxSwift/Observables/SingleAsync.swift; sourceTree = ""; }; + 1E1356395FE392C74DC067DC515B2E84 /* ObservableConvertibleType+Signal.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ObservableConvertibleType+Signal.swift"; path = "RxCocoa/Traits/Signal/ObservableConvertibleType+Signal.swift"; sourceTree = ""; }; + 1E9AA4AE06C1A4752179DC22A2DA027C /* Deprecated.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Deprecated.swift; path = RxSwift/Deprecated.swift; sourceTree = ""; }; + 1EA27B0FA2BCDEE2E68302FE74F36B0F /* ReplaySubject.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ReplaySubject.swift; path = RxSwift/Subjects/ReplaySubject.swift; sourceTree = ""; }; + 1F013734C88EBE1D69DEAD484ECADACE /* collection_notifier.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = collection_notifier.cpp; path = Realm/ObjectStore/src/impl/collection_notifier.cpp; sourceTree = ""; }; + 202EAEE640EB38B4F0DFDFD11149CDB4 /* RxSwift-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RxSwift-umbrella.h"; sourceTree = ""; }; + 2034C81E59E1F1EF6E36D917E0936861 /* Result+Alamofire.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Result+Alamofire.swift"; path = "Source/Result+Alamofire.swift"; sourceTree = ""; }; + 21154A52CE37F60FB2E8149FB1B840DF /* RLMEmbeddedObject.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMEmbeddedObject.h; path = include/RLMEmbeddedObject.h; sourceTree = ""; }; + 21346E0C05D36D3AD36B91ACB9011DD0 /* Amb.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Amb.swift; path = RxSwift/Observables/Amb.swift; sourceTree = ""; }; + 22C6AE88E774A68F4D2348DE664A96A9 /* SchedulerType+SharedSequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "SchedulerType+SharedSequence.swift"; path = "RxCocoa/Traits/SharedSequence/SchedulerType+SharedSequence.swift"; sourceTree = ""; }; + 23131B8059FE945B73FC34E46F907CD3 /* ScheduledDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ScheduledDisposable.swift; path = RxSwift/Disposables/ScheduledDisposable.swift; sourceTree = ""; }; + 23B95E3E4BB5C2C0F727D6DCAA4EFD16 /* RLMResults.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMResults.mm; path = Realm/RLMResults.mm; sourceTree = ""; }; + 24A78EE46C9AB6747F7EAE6E3FDA5DD3 /* MultipartFormData.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MultipartFormData.swift; path = Source/MultipartFormData.swift; sourceTree = ""; }; + 24BE49CFC9CEDC6E3FB1D1D9519FFB6D /* RLMRealmConfiguration+Sync.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "RLMRealmConfiguration+Sync.h"; path = "include/RLMRealmConfiguration+Sync.h"; sourceTree = ""; }; + 25160B7A5A95101435E2C635A22B4B66 /* NSSlider+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSSlider+Rx.swift"; path = "RxCocoa/macOS/NSSlider+Rx.swift"; sourceTree = ""; }; + 2550C023355B7965233A026416E78B0E /* DisposeBag.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DisposeBag.swift; path = RxSwift/Disposables/DisposeBag.swift; sourceTree = ""; }; + 2574918564F0C7583E08ECC28A77617E /* Zip+Collection.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Zip+Collection.swift"; path = "RxSwift/Observables/Zip+Collection.swift"; sourceTree = ""; }; + 2678655DA16D1C91C49D41DFDA5870FA /* RxRelay.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RxRelay.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 271BA88AC2355AE18AC1B121E0E92300 /* Pods-Darner-dan-uh-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-Darner-dan-uh-umbrella.h"; sourceTree = ""; }; - 29A777BD3705A34957AB2A6F52F7C8B9 /* UIButton+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIButton+Rx.swift"; path = "RxCocoa/iOS/UIButton+Rx.swift"; sourceTree = ""; }; - 29C241C94E36BC9D91A93A0A7A171DBD /* SchedulerType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SchedulerType.swift; path = RxSwift/SchedulerType.swift; sourceTree = ""; }; - 2A045B4142C036B090AF9E5756BB4564 /* DispatchQueue+Alamofire.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "DispatchQueue+Alamofire.swift"; path = "Source/DispatchQueue+Alamofire.swift"; sourceTree = ""; }; - 2AB367DA9D4CDE24360F2925BA4C2586 /* PriorityQueue.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PriorityQueue.swift; path = Platform/DataStructures/PriorityQueue.swift; sourceTree = ""; }; - 2AE26FCFCEC8888CF9E2D904C2DEA925 /* InfiniteSequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = InfiniteSequence.swift; path = Platform/DataStructures/InfiniteSequence.swift; sourceTree = ""; }; - 2C25F1A4546932BF5BD6CDB8F6D03DE9 /* RequestInterceptor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RequestInterceptor.swift; path = Source/RequestInterceptor.swift; sourceTree = ""; }; - 2D3DB0FAE03FDA2754ED33CD92F81F37 /* Create.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Create.swift; path = RxSwift/Observables/Create.swift; sourceTree = ""; }; - 2DFCDEDCDD5FC14895A9DD21AD8A2F2B /* LockOwnerType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LockOwnerType.swift; path = RxSwift/Concurrency/LockOwnerType.swift; sourceTree = ""; }; - 2E187C471E348C73FE75C9A27421B443 /* Alamofire.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Alamofire.debug.xcconfig; sourceTree = ""; }; - 2F5BD2B31A5F1E29F8CDF82E49560F2C /* Zip.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Zip.swift; path = RxSwift/Observables/Zip.swift; sourceTree = ""; }; - 313153C53456E2FB1F84D5E8C9ED46FC /* Alamofire-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Alamofire-prefix.pch"; sourceTree = ""; }; - 32835977A2758FB8C93C35BC8AF41145 /* Alamofire.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = Alamofire.modulemap; sourceTree = ""; }; - 329C2C237E5807C5D2E690EF5670A8FD /* RxTabBarDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTabBarDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxTabBarDelegateProxy.swift; sourceTree = ""; }; - 32D297EFE0811B032CE8EA6F153CDF2E /* RecursiveLock.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RecursiveLock.swift; path = Platform/RecursiveLock.swift; sourceTree = ""; }; - 3316846B050A463A0CBDF297D8B28ED3 /* UIRefreshControl+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIRefreshControl+Rx.swift"; path = "RxCocoa/iOS/UIRefreshControl+Rx.swift"; sourceTree = ""; }; - 33861B0287E2C5260CA418BDE89B675D /* Amb.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Amb.swift; path = RxSwift/Observables/Amb.swift; sourceTree = ""; }; - 35959D5AA25F9D8D128B66392E2910EC /* RxPickerViewDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxPickerViewDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxPickerViewDelegateProxy.swift; sourceTree = ""; }; - 3596906DE866446245B777C72B463CA7 /* NSLayoutConstraint+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSLayoutConstraint+Rx.swift"; path = "RxCocoa/Common/NSLayoutConstraint+Rx.swift"; sourceTree = ""; }; + 273D1C710EAED20857E1D3D9F2D58709 /* Disposables.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Disposables.swift; path = RxSwift/Disposables/Disposables.swift; sourceTree = ""; }; + 2792D1140DA9A6D5A0AE6C7D26CE34DE /* RLMArray.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMArray.h; path = include/RLMArray.h; sourceTree = ""; }; + 27B03A18EA69A32F4FCD8E7A5D342674 /* Catch.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Catch.swift; path = RxSwift/Observables/Catch.swift; sourceTree = ""; }; + 27B99BE284348A1148EC9971A44FE17A /* RLMObjectBase.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMObjectBase.mm; path = Realm/RLMObjectBase.mm; sourceTree = ""; }; + 27C2257CED81A269B4F3CFD395A737F8 /* SubscribeOn.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SubscribeOn.swift; path = RxSwift/Observables/SubscribeOn.swift; sourceTree = ""; }; + 29043CE1FADE4EECB264248CA6136275 /* UISearchBar+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UISearchBar+Rx.swift"; path = "RxCocoa/iOS/UISearchBar+Rx.swift"; sourceTree = ""; }; + 29622D1F2C8710735FC606C6C7AB068C /* RLMFindOptions.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMFindOptions.mm; path = Realm/RLMFindOptions.mm; sourceTree = ""; }; + 296C69A8DA05E42FC09D7342DEA5E30D /* ObservableConvertibleType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObservableConvertibleType.swift; path = RxSwift/ObservableConvertibleType.swift; sourceTree = ""; }; + 299B1BEACD3DC873914E50E57C3E4F43 /* Platform.Darwin.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Platform.Darwin.swift; path = Platform/Platform.Darwin.swift; sourceTree = ""; }; + 2A1F51107743C21D53321F2E4C3C2B12 /* Alamofire-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Alamofire-umbrella.h"; sourceTree = ""; }; + 2A659C5B4905F50CF069CBEC4BA23D5A /* RLMSyncManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMSyncManager.h; path = include/RLMSyncManager.h; sourceTree = ""; }; + 2A784BB19543BE7255AA56FA7E88E1E0 /* GroupBy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = GroupBy.swift; path = RxSwift/Observables/GroupBy.swift; sourceTree = ""; }; + 2AE4ED8FA170DF993930A077F70FA6E7 /* RLMProperty.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMProperty.h; path = include/RLMProperty.h; sourceTree = ""; }; + 2AE88125C2D485771098E31F97DB791B /* RxRelay.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = RxRelay.modulemap; sourceTree = ""; }; + 2B1917E6A743DBE3D87B9043CACA8435 /* UITabBar+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UITabBar+Rx.swift"; path = "RxCocoa/iOS/UITabBar+Rx.swift"; sourceTree = ""; }; + 2BD4FCE00CFCBE8E98C06E5C3A0495E7 /* scheduler.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = scheduler.cpp; path = Realm/ObjectStore/src/util/scheduler.cpp; sourceTree = ""; }; + 2C227BE1AC1012FDEA2508280A710B85 /* EmbeddedObject.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = EmbeddedObject.swift; path = RealmSwift/EmbeddedObject.swift; sourceTree = ""; }; + 2D244D7B1DC3CBCF25A32DD82D7F612D /* RxCollectionViewDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxCollectionViewDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxCollectionViewDelegateProxy.swift; sourceTree = ""; }; + 2E317DE1BFFB70C4D5832975F2922B01 /* RxTextViewDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTextViewDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxTextViewDelegateProxy.swift; sourceTree = ""; }; + 2E3BFA2B1FE0ED598F6CD11830FCC6EA /* realm_coordinator.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = realm_coordinator.cpp; path = Realm/ObjectStore/src/impl/realm_coordinator.cpp; sourceTree = ""; }; + 2EA417896E98F2FA28958FEFBBFAC5B2 /* RequestTaskMap.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RequestTaskMap.swift; path = Source/RequestTaskMap.swift; sourceTree = ""; }; + 2EA875143B8C27199FCF997B7DB5F566 /* RxRelay.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = RxRelay.release.xcconfig; sourceTree = ""; }; + 2EC0428FE529F2A45EE29C2AAD2A467C /* RLMBSON.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMBSON.mm; path = Realm/RLMBSON.mm; sourceTree = ""; }; + 2EFFF14B7584C9C947179DA2BC659A44 /* RLMProviderClient.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMProviderClient.mm; path = Realm/RLMProviderClient.mm; sourceTree = ""; }; + 30B878398E136A1052ECEC59EB9A252D /* RLMRealmConfiguration.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMRealmConfiguration.h; path = include/RLMRealmConfiguration.h; sourceTree = ""; }; + 31099800731F7C7C9E93FCD519007B12 /* CompactMap.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CompactMap.swift; path = RxSwift/Observables/CompactMap.swift; sourceTree = ""; }; + 321F4B543D57E15D74C5F63616BD9783 /* ObservableConvertibleType+SharedSequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ObservableConvertibleType+SharedSequence.swift"; path = "RxCocoa/Traits/SharedSequence/ObservableConvertibleType+SharedSequence.swift"; sourceTree = ""; }; + 339215A49D0EE00F18DAD73C85C8CB04 /* RLMCollection.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMCollection.h; path = include/RLMCollection.h; sourceTree = ""; }; + 339AE1A23AF8CB3EC9886CBBF610FEA6 /* RxAlamofire.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = RxAlamofire.debug.xcconfig; sourceTree = ""; }; + 3489ECAB322E95680C288808406928E2 /* RLMUpdateChecker.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMUpdateChecker.mm; path = Realm/RLMUpdateChecker.mm; sourceTree = ""; }; + 351FE5E0BB710A20BA562FAA785B977A /* RxSwift.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = RxSwift.modulemap; sourceTree = ""; }; + 355631D0FA9773D3CBAD76E466F848DE /* ObserverBase.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObserverBase.swift; path = RxSwift/Observers/ObserverBase.swift; sourceTree = ""; }; + 357BCD5C989B4B1386A6534171E16B6B /* object.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = object.cpp; path = Realm/ObjectStore/src/object.cpp; sourceTree = ""; }; 35ABD25029216D858A8EE7DBA6C58080 /* Pods-Darner-dan-uh-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-Darner-dan-uh-Info.plist"; sourceTree = ""; }; - 35CD46DE65AF42A722F77B020C46D90C /* _RXDelegateProxy.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = _RXDelegateProxy.h; path = RxCocoa/Runtime/include/_RXDelegateProxy.h; sourceTree = ""; }; - 369F2D26E42DB35A68DD079DB5EC8CE0 /* Alamofire-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Alamofire-Info.plist"; sourceTree = ""; }; - 3731D6B5F5645F219064F326F5DBBC0D /* UIProgressView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIProgressView+Rx.swift"; path = "RxCocoa/iOS/UIProgressView+Rx.swift"; sourceTree = ""; }; - 386FAD9AC5C475D7BA99FC1A87649B67 /* Disposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Disposable.swift; path = RxSwift/Disposable.swift; sourceTree = ""; }; - 390ADDE880682922C795B8C9F7EF4C6B /* UIPageControl+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIPageControl+Rx.swift"; path = "RxCocoa/iOS/UIPageControl+Rx.swift"; sourceTree = ""; }; - 39C5C966A2E80796DAC4539D2C64490F /* Timer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Timer.swift; path = RxSwift/Observables/Timer.swift; sourceTree = ""; }; - 39DCD13C6B63A7BC27F88C977C14B2D8 /* Protected.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Protected.swift; path = Source/Protected.swift; sourceTree = ""; }; - 3A4B1BFFB33A19ABE0476723FF458911 /* PublishRelay+Signal.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "PublishRelay+Signal.swift"; path = "RxCocoa/Traits/Signal/PublishRelay+Signal.swift"; sourceTree = ""; }; - 3A6FB965F9F761670F3AE2F6485D5E11 /* AnyObserver.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AnyObserver.swift; path = RxSwift/AnyObserver.swift; sourceTree = ""; }; - 3AE97F55029A327A68BA15B8A7E84BE6 /* GroupedObservable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = GroupedObservable.swift; path = RxSwift/GroupedObservable.swift; sourceTree = ""; }; - 3AFABBBFA80EA15962031B302097CA32 /* TakeWhile.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TakeWhile.swift; path = RxSwift/Observables/TakeWhile.swift; sourceTree = ""; }; - 3BA20BD3717079A8B70018B2E2B847A4 /* KVORepresentable+CoreGraphics.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "KVORepresentable+CoreGraphics.swift"; path = "RxCocoa/Foundation/KVORepresentable+CoreGraphics.swift"; sourceTree = ""; }; - 3D09F935DC494553C710F412276A8499 /* Multicast.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Multicast.swift; path = RxSwift/Observables/Multicast.swift; sourceTree = ""; }; - 3D10EA8BD2DCC28FFB44502861805167 /* RxRelay-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "RxRelay-Info.plist"; sourceTree = ""; }; - 3E7397B9BB16FC5807B0C849884DED48 /* ServerTrustEvaluation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ServerTrustEvaluation.swift; path = Source/ServerTrustEvaluation.swift; sourceTree = ""; }; - 3F2C7582BCAF3FDBE0408C5CE66746BE /* Repeat.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Repeat.swift; path = RxSwift/Observables/Repeat.swift; sourceTree = ""; }; - 429F241033F18A4B1C77E5B96EC83B8B /* VirtualTimeConverterType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = VirtualTimeConverterType.swift; path = RxSwift/Schedulers/VirtualTimeConverterType.swift; sourceTree = ""; }; - 43A58125D39C8209160D767B9FCD6715 /* CachedResponseHandler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CachedResponseHandler.swift; path = Source/CachedResponseHandler.swift; sourceTree = ""; }; - 43EE4AC30D4D78D61696489C29D9CC3E /* Cancelable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Cancelable.swift; path = RxSwift/Cancelable.swift; sourceTree = ""; }; - 4433B551F7F37D4C8EF24EE7E6CEDFD7 /* _RX.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = _RX.h; path = RxCocoa/Runtime/include/_RX.h; sourceTree = ""; }; - 4523C7B556A036033B3A5F949125AFC7 /* ObserverType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObserverType.swift; path = RxSwift/ObserverType.swift; sourceTree = ""; }; - 4569C98C4590D9EC3361D848DCB582C8 /* ControlProperty+Driver.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ControlProperty+Driver.swift"; path = "RxCocoa/Traits/Driver/ControlProperty+Driver.swift"; sourceTree = ""; }; - 46DD6E7421FD83F1CBB2CE3D863ECDC6 /* ObservableType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObservableType.swift; path = RxSwift/ObservableType.swift; sourceTree = ""; }; - 47FFFD359F4E6910FBFA61F227E03B31 /* ParameterEncoder.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ParameterEncoder.swift; path = Source/ParameterEncoder.swift; sourceTree = ""; }; - 48C8732A69884F45E5C836FB0D58C7A1 /* UIStepper+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIStepper+Rx.swift"; path = "RxCocoa/iOS/UIStepper+Rx.swift"; sourceTree = ""; }; - 48F1B0D43C35A06740FE33CFC6A0F5D3 /* NSObject+Rx+RawRepresentable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSObject+Rx+RawRepresentable.swift"; path = "RxCocoa/Foundation/NSObject+Rx+RawRepresentable.swift"; sourceTree = ""; }; - 48F9D5B73C10CD49B315100BEE5DA548 /* DelegateProxyType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DelegateProxyType.swift; path = RxCocoa/Common/DelegateProxyType.swift; sourceTree = ""; }; - 491B91C5AEEA5379C8161A8EF83C2201 /* Merge.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Merge.swift; path = RxSwift/Observables/Merge.swift; sourceTree = ""; }; - 4D1A4773C251551DBF3256469BDA716E /* RxPickerViewDataSourceType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxPickerViewDataSourceType.swift; path = RxCocoa/iOS/Protocols/RxPickerViewDataSourceType.swift; sourceTree = ""; }; - 4E45254E5CC9E0AC1386E062A11CF266 /* Catch.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Catch.swift; path = RxSwift/Observables/Catch.swift; sourceTree = ""; }; - 4EDB5B83E7753170C64A678FD75B51C2 /* KVORepresentable+Swift.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "KVORepresentable+Swift.swift"; path = "RxCocoa/Foundation/KVORepresentable+Swift.swift"; sourceTree = ""; }; - 4FE45E4A160BBBF16808F12971CC5A89 /* UIApplication+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIApplication+Rx.swift"; path = "RxCocoa/iOS/UIApplication+Rx.swift"; sourceTree = ""; }; - 5010F104E06C52D713C0FEA244872C4B /* RxCocoa.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxCocoa.swift; path = RxCocoa/RxCocoa.swift; sourceTree = ""; }; - 5144D49C296E97677FB28CA7B6A74D08 /* RxWKNavigationDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxWKNavigationDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxWKNavigationDelegateProxy.swift; sourceTree = ""; }; - 5180C903E0EECAD555BDF74DDFE1EC53 /* NotificationCenter+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NotificationCenter+Rx.swift"; path = "RxCocoa/Foundation/NotificationCenter+Rx.swift"; sourceTree = ""; }; - 51EE13A170006C38AA759AC268753B9A /* Sink.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Sink.swift; path = RxSwift/Observables/Sink.swift; sourceTree = ""; }; - 5399BBECE22553D36BE196941994439E /* OperationQueue+Alamofire.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "OperationQueue+Alamofire.swift"; path = "Source/OperationQueue+Alamofire.swift"; sourceTree = ""; }; - 556A6CF39F72E28DD01FC3C31B0C116D /* RxCocoaObjCRuntimeError+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "RxCocoaObjCRuntimeError+Extensions.swift"; path = "RxCocoa/Common/RxCocoaObjCRuntimeError+Extensions.swift"; sourceTree = ""; }; - 55D718D09D4BA0E6833E730CA280D373 /* DistinctUntilChanged.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DistinctUntilChanged.swift; path = RxSwift/Observables/DistinctUntilChanged.swift; sourceTree = ""; }; - 5798BC6E0D346B973EED8805BD8294C5 /* ScheduledItem.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ScheduledItem.swift; path = RxSwift/Schedulers/Internal/ScheduledItem.swift; sourceTree = ""; }; - 58E09376519428A591949F090A35B864 /* ControlEvent+Signal.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ControlEvent+Signal.swift"; path = "RxCocoa/Traits/Signal/ControlEvent+Signal.swift"; sourceTree = ""; }; - 59F13789F4CF993E4174281BADA9FE5C /* UINavigationController+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UINavigationController+Rx.swift"; path = "RxCocoa/iOS/UINavigationController+Rx.swift"; sourceTree = ""; }; - 5A59821B4014E4768C966D6250EC7415 /* RxCocoa-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "RxCocoa-Info.plist"; sourceTree = ""; }; - 5AB20C0696C90368521BC8C5D30941FF /* PrimitiveSequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PrimitiveSequence.swift; path = RxSwift/Traits/PrimitiveSequence.swift; sourceTree = ""; }; - 5AB7D69D293E93ED1C08B79BA59670FF /* Completable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Completable.swift; path = RxSwift/Traits/Completable.swift; sourceTree = ""; }; - 5BBBD32E7904C793C4B7CE8BBD493CF4 /* RecursiveLock.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RecursiveLock.swift; path = Platform/RecursiveLock.swift; sourceTree = ""; }; - 5BDAE5B5F0CEA445E64668F0AE99F0A0 /* ObservableType+PrimitiveSequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ObservableType+PrimitiveSequence.swift"; path = "RxSwift/Traits/ObservableType+PrimitiveSequence.swift"; sourceTree = ""; }; - 5C6DD10F6A9C17A249C1E425DA10B8AF /* SharedSequence+Operators.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "SharedSequence+Operators.swift"; path = "RxCocoa/Traits/SharedSequence/SharedSequence+Operators.swift"; sourceTree = ""; }; - 5C8DFF242FF6AD0B5D39025559BF1464 /* Just.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Just.swift; path = RxSwift/Observables/Just.swift; sourceTree = ""; }; - 5D3B3309D720B6FF46FCAA66C89D18E8 /* SchedulerType+SharedSequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "SchedulerType+SharedSequence.swift"; path = "RxCocoa/Traits/SharedSequence/SchedulerType+SharedSequence.swift"; sourceTree = ""; }; - 5D51CA2749FDF55B4FCB399B3C2D0CD2 /* BinaryDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BinaryDisposable.swift; path = RxSwift/Disposables/BinaryDisposable.swift; sourceTree = ""; }; + 35B19D09D0DB2E94A7249C68294BD24E /* RLMArray.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMArray.mm; path = Realm/RLMArray.mm; sourceTree = ""; }; + 35E1C5A9B4B09EE53C0486B10DCAB3D9 /* DisposeBase.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DisposeBase.swift; path = RxSwift/Disposables/DisposeBase.swift; sourceTree = ""; }; + 36A621775AD2772E5FEEDCE7B4C00609 /* RLMMongoClient.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMMongoClient.mm; path = Realm/RLMMongoClient.mm; sourceTree = ""; }; + 36B0CAA1E7547C748296D9FF14B3A8F9 /* Merge.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Merge.swift; path = RxSwift/Observables/Merge.swift; sourceTree = ""; }; + 36BF8A2B8D6FDF8C2D4039E82ED313B0 /* SwitchIfEmpty.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SwitchIfEmpty.swift; path = RxSwift/Observables/SwitchIfEmpty.swift; sourceTree = ""; }; + 3735D6A2DD9E0153CCC36C2C9EB50C64 /* Throttle.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Throttle.swift; path = RxSwift/Observables/Throttle.swift; sourceTree = ""; }; + 3792EC9BB21CD2D5F7B80FB23B95039E /* Observable+Bind.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Observable+Bind.swift"; path = "RxRelay/Observable+Bind.swift"; sourceTree = ""; }; + 37A0F60CC9D52B64D82BCC6F7CD12FAD /* NSTextField+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSTextField+Rx.swift"; path = "RxCocoa/macOS/NSTextField+Rx.swift"; sourceTree = ""; }; + 37D024D0F04AAD55C5660DD29517DE6C /* RLMObjectBase_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMObjectBase_Private.h; path = include/RLMObjectBase_Private.h; sourceTree = ""; }; + 3888EEE9DD9958C44FE1090A609BF16F /* Queue.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Queue.swift; path = Platform/DataStructures/Queue.swift; sourceTree = ""; }; + 38ACC5B4987910374BEBC50EBEC37F85 /* Combine.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Combine.swift; path = RealmSwift/Combine.swift; sourceTree = ""; }; + 38BCA73981CA09129A31DC7B76307E1D /* List.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = List.swift; path = RealmSwift/List.swift; sourceTree = ""; }; + 392210D1A703D4FBF3F414E4EEA4B01C /* ObjectId.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObjectId.swift; path = RealmSwift/ObjectId.swift; sourceTree = ""; }; + 395BA47D1C6A5F1B244D5486B0BE5279 /* HTTPHeaders.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HTTPHeaders.swift; path = Source/HTTPHeaders.swift; sourceTree = ""; }; + 398354D20FA08BCFAF261A15A601B056 /* RxSwift-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "RxSwift-dummy.m"; sourceTree = ""; }; + 3A3C70D050B1B4B178ADA00B9AA4F6AA /* DistinctUntilChanged.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DistinctUntilChanged.swift; path = RxSwift/Observables/DistinctUntilChanged.swift; sourceTree = ""; }; + 3A40B0E7398EBDFA5BB36A1A3D484D15 /* Alamofire.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Alamofire.debug.xcconfig; sourceTree = ""; }; + 3B5C59F9DE41D9B01A435F7BF7BD1E26 /* Multicast.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Multicast.swift; path = RxSwift/Observables/Multicast.swift; sourceTree = ""; }; + 3C3AF2E791EE67E3DF385C1781D769A1 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; + 3C97DEF2379317945ADFDFD934CC62FA /* Alamofire-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Alamofire-Info.plist"; sourceTree = ""; }; + 3D0180CFE946C46EF8AF4737A4DFAD94 /* RxTextStorageDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTextStorageDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxTextStorageDelegateProxy.swift; sourceTree = ""; }; + 3D07F541D43757522E39C49E24343496 /* RxCocoa.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = RxCocoa.modulemap; sourceTree = ""; }; + 3DAB14E2B6EDB1F43829CF2AB53CC4A1 /* ToArray.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ToArray.swift; path = RxSwift/Observables/ToArray.swift; sourceTree = ""; }; + 3E2548ECC06C74EA7204E04959046038 /* Concat.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Concat.swift; path = RxSwift/Observables/Concat.swift; sourceTree = ""; }; + 3F3E96D01CCFEFD7A748E4B5C5D839D8 /* placeholder.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = placeholder.cpp; path = Realm/ObjectStore/src/placeholder.cpp; sourceTree = ""; }; + 3F594796D37FA8E4181B6C9837866D3C /* Map.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Map.swift; path = RxSwift/Observables/Map.swift; sourceTree = ""; }; + 40B6058E10D64C4CDA4C4003E5F09318 /* _RXKVOObserver.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = _RXKVOObserver.m; path = RxCocoa/Runtime/_RXKVOObserver.m; sourceTree = ""; }; + 413A00C1692E2DBDCF425033FC1A5200 /* RxSwift-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RxSwift-prefix.pch"; sourceTree = ""; }; + 42A4B9682D6833BEBF451FE680D4EAF3 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/Security.framework; sourceTree = DEVELOPER_DIR; }; + 42BC5BAEE68B463D825B57F887FED7E2 /* Platform.Darwin.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Platform.Darwin.swift; path = Platform/Platform.Darwin.swift; sourceTree = ""; }; + 42C7AFF87F4881919AEDE31682621C65 /* collection_change_builder.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = collection_change_builder.cpp; path = Realm/ObjectStore/src/impl/collection_change_builder.cpp; sourceTree = ""; }; + 434FC690A867299DE9E7360140680714 /* CombineLatest+Collection.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "CombineLatest+Collection.swift"; path = "RxSwift/Observables/CombineLatest+Collection.swift"; sourceTree = ""; }; + 43628ED44C9AA3D3503458B602E82696 /* AnonymousObserver.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AnonymousObserver.swift; path = RxSwift/Observers/AnonymousObserver.swift; sourceTree = ""; }; + 437919EE08EC6BFCCBAC3BD346309742 /* RealmSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = RealmSwift.framework; path = RealmSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 43BBDAB01E88E016FDB56CAE0E18D1AB /* UISegmentedControl+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UISegmentedControl+Rx.swift"; path = "RxCocoa/iOS/UISegmentedControl+Rx.swift"; sourceTree = ""; }; + 4425212D91422CC722267318D089C54F /* InvocableScheduledItem.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = InvocableScheduledItem.swift; path = RxSwift/Schedulers/Internal/InvocableScheduledItem.swift; sourceTree = ""; }; + 444FCF6395FE1FD628DE5A8E7D80B3E5 /* RLMQueryUtil.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMQueryUtil.mm; path = Realm/RLMQueryUtil.mm; sourceTree = ""; }; + 44D3FFDDA0AB5DE8F05DECEEBDEB12AF /* RLMObjectId.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMObjectId.mm; path = Realm/RLMObjectId.mm; sourceTree = ""; }; + 4524CEDB98A45F635C925EEFC4AC4D3A /* RxSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RxSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 45A889D4629D068E1484C1D3DF16D952 /* Protected.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Protected.swift; path = Source/Protected.swift; sourceTree = ""; }; + 45B647ABF0A00004F68914CBADFB5B27 /* RLMFindOptions.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMFindOptions.h; path = include/RLMFindOptions.h; sourceTree = ""; }; + 462749C51F01BD979C5B7601F7EDCB60 /* Dematerialize.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Dematerialize.swift; path = RxSwift/Observables/Dematerialize.swift; sourceTree = ""; }; + 46F0BDEBDA102A8F380230089E3DF83A /* NSImageView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSImageView+Rx.swift"; path = "RxCocoa/macOS/NSImageView+Rx.swift"; sourceTree = ""; }; + 474B55CB2CC0E9BAE21E4A0D1DD8D50A /* RLMRealm_Dynamic.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMRealm_Dynamic.h; path = include/RLMRealm_Dynamic.h; sourceTree = ""; }; + 4837AB0A4DF18729E0F0A4791CE14A1F /* UIViewController+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIViewController+Rx.swift"; path = "RxCocoa/iOS/UIViewController+Rx.swift"; sourceTree = ""; }; + 48E379072BB61DABCB5FDA0E8A8E8EB9 /* RLMObjectId.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMObjectId.h; path = include/RLMObjectId.h; sourceTree = ""; }; + 49E7584983330E54D87E476814915B7B /* Realm-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Realm-prefix.pch"; sourceTree = ""; }; + 49F9716687BE37F18CD9BFE6A52FD2DA /* AsMaybe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AsMaybe.swift; path = RxSwift/Observables/AsMaybe.swift; sourceTree = ""; }; + 4AD199BA92F23A99AF5C9029FFE852F6 /* UIControl+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIControl+Rx.swift"; path = "RxCocoa/iOS/UIControl+Rx.swift"; sourceTree = ""; }; + 4ADCB6FD187409DE26C251F11D5BB1BC /* results_notifier.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = results_notifier.cpp; path = Realm/ObjectStore/src/impl/results_notifier.cpp; sourceTree = ""; }; + 4B4DC0F0B575AE2E7C0CB9D6293F8333 /* RxSwift-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "RxSwift-Info.plist"; sourceTree = ""; }; + 4C01E6FADE447436D88928C88EC55978 /* Alamofire.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Alamofire.release.xcconfig; sourceTree = ""; }; + 4D13E474693D288FA9DFD047070BE0C4 /* UITabBarController+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UITabBarController+Rx.swift"; path = "RxCocoa/iOS/UITabBarController+Rx.swift"; sourceTree = ""; }; + 4D35DDC112BDC5FFC671470DD73ECC07 /* Schema.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Schema.swift; path = RealmSwift/Schema.swift; sourceTree = ""; }; + 4DB882D96AE746E55CFCDEEA459DA375 /* StringEncoding+Alamofire.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "StringEncoding+Alamofire.swift"; path = "Source/StringEncoding+Alamofire.swift"; sourceTree = ""; }; + 4EC3085A93400F8B25DEC31B6BB987E8 /* ItemEvents.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ItemEvents.swift; path = RxCocoa/iOS/Events/ItemEvents.swift; sourceTree = ""; }; + 4F9470706D8F36E200A0E14D91125B4E /* DelegateProxyType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DelegateProxyType.swift; path = RxCocoa/Common/DelegateProxyType.swift; sourceTree = ""; }; + 4FA07826EC4D168DA6EC97F9164EA43F /* shared_realm.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = shared_realm.cpp; path = Realm/ObjectStore/src/shared_realm.cpp; sourceTree = ""; }; + 4FCF57E40DC0EEE76170EA7566F7A93D /* RxPickerViewDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxPickerViewDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxPickerViewDelegateProxy.swift; sourceTree = ""; }; + 507E063CA30A2126D999BD8DD729A4FD /* ObjectSchema.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObjectSchema.swift; path = RealmSwift/ObjectSchema.swift; sourceTree = ""; }; + 5119D72B27B8C09312A82E4774AB6C96 /* NSButton+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSButton+Rx.swift"; path = "RxCocoa/macOS/NSButton+Rx.swift"; sourceTree = ""; }; + 514EDB50B37C0BA31EE0FF3E4DB2C0FC /* RLMUtil.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMUtil.mm; path = Realm/RLMUtil.mm; sourceTree = ""; }; + 51733B99E1E51A063736971961F48AF0 /* PublishSubject.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PublishSubject.swift; path = RxSwift/Subjects/PublishSubject.swift; sourceTree = ""; }; + 518DC531B255B88E40E5651418722E86 /* RxCollectionViewReactiveArrayDataSource.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxCollectionViewReactiveArrayDataSource.swift; path = RxCocoa/iOS/DataSources/RxCollectionViewReactiveArrayDataSource.swift; sourceTree = ""; }; + 51B7DF99F44018B800FB12ACED5FF6DD /* PriorityQueue.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PriorityQueue.swift; path = Platform/DataStructures/PriorityQueue.swift; sourceTree = ""; }; + 528B9C2D3C3B86EDE0CF0FCD180ADD76 /* MultipartUpload.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MultipartUpload.swift; path = Source/MultipartUpload.swift; sourceTree = ""; }; + 52C941DCDB3F6B0C1A675A2389D157F8 /* _RX.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = _RX.m; path = RxCocoa/Runtime/_RX.m; sourceTree = ""; }; + 5346001597BAFBB0875B82142214C534 /* DispatchQueueConfiguration.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DispatchQueueConfiguration.swift; path = RxSwift/Schedulers/Internal/DispatchQueueConfiguration.swift; sourceTree = ""; }; + 53EAC9C5F32183C09D621EB078E77FB8 /* UIView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIView+Rx.swift"; path = "RxCocoa/iOS/UIView+Rx.swift"; sourceTree = ""; }; + 54304BCBA467BC5A9BADBDEAAEC497B7 /* ObservableConvertibleType+Driver.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ObservableConvertibleType+Driver.swift"; path = "RxCocoa/Traits/Driver/ObservableConvertibleType+Driver.swift"; sourceTree = ""; }; + 54CA22C46BEA679028DABD5E41774F7D /* ObservableType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObservableType.swift; path = RxSwift/ObservableType.swift; sourceTree = ""; }; + 55667AE78EBF92BF3FD083D92F3F038E /* ControlTarget.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ControlTarget.swift; path = RxCocoa/Common/ControlTarget.swift; sourceTree = ""; }; + 56071D6A7FAAD47EDEE69ABCC81232D0 /* Decimal128.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Decimal128.swift; path = RealmSwift/Decimal128.swift; sourceTree = ""; }; + 5620DEC10EDB32C938A7BCA68FC4785D /* Lock.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Lock.swift; path = RxSwift/Concurrency/Lock.swift; sourceTree = ""; }; + 57D26DE88762BD941DD60CB00B72DA3D /* RLMObject_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMObject_Private.h; path = include/RLMObject_Private.h; sourceTree = ""; }; + 57DDCE1EB82077DFA8196D502BE48F31 /* InvocableType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = InvocableType.swift; path = RxSwift/Schedulers/Internal/InvocableType.swift; sourceTree = ""; }; + 59497FB083F1C96E811BF0ADD11511B9 /* RLMRealm.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMRealm.h; path = include/RLMRealm.h; sourceTree = ""; }; + 597BC46EC61C37E53FF2B9A3DFDD76CC /* RLMDecimal128.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMDecimal128.h; path = include/RLMDecimal128.h; sourceTree = ""; }; + 59D97F87A443456155F519E2A0FCD855 /* Signal.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Signal.swift; path = RxCocoa/Traits/Signal/Signal.swift; sourceTree = ""; }; + 5A1141A4DC6BF96018F16D5E1D3579D2 /* Realm-xcframeworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Realm-xcframeworks.sh"; sourceTree = ""; }; + 5B2E877567298339EF627B1FF714AE0C /* OperationQueue+Alamofire.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "OperationQueue+Alamofire.swift"; path = "Source/OperationQueue+Alamofire.swift"; sourceTree = ""; }; + 5B5470E42687026564FABF072383156A /* Timeout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Timeout.swift; path = RxSwift/Observables/Timeout.swift; sourceTree = ""; }; + 5B667C049F3C637F0B9FBA40721F2DCA /* RLMMongoCollection.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMMongoCollection.mm; path = Realm/RLMMongoCollection.mm; sourceTree = ""; }; + 5BA07F30960653B557BD112DFE0FA2FD /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/CFNetwork.framework; sourceTree = DEVELOPER_DIR; }; + 5BE4CA9CBC1AD20B27FCF3C637CEC001 /* NSView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSView+Rx.swift"; path = "RxCocoa/macOS/NSView+Rx.swift"; sourceTree = ""; }; 5D797E9A5C5782CE845840781FA1CC81 /* Alamofire.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Alamofire.framework; path = Alamofire.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 61F51B59B445C72F183D9CD178727B31 /* Zip+arity.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Zip+arity.swift"; path = "RxSwift/Observables/Zip+arity.swift"; sourceTree = ""; }; - 63BB583E7867A580C3470AC51FF64304 /* UITabBarController+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UITabBarController+Rx.swift"; path = "RxCocoa/iOS/UITabBarController+Rx.swift"; sourceTree = ""; }; - 63F81B444952A4A8B726B8F7E7F2DCB4 /* RedirectHandler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RedirectHandler.swift; path = Source/RedirectHandler.swift; sourceTree = ""; }; - 64B2FF80E466BCBACC87D06E77E7DE42 /* EventMonitor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = EventMonitor.swift; path = Source/EventMonitor.swift; sourceTree = ""; }; - 65E6B5B902603AF8C36756D07E7024DB /* CompositeDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CompositeDisposable.swift; path = RxSwift/Disposables/CompositeDisposable.swift; sourceTree = ""; }; - 6649FD173A631AE0DF45F9BD4F0394AA /* Reduce.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Reduce.swift; path = RxSwift/Observables/Reduce.swift; sourceTree = ""; }; - 66D915A4C32A6B2AE8EA8CDD952CCF81 /* Alamofire.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Alamofire.release.xcconfig; sourceTree = ""; }; - 671EDE771550EBC0A957B46405BEA906 /* UITabBarItem+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UITabBarItem+Rx.swift"; path = "RxCocoa/iOS/UITabBarItem+Rx.swift"; sourceTree = ""; }; - 68CD61BA0DC293FEC7C65FEABFC9CF7B /* HTTPHeaders.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HTTPHeaders.swift; path = Source/HTTPHeaders.swift; sourceTree = ""; }; - 68D3944E9EFF58CCE1B9DCAB666EDD71 /* TextInput.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TextInput.swift; path = RxCocoa/Common/TextInput.swift; sourceTree = ""; }; - 69272EAAED861BAC838702AA74D4304E /* GroupBy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = GroupBy.swift; path = RxSwift/Observables/GroupBy.swift; sourceTree = ""; }; - 695B8FEB2CE2E58AC36323480D088515 /* UIControl+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIControl+Rx.swift"; path = "RxCocoa/iOS/UIControl+Rx.swift"; sourceTree = ""; }; + 5DC72A276813FE5860E1E696B9AB591D /* ParameterEncoder.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ParameterEncoder.swift; path = Source/ParameterEncoder.swift; sourceTree = ""; }; + 5E43F537772E258AF502F38A512641D1 /* Observable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Observable.swift; path = RxSwift/Observable.swift; sourceTree = ""; }; + 5E4DC26BFD994975A4452321FEE2E86D /* RLMProperty.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMProperty.mm; path = Realm/RLMProperty.mm; sourceTree = ""; }; + 5E7AC000EA49E075669EE248F2B7E05D /* RxAlamofire.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = RxAlamofire.release.xcconfig; sourceTree = ""; }; + 5EA93CB577014200856DD7108C1B0220 /* CombineLatest.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CombineLatest.swift; path = RxSwift/Observables/CombineLatest.swift; sourceTree = ""; }; + 5EF5469A5815CD32CD6EDDCE7D18638E /* Request.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Request.swift; path = Source/Request.swift; sourceTree = ""; }; + 5F1A25FE11E235D26A2DF9E9B0C5F486 /* ImmediateSchedulerType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ImmediateSchedulerType.swift; path = RxSwift/ImmediateSchedulerType.swift; sourceTree = ""; }; + 5F3DC0EA3882AAC0C73433CD4667975C /* RxWKNavigationDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxWKNavigationDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxWKNavigationDelegateProxy.swift; sourceTree = ""; }; + 5FFE744FD97312727A9E1589CD8DBE63 /* UIActivityIndicatorView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIActivityIndicatorView+Rx.swift"; path = "RxCocoa/iOS/UIActivityIndicatorView+Rx.swift"; sourceTree = ""; }; + 6008D806F7FE06FEE6315C1A586CBE38 /* RLMArray_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMArray_Private.h; path = include/RLMArray_Private.h; sourceTree = ""; }; + 6155D234BBD32E52148B0991435CB0E5 /* ConcurrentDispatchQueueScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConcurrentDispatchQueueScheduler.swift; path = RxSwift/Schedulers/ConcurrentDispatchQueueScheduler.swift; sourceTree = ""; }; + 61DF4B6E4DF859118106BF282B06A33C /* Window.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Window.swift; path = RxSwift/Observables/Window.swift; sourceTree = ""; }; + 620007ED9E8C608CA8206880D8995253 /* system_configuration.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = system_configuration.cpp; path = Realm/ObjectStore/src/sync/impl/apple/system_configuration.cpp; sourceTree = ""; }; + 62417B7C7ED038B5F8F43B05FAD2BFE4 /* UINavigationController+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UINavigationController+Rx.swift"; path = "RxCocoa/iOS/UINavigationController+Rx.swift"; sourceTree = ""; }; + 624F02C1F26E3F4651425171FAEE3170 /* RxCollectionViewDataSourcePrefetchingProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxCollectionViewDataSourcePrefetchingProxy.swift; path = RxCocoa/iOS/Proxies/RxCollectionViewDataSourcePrefetchingProxy.swift; sourceTree = ""; }; + 62D4533872082639E49CC2D812CCA9FF /* RxPickerViewDataSourceType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxPickerViewDataSourceType.swift; path = RxCocoa/iOS/Protocols/RxPickerViewDataSourceType.swift; sourceTree = ""; }; + 63D68E55920A869C800D56FD98EC9C81 /* NSLayoutConstraint+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSLayoutConstraint+Rx.swift"; path = "RxCocoa/Common/NSLayoutConstraint+Rx.swift"; sourceTree = ""; }; + 6410892B86384E401E39178B508F47B7 /* NotificationCenter+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NotificationCenter+Rx.swift"; path = "RxCocoa/Foundation/NotificationCenter+Rx.swift"; sourceTree = ""; }; + 645DF232325867ABB538CC52A0A2A677 /* Zip+arity.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Zip+arity.swift"; path = "RxSwift/Observables/Zip+arity.swift"; sourceTree = ""; }; + 64C4A169FCD8C606185D6CB50AE9ADF6 /* RLMEmailPasswordAuth.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMEmailPasswordAuth.h; path = include/RLMEmailPasswordAuth.h; sourceTree = ""; }; + 651FA28CF0389AA0022093E86CDC588E /* regular_expression.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = regular_expression.cpp; path = Realm/ObjectStore/src/util/bson/regular_expression.cpp; sourceTree = ""; }; + 65553F09D06098FE8A398224ED2104A4 /* realm-sync.xcframework */ = {isa = PBXFileReference; includeInIndex = 1; name = "realm-sync.xcframework"; path = "core/realm-sync.xcframework"; sourceTree = ""; }; + 65A1C3236E061F091E6E42FC717B46DB /* ScheduledItem.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ScheduledItem.swift; path = RxSwift/Schedulers/Internal/ScheduledItem.swift; sourceTree = ""; }; + 661DBD2189C578AADB4AD2ABECB572D6 /* Reduce.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Reduce.swift; path = RxSwift/Observables/Reduce.swift; sourceTree = ""; }; + 663782B983674097667AA655877DE251 /* CombineLatest+arity.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "CombineLatest+arity.swift"; path = "RxSwift/Observables/CombineLatest+arity.swift"; sourceTree = ""; }; + 6652A6E7278B0F41CBFCE6520A354FC7 /* RLMCredentials.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMCredentials.h; path = include/RLMCredentials.h; sourceTree = ""; }; + 6659B577E42EF97A5FDF4BC0E77791C7 /* RxPickerViewAdapter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxPickerViewAdapter.swift; path = RxCocoa/iOS/DataSources/RxPickerViewAdapter.swift; sourceTree = ""; }; + 66AEF1F18BB09CFF26081204A5716BAB /* Maybe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Maybe.swift; path = RxSwift/Traits/Maybe.swift; sourceTree = ""; }; + 66EDB9DF199CC9BF81C564719B0E75AC /* RLMObjectBase_Dynamic.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMObjectBase_Dynamic.h; path = include/RLMObjectBase_Dynamic.h; sourceTree = ""; }; + 672BD61565B17E3649CB5C53F72C117C /* RedirectHandler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RedirectHandler.swift; path = Source/RedirectHandler.swift; sourceTree = ""; }; + 673B530043EE97D068D4854830529D8F /* RxCollectionViewDataSourceProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxCollectionViewDataSourceProxy.swift; path = RxCocoa/iOS/Proxies/RxCollectionViewDataSourceProxy.swift; sourceTree = ""; }; + 6781794A3C328F78F4B8FD5954B94C05 /* list.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = list.cpp; path = Realm/ObjectStore/src/list.cpp; sourceTree = ""; }; + 685C0AD8CD4FEC498B803EBEAB9D460C /* push_client.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = push_client.cpp; path = Realm/ObjectStore/src/sync/push_client.cpp; sourceTree = ""; }; + 68C58BEBFF4071BC2F983B1A9DCAFED4 /* TakeWhile.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TakeWhile.swift; path = RxSwift/Observables/TakeWhile.swift; sourceTree = ""; }; + 6924294AB88A4FA6537B15BA0B6F297D /* RLMObjectBase.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMObjectBase.h; path = include/RLMObjectBase.h; sourceTree = ""; }; + 697BC47AE64E2A2BC38671AAD282C4A4 /* Sync.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Sync.swift; path = RealmSwift/Sync.swift; sourceTree = ""; }; + 6A6C8E21EBFBFFCDA1933049C170A78C /* RLMSyncUtil.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMSyncUtil.mm; path = Realm/RLMSyncUtil.mm; sourceTree = ""; }; + 6A6DFD2E3086F70BABF4D552F3F82567 /* sync_metadata.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = sync_metadata.cpp; path = Realm/ObjectStore/src/sync/impl/sync_metadata.cpp; sourceTree = ""; }; + 6A9EAA3A3F0ADEAA5CA9017D7A367920 /* BehaviorRelay.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BehaviorRelay.swift; path = RxRelay/BehaviorRelay.swift; sourceTree = ""; }; 6AB5594F15BA137C18F182717955CB2E /* Pods_Darner_dan_uh.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Pods_Darner_dan_uh.framework; path = "Pods-Darner-dan-uh.framework"; sourceTree = BUILT_PRODUCTS_DIR; }; - 6BC6717EFA577FA1D6989094852AB703 /* ResponseSerialization.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ResponseSerialization.swift; path = Source/ResponseSerialization.swift; sourceTree = ""; }; - 6C2486F75744B1FC4A37CD9456E933D8 /* BehaviorSubject.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BehaviorSubject.swift; path = RxSwift/Subjects/BehaviorSubject.swift; sourceTree = ""; }; - 700A4CD2C06E3944CED95A0F3210EDC2 /* Bag+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Bag+Rx.swift"; path = "RxSwift/Extensions/Bag+Rx.swift"; sourceTree = ""; }; - 7118B325E21EA425E6E5598213DEB350 /* Errors.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Errors.swift; path = RxSwift/Errors.swift; sourceTree = ""; }; - 71338F1DF2F29A6EE619AF0A7C9C7311 /* RxPickerViewDataSourceProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxPickerViewDataSourceProxy.swift; path = RxCocoa/iOS/Proxies/RxPickerViewDataSourceProxy.swift; sourceTree = ""; }; - 7158E03F9F9E66C75E4578F6F0D41BB4 /* PublishRelay.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PublishRelay.swift; path = RxRelay/PublishRelay.swift; sourceTree = ""; }; - 722CD18502E18B8FCB01DF7B127ECDBA /* SingleAssignmentDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SingleAssignmentDisposable.swift; path = RxSwift/Disposables/SingleAssignmentDisposable.swift; sourceTree = ""; }; - 724C773201D9539EF9D9CFF6D6513A87 /* ToArray.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ToArray.swift; path = RxSwift/Observables/ToArray.swift; sourceTree = ""; }; - 72FB3EEC19F1F948F81C181D6FBFC668 /* UIGestureRecognizer+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIGestureRecognizer+Rx.swift"; path = "RxCocoa/iOS/UIGestureRecognizer+Rx.swift"; sourceTree = ""; }; - 734FC1CAA915693F4537D08A4A8D8268 /* Take.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Take.swift; path = RxSwift/Observables/Take.swift; sourceTree = ""; }; - 73A9D94E1C53404F1C79C9361B4FE031 /* BehaviorRelay.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BehaviorRelay.swift; path = RxRelay/BehaviorRelay.swift; sourceTree = ""; }; - 7468EC0CFAB9F0DAE3E4C9ABD87F9835 /* TakeUntil.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TakeUntil.swift; path = RxSwift/Observables/TakeUntil.swift; sourceTree = ""; }; - 746ECD0F77098F9DA6B011D51999C74D /* DispatchQueue+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "DispatchQueue+Extensions.swift"; path = "Platform/DispatchQueue+Extensions.swift"; sourceTree = ""; }; - 75CA936BEB05C9F8DDCA3F8C09F3FD0D /* ShareReplayScope.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ShareReplayScope.swift; path = RxSwift/Observables/ShareReplayScope.swift; sourceTree = ""; }; - 75CB38A7C83A94843D8DAF65E964D744 /* RxCollectionViewDataSourceProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxCollectionViewDataSourceProxy.swift; path = RxCocoa/iOS/Proxies/RxCollectionViewDataSourceProxy.swift; sourceTree = ""; }; - 76EDB2CA5901A84A6295300BFF0991EB /* SynchronizedUnsubscribeType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SynchronizedUnsubscribeType.swift; path = RxSwift/Concurrency/SynchronizedUnsubscribeType.swift; sourceTree = ""; }; - 77BAE41DE8F15764B25F01E46AFBF15E /* HistoricalScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HistoricalScheduler.swift; path = RxSwift/Schedulers/HistoricalScheduler.swift; sourceTree = ""; }; - 78F0A6654B98B62DC64FA1664AD7FACF /* KeyPathBinder.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = KeyPathBinder.swift; path = RxCocoa/Common/KeyPathBinder.swift; sourceTree = ""; }; - 79BE01F296E7734CBB0F06D590545AB6 /* RxCollectionViewDataSourceType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxCollectionViewDataSourceType.swift; path = RxCocoa/iOS/Protocols/RxCollectionViewDataSourceType.swift; sourceTree = ""; }; - 7A11A7403C8F81B77F8C11652F2506DE /* UIScrollView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIScrollView+Rx.swift"; path = "RxCocoa/iOS/UIScrollView+Rx.swift"; sourceTree = ""; }; - 7B24C8DC7CFE2282E35EB7B1BAFD5AD2 /* ObservableConvertibleType+SharedSequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ObservableConvertibleType+SharedSequence.swift"; path = "RxCocoa/Traits/SharedSequence/ObservableConvertibleType+SharedSequence.swift"; sourceTree = ""; }; - 7C190B94A6B2940D3FB8792AF205241E /* Map.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Map.swift; path = RxSwift/Observables/Map.swift; sourceTree = ""; }; - 7C64D7DFFFAF12902AD0718F6F2F6C6B /* Timeout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Timeout.swift; path = RxSwift/Observables/Timeout.swift; sourceTree = ""; }; - 7D82EFD974A7B79DCB06387BFA6925C9 /* Combine.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Combine.swift; path = Source/Combine.swift; sourceTree = ""; }; - 7E09A0E2396C110A208EC13C7433F660 /* InvocableScheduledItem.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = InvocableScheduledItem.swift; path = RxSwift/Schedulers/Internal/InvocableScheduledItem.swift; sourceTree = ""; }; - 7E5D3D875EA46CC50F03F97C512911F0 /* URLEncodedFormEncoder.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = URLEncodedFormEncoder.swift; path = Source/URLEncodedFormEncoder.swift; sourceTree = ""; }; - 7EBCC7FF0F228A25D24C5FB31329EB64 /* Debug.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Debug.swift; path = RxSwift/Observables/Debug.swift; sourceTree = ""; }; - 7EEF27C2DCA3ADEB3B8D204BF95F3CEC /* VirtualTimeScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = VirtualTimeScheduler.swift; path = RxSwift/Schedulers/VirtualTimeScheduler.swift; sourceTree = ""; }; - 808E993F2D6447824333774C0C6EF094 /* AnonymousObserver.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AnonymousObserver.swift; path = RxSwift/Observers/AnonymousObserver.swift; sourceTree = ""; }; + 6B7A5B0F7FA13D2ED0C0C194C5E8EECB /* RLMSyncConfiguration.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMSyncConfiguration.h; path = include/RLMSyncConfiguration.h; sourceTree = ""; }; + 6D7711C205CBF6BCA6CC225854D7D96E /* RxTableViewDataSourcePrefetchingProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTableViewDataSourcePrefetchingProxy.swift; path = RxCocoa/iOS/Proxies/RxTableViewDataSourcePrefetchingProxy.swift; sourceTree = ""; }; + 6DBD72C6356BDA4CBF5FFA393F9D6B9E /* transact_log_handler.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = transact_log_handler.cpp; path = Realm/ObjectStore/src/impl/transact_log_handler.cpp; sourceTree = ""; }; + 6EF4F2B170D864CB87EB954D73D92566 /* URLSession+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "URLSession+Rx.swift"; path = "RxCocoa/Foundation/URLSession+Rx.swift"; sourceTree = ""; }; + 6F88EF52999F2464E771FC2D673E42B7 /* WithLatestFrom.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = WithLatestFrom.swift; path = RxSwift/Observables/WithLatestFrom.swift; sourceTree = ""; }; + 7018E4C3E8A75A113B688D25BC4EAE63 /* Do.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Do.swift; path = RxSwift/Observables/Do.swift; sourceTree = ""; }; + 709CB3C96BE62917AB9B052EAE6A59A4 /* RxAlamofire.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = RxAlamofire.modulemap; sourceTree = ""; }; + 712C52F8298ACFE9974537269740BA0D /* results.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = results.cpp; path = Realm/ObjectStore/src/results.cpp; sourceTree = ""; }; + 7199CFB5B8CAFD358110536A33C227A4 /* StartWith.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = StartWith.swift; path = RxSwift/Observables/StartWith.swift; sourceTree = ""; }; + 71A6EDA338F7DA1AA89C3FAF02FBB03B /* RLMEmbeddedObject.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMEmbeddedObject.mm; path = Realm/RLMEmbeddedObject.mm; sourceTree = ""; }; + 71C7AD37453C1150D3F33183FFB649B4 /* Sample.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Sample.swift; path = RxSwift/Observables/Sample.swift; sourceTree = ""; }; + 723F15F9375F2B593537ECFA203122C1 /* ControlProperty.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ControlProperty.swift; path = RxCocoa/Traits/ControlProperty.swift; sourceTree = ""; }; + 724255BC9B7D55EC976790CCFA597FD3 /* Signal+Subscription.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Signal+Subscription.swift"; path = "RxCocoa/Traits/Signal/Signal+Subscription.swift"; sourceTree = ""; }; + 72842ABA9A87A415D9DA5339DCC9B4BD /* RLMPushClient.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMPushClient.h; path = include/RLMPushClient.h; sourceTree = ""; }; + 72A2153FA40633D4FF37728672DFCC9C /* generic_network_transport.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = generic_network_transport.cpp; path = Realm/ObjectStore/src/sync/generic_network_transport.cpp; sourceTree = ""; }; + 73459032C7AED3F87C065F092BFDC3ED /* RLMRealmUtil.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMRealmUtil.mm; path = Realm/RLMRealmUtil.mm; sourceTree = ""; }; + 7365074ECE61B11E251379CA978A43A5 /* BinaryDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BinaryDisposable.swift; path = RxSwift/Disposables/BinaryDisposable.swift; sourceTree = ""; }; + 7386464B12C9B9D5D45B6DB16A6EE443 /* RefCountDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RefCountDisposable.swift; path = RxSwift/Disposables/RefCountDisposable.swift; sourceTree = ""; }; + 73A9A3EEEFC050E309B1CF7BB6B34EFE /* Never.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Never.swift; path = RxSwift/Observables/Never.swift; sourceTree = ""; }; + 73C10FBD152E2E4CC495ABBFFDA46BF0 /* RLMCredentials.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMCredentials.mm; path = Realm/RLMCredentials.mm; sourceTree = ""; }; + 747A3C76800A1F6EC0D6086DFC8CB10E /* RLMMongoCollection.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMMongoCollection.h; path = include/RLMMongoCollection.h; sourceTree = ""; }; + 74979024C8AA2EBCEA8080A78F40EEBF /* Deferred.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Deferred.swift; path = RxSwift/Observables/Deferred.swift; sourceTree = ""; }; + 75901C59B7444C2042CFE3AE5FD1990D /* Debug.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Debug.swift; path = RxSwift/Observables/Debug.swift; sourceTree = ""; }; + 7606F0023754B879718D8B9541F4BF15 /* ObservableType+PrimitiveSequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ObservableType+PrimitiveSequence.swift"; path = "RxSwift/Traits/ObservableType+PrimitiveSequence.swift"; sourceTree = ""; }; + 768B96ADE27F4305ED123B2603C54787 /* Alamofire.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Alamofire.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 776C91B3873938A23ED3424F3518F119 /* RxCocoa-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RxCocoa-prefix.pch"; sourceTree = ""; }; + 77AF92F12F598B9BEED3DFFCDE50EAC8 /* ObserveOn.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObserveOn.swift; path = RxSwift/Observables/ObserveOn.swift; sourceTree = ""; }; + 77F0820D4FCD444B8F0423461352022F /* RxAlamofire-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "RxAlamofire-dummy.m"; sourceTree = ""; }; + 784FD3E1244F1A96A68DBAACA9AACFED /* ControlEvent+Signal.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ControlEvent+Signal.swift"; path = "RxCocoa/Traits/Signal/ControlEvent+Signal.swift"; sourceTree = ""; }; + 78BD15A38C1C2292CA446D8971F118FE /* RLMRealmConfiguration_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMRealmConfiguration_Private.h; path = include/RLMRealmConfiguration_Private.h; sourceTree = ""; }; + 78BF537112F36CF990F71AF86E97C406 /* KVORepresentable+CoreGraphics.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "KVORepresentable+CoreGraphics.swift"; path = "RxCocoa/Foundation/KVORepresentable+CoreGraphics.swift"; sourceTree = ""; }; + 7917278D67C732EA8824D2F598180959 /* TailRecursiveSink.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TailRecursiveSink.swift; path = RxSwift/Observers/TailRecursiveSink.swift; sourceTree = ""; }; + 79A8CC9EDAA7DFCB1E18EC681B2E22B5 /* Bag.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Bag.swift; path = Platform/DataStructures/Bag.swift; sourceTree = ""; }; + 79CA8D74CEF50C0C13559089D0DEA8A3 /* remote_mongo_client.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = remote_mongo_client.cpp; path = Realm/ObjectStore/src/sync/remote_mongo_client.cpp; sourceTree = ""; }; + 7B5BFEC05FC481CB99545BF0DB1DB91F /* Realm.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Realm.release.xcconfig; sourceTree = ""; }; + 7B83B53F912C1DDF4F1CDD642DFB2F3D /* RxCocoa-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RxCocoa-umbrella.h"; sourceTree = ""; }; + 7CB0323D0C93433A2A590C992D5B2C75 /* KVORepresentable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = KVORepresentable.swift; path = RxCocoa/Foundation/KVORepresentable.swift; sourceTree = ""; }; + 7D8A38AE011A373694F41430F9242A03 /* Completable+AndThen.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Completable+AndThen.swift"; path = "RxSwift/Traits/Completable+AndThen.swift"; sourceTree = ""; }; + 7DD046180099B4434D80E9C4EB641390 /* SubjectType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SubjectType.swift; path = RxSwift/Subjects/SubjectType.swift; sourceTree = ""; }; + 7E2F3BC87F104DB09900DB492F6B2079 /* WKWebView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "WKWebView+Rx.swift"; path = "RxCocoa/iOS/WKWebView+Rx.swift"; sourceTree = ""; }; + 7EFE079604B17211ADC0DBD90895F0F7 /* NSError+RLMSync.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "NSError+RLMSync.m"; path = "Realm/NSError+RLMSync.m"; sourceTree = ""; }; + 7F4BDF9CDF423C6AE4A6BE7176115309 /* Realm.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = Realm.modulemap; sourceTree = ""; }; + 7F68B8830F1AF80F4EA87E62B55CD11F /* RealmConfiguration.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RealmConfiguration.swift; path = RealmSwift/RealmConfiguration.swift; sourceTree = ""; }; + 7FEB4D9BA45A0D280A2E12721EDDE69A /* RLMSchema_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMSchema_Private.h; path = include/RLMSchema_Private.h; sourceTree = ""; }; + 7FF061165F98F4381C924039DC3469FB /* app.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = app.cpp; path = Realm/ObjectStore/src/sync/app.cpp; sourceTree = ""; }; 809C5FAB588354C9BA37DC3EAB8CB45C /* RxSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = RxSwift.framework; path = RxSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 82222D308116F3DD1A7671C934667A99 /* Driver.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Driver.swift; path = RxCocoa/Traits/Driver/Driver.swift; sourceTree = ""; }; - 825187DCC64EE46B0EFA0A41454B8172 /* SectionedViewDataSourceType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SectionedViewDataSourceType.swift; path = RxCocoa/Common/SectionedViewDataSourceType.swift; sourceTree = ""; }; - 8298B6CF3236C82E2CAD1913C751A27A /* StartWith.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = StartWith.swift; path = RxSwift/Observables/StartWith.swift; sourceTree = ""; }; - 82CF61945D38FCF90C8205EF6C6049E6 /* RxSwift.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = RxSwift.release.xcconfig; sourceTree = ""; }; - 83CCEE94FAB38943A2870279FA91DFE3 /* UIDatePicker+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIDatePicker+Rx.swift"; path = "RxCocoa/iOS/UIDatePicker+Rx.swift"; sourceTree = ""; }; - 83D73284DCEE4FE8C76234DE2ACCD393 /* RxRelay.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RxRelay.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 841FA2717197F3826D2C1BE1E8A19A1B /* RxSearchBarDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxSearchBarDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxSearchBarDelegateProxy.swift; sourceTree = ""; }; - 847E8C3BE479BE92FDDC97E5D40D4DCE /* RetryPolicy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RetryPolicy.swift; path = Source/RetryPolicy.swift; sourceTree = ""; }; - 84BF31B4F35220C06C94D6486C204AE2 /* UIAlertAction+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIAlertAction+Rx.swift"; path = "RxCocoa/iOS/UIAlertAction+Rx.swift"; sourceTree = ""; }; - 8562E45AECE2A39A478C87F465CA781E /* SingleAsync.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SingleAsync.swift; path = RxSwift/Observables/SingleAsync.swift; sourceTree = ""; }; - 86C1631C4A90FA9150FA3655A6719B66 /* SharedSequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SharedSequence.swift; path = RxCocoa/Traits/SharedSequence/SharedSequence.swift; sourceTree = ""; }; - 87A259B0B87DE94E12C68F977565F77E /* SwitchIfEmpty.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SwitchIfEmpty.swift; path = RxSwift/Observables/SwitchIfEmpty.swift; sourceTree = ""; }; - 87A84A65C3F2568A97179656B9AF632F /* UITableView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UITableView+Rx.swift"; path = "RxCocoa/iOS/UITableView+Rx.swift"; sourceTree = ""; }; - 895A56F29AE70279A3FEDF60F962626C /* ConcurrentDispatchQueueScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConcurrentDispatchQueueScheduler.swift; path = RxSwift/Schedulers/ConcurrentDispatchQueueScheduler.swift; sourceTree = ""; }; - 89F07902A639D9463D1E12EF99A9B561 /* PrimitiveSequence+Zip+arity.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "PrimitiveSequence+Zip+arity.swift"; path = "RxSwift/Traits/PrimitiveSequence+Zip+arity.swift"; sourceTree = ""; }; - 8A2DBFDEF94D9662C5B07A332E73688E /* Deprecated.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Deprecated.swift; path = RxCocoa/Deprecated.swift; sourceTree = ""; }; - 8ADD934EFC16C04986525A256FAF54FC /* Do.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Do.swift; path = RxSwift/Observables/Do.swift; sourceTree = ""; }; - 8C025AFFED9E62D011484129DF62E696 /* UICollectionView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UICollectionView+Rx.swift"; path = "RxCocoa/iOS/UICollectionView+Rx.swift"; sourceTree = ""; }; - 8C2C0BA6DCCAC653154B4C7C85BFC951 /* ImmediateSchedulerType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ImmediateSchedulerType.swift; path = RxSwift/ImmediateSchedulerType.swift; sourceTree = ""; }; - 8C5C5E1306EC265A2A7887CE3A3F9671 /* UITextView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UITextView+Rx.swift"; path = "RxCocoa/iOS/UITextView+Rx.swift"; sourceTree = ""; }; - 8C9BCC3F17727084979A31BEF7947939 /* RxCollectionViewReactiveArrayDataSource.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxCollectionViewReactiveArrayDataSource.swift; path = RxCocoa/iOS/DataSources/RxCollectionViewReactiveArrayDataSource.swift; sourceTree = ""; }; - 8CEC26A7701127C819179F739A292434 /* Notifications.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Notifications.swift; path = Source/Notifications.swift; sourceTree = ""; }; - 8F827C8190D1956882FEDB02BF7DA311 /* ScheduledItemType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ScheduledItemType.swift; path = RxSwift/Schedulers/Internal/ScheduledItemType.swift; sourceTree = ""; }; - 8FFF273E60390BCB4D3FDF0CF08E2348 /* Bag.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Bag.swift; path = Platform/DataStructures/Bag.swift; sourceTree = ""; }; - 90E10AF3A7B96FE0920F8B8DE86C4219 /* Producer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Producer.swift; path = RxSwift/Observables/Producer.swift; sourceTree = ""; }; - 910E3E80559F53D4F796EE8F57AA99C8 /* Sample.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Sample.swift; path = RxSwift/Observables/Sample.swift; sourceTree = ""; }; - 91584B212EE8EEDC31D307A6B76CFEF5 /* UISearchController+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UISearchController+Rx.swift"; path = "RxCocoa/iOS/UISearchController+Rx.swift"; sourceTree = ""; }; - 91EACAB565BF2BFEA11F77968AC8DE14 /* RxPickerViewAdapter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxPickerViewAdapter.swift; path = RxCocoa/iOS/DataSources/RxPickerViewAdapter.swift; sourceTree = ""; }; - 91F209C3C5BD5EA95444DC72928A82C5 /* ControlEvent+Driver.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ControlEvent+Driver.swift"; path = "RxCocoa/Traits/Driver/ControlEvent+Driver.swift"; sourceTree = ""; }; - 92E284F02D192F4D40930B6436D1FF91 /* NopDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = NopDisposable.swift; path = RxSwift/Disposables/NopDisposable.swift; sourceTree = ""; }; - 95FBECA2920D68E70F2D918ED16EE65F /* Zip+Collection.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Zip+Collection.swift"; path = "RxSwift/Observables/Zip+Collection.swift"; sourceTree = ""; }; - 96D5C46415477108721579DE2581D8B8 /* Buffer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Buffer.swift; path = RxSwift/Observables/Buffer.swift; sourceTree = ""; }; - 96F2CC4F3C17654C39122D70966D11A1 /* SerialDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SerialDisposable.swift; path = RxSwift/Disposables/SerialDisposable.swift; sourceTree = ""; }; - 96FF3C3F6E5DD44B9D6F1953F267234B /* NetworkReachabilityManager.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = NetworkReachabilityManager.swift; path = Source/NetworkReachabilityManager.swift; sourceTree = ""; }; - 970BA40FE81A997797A75CA0790B616A /* ScheduledDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ScheduledDisposable.swift; path = RxSwift/Disposables/ScheduledDisposable.swift; sourceTree = ""; }; - 9755430B399C67DC347AC34EB3CB5BB1 /* Queue.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Queue.swift; path = Platform/DataStructures/Queue.swift; sourceTree = ""; }; - 986E10F6FB6A0D91ACBD54436DEE367D /* RxCollectionViewDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxCollectionViewDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxCollectionViewDelegateProxy.swift; sourceTree = ""; }; + 81A4B883DE20BA52DBECF0CE87117416 /* Reactive.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Reactive.swift; path = RxSwift/Reactive.swift; sourceTree = ""; }; + 82266C25BBCBD86647BC2B7923D2B33A /* Materialize.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Materialize.swift; path = RxSwift/Observables/Materialize.swift; sourceTree = ""; }; + 82371E956C3016CE2FAB26325FA8263C /* UIImageView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIImageView+Rx.swift"; path = "RxCocoa/iOS/UIImageView+Rx.swift"; sourceTree = ""; }; + 82F1475AA0F9C33F7EA4A1459305D2AB /* RxAlamofire.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = RxAlamofire.framework; path = RxAlamofire.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 83D5D07DBB1E6BEFC0FA713727BD7111 /* sync_user.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = sync_user.cpp; path = Realm/ObjectStore/src/sync/sync_user.cpp; sourceTree = ""; }; + 83DE5521B45742BFD64A13767CBCF9B6 /* RxCocoaRuntime.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RxCocoaRuntime.h; path = RxCocoa/Runtime/include/RxCocoaRuntime.h; sourceTree = ""; }; + 8438E4076B74C43E8903AF30E833AD3F /* UITableView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UITableView+Rx.swift"; path = "RxCocoa/iOS/UITableView+Rx.swift"; sourceTree = ""; }; + 8474F500BF2F1D1E0C3B2C645C25E944 /* Alamofire-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Alamofire-prefix.pch"; sourceTree = ""; }; + 84A45083FC7449764AF1103A0342E595 /* Take.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Take.swift; path = RxSwift/Observables/Take.swift; sourceTree = ""; }; + 84E405EFB78E63F9D2F57CA86CA6BC4D /* RLMRealm+Sync.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "RLMRealm+Sync.h"; path = "include/RLMRealm+Sync.h"; sourceTree = ""; }; + 869B025D18E382BEA868469B62E768EF /* RLMRealmConfiguration+Sync.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = "RLMRealmConfiguration+Sync.mm"; path = "Realm/RLMRealmConfiguration+Sync.mm"; sourceTree = ""; }; + 880083C6631CCDD9FCFB3D3742A37D59 /* RLMCollection_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMCollection_Private.h; path = include/RLMCollection_Private.h; sourceTree = ""; }; + 886B2C07DFF2C711F399CC43936EAAE6 /* Repeat.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Repeat.swift; path = RxSwift/Observables/Repeat.swift; sourceTree = ""; }; + 888D23E446A07C3A3365606FF924FBDA /* RLMNetworkTransport.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMNetworkTransport.h; path = include/RLMNetworkTransport.h; sourceTree = ""; }; + 8A193A9805AD36F6923C1094E275C8F3 /* index_set.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = index_set.cpp; path = Realm/ObjectStore/src/index_set.cpp; sourceTree = ""; }; + 8A2612662E1FE096C9556E86ED4BC8C0 /* UICollectionView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UICollectionView+Rx.swift"; path = "RxCocoa/iOS/UICollectionView+Rx.swift"; sourceTree = ""; }; + 8A46F5C2B8DA96C883B9042D339476E0 /* UIDatePicker+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIDatePicker+Rx.swift"; path = "RxCocoa/iOS/UIDatePicker+Rx.swift"; sourceTree = ""; }; + 8A83EEE7FF87AE4434072CD2E879BAB8 /* Cancelable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Cancelable.swift; path = RxSwift/Cancelable.swift; sourceTree = ""; }; + 8A99B37E50B6E39B7CD160179B1048DF /* AddRef.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AddRef.swift; path = RxSwift/Observables/AddRef.swift; sourceTree = ""; }; + 8B27C2C39ABC4A9CFFDF48A71687A545 /* RxCocoa.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxCocoa.swift; path = RxCocoa/RxCocoa.swift; sourceTree = ""; }; + 8B39675E53AC002A88BF4E125C3B555A /* RxTabBarControllerDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTabBarControllerDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxTabBarControllerDelegateProxy.swift; sourceTree = ""; }; + 8BD9325336D6BFDFCEDBD5E891C35801 /* RxAlamofire-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RxAlamofire-umbrella.h"; sourceTree = ""; }; + 8BEF15345C60B26DE20F2B3F14A965C5 /* Create.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Create.swift; path = RxSwift/Observables/Create.swift; sourceTree = ""; }; + 8D59A9F196D2018A996B8B5D4092D628 /* RecursiveScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RecursiveScheduler.swift; path = RxSwift/Schedulers/RecursiveScheduler.swift; sourceTree = ""; }; + 8D5D2EE19CA67D347686A2E578910C66 /* Realm.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Realm.h; path = include/Realm.h; sourceTree = ""; }; + 8D859A8A88C5A84E3E4AD9AD9B6B463C /* NSObject+Rx+KVORepresentable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSObject+Rx+KVORepresentable.swift"; path = "RxCocoa/Foundation/NSObject+Rx+KVORepresentable.swift"; sourceTree = ""; }; + 8D9F194E31435BDE8CF3925BAFF22F43 /* uuid.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = uuid.cpp; path = Realm/ObjectStore/src/util/uuid.cpp; sourceTree = ""; }; + 8DE3CA5A0A2191AE9FDC8035DA6936DC /* RxTabBarDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTabBarDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxTabBarDelegateProxy.swift; sourceTree = ""; }; + 8E98590E803C6C2C41CAE017D38F9FFE /* RLMRealm.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMRealm.mm; path = Realm/RLMRealm.mm; sourceTree = ""; }; + 8FBE3C34D8D3B16941AB50B4CC5848B1 /* DefaultIfEmpty.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DefaultIfEmpty.swift; path = RxSwift/Observables/DefaultIfEmpty.swift; sourceTree = ""; }; + 90520370565051AB89C191544C3D53CE /* weak_realm_notifier.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = weak_realm_notifier.cpp; path = Realm/ObjectStore/src/impl/weak_realm_notifier.cpp; sourceTree = ""; }; + 9131396FAB541FDAB151AB74DBB27C00 /* RLMSyncManager.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMSyncManager.mm; path = Realm/RLMSyncManager.mm; sourceTree = ""; }; + 91D0991D750AE18A29982329B999FEDF /* Range.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Range.swift; path = RxSwift/Observables/Range.swift; sourceTree = ""; }; + 921BE4A82C4A7A5C72A0C6F8B8FEF200 /* Realm.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Realm.framework; path = Realm.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 9321A74C66CB2C438FF080AD05E16A91 /* RealmSwift-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "RealmSwift-Info.plist"; sourceTree = ""; }; + 9324A6849331CB03EC6A65F1D0181040 /* Scan.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Scan.swift; path = RxSwift/Observables/Scan.swift; sourceTree = ""; }; + 9353D0C358A0729BB1BEBEE191E85F7D /* NSObject+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSObject+Rx.swift"; path = "RxCocoa/Foundation/NSObject+Rx.swift"; sourceTree = ""; }; + 93E8A674D112A59F350E4FA5585AB904 /* HistoricalSchedulerTimeConverter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HistoricalSchedulerTimeConverter.swift; path = RxSwift/Schedulers/HistoricalSchedulerTimeConverter.swift; sourceTree = ""; }; + 9412756A303D90418C6D9386101C3738 /* RLMProviderClient.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMProviderClient.h; path = include/RLMProviderClient.h; sourceTree = ""; }; + 9482D73017F85685522CA70803E01C6D /* RxRelay-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RxRelay-prefix.pch"; sourceTree = ""; }; + 94DFF8110F6D1F6DD68850F236420519 /* NSTextStorage+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSTextStorage+Rx.swift"; path = "RxCocoa/iOS/NSTextStorage+Rx.swift"; sourceTree = ""; }; + 9645FC628D296BC5A54B036A9DF35F9F /* ObjectiveCSupport+Sync.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ObjectiveCSupport+Sync.swift"; path = "RealmSwift/ObjectiveCSupport+Sync.swift"; sourceTree = ""; }; + 97114D5DB038834C71DF6D35894881E3 /* RLMClassInfo.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMClassInfo.mm; path = Realm/RLMClassInfo.mm; sourceTree = ""; }; + 97432F3721A1295916E9EE9A63DF61E6 /* RetryWhen.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RetryWhen.swift; path = RxSwift/Observables/RetryWhen.swift; sourceTree = ""; }; + 9780DFB1A6645BAF294350731A0D5D12 /* RxTableViewDataSourceType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTableViewDataSourceType.swift; path = RxCocoa/iOS/Protocols/RxTableViewDataSourceType.swift; sourceTree = ""; }; + 97C0C3568B5022C6BB1A43D26687A849 /* PrimitiveSequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PrimitiveSequence.swift; path = RxSwift/Traits/PrimitiveSequence.swift; sourceTree = ""; }; + 97E523BCD01E85E993214379AEB68DE6 /* object_schema.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = object_schema.cpp; path = Realm/ObjectStore/src/object_schema.cpp; sourceTree = ""; }; 988DE88749782C9C163B1D7A9FA18BD2 /* Pods-Darner-dan-uh.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-Darner-dan-uh.modulemap"; sourceTree = ""; }; - 98EA88CC63643B3A84D3750A2A6E4BAD /* RecursiveScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RecursiveScheduler.swift; path = RxSwift/Schedulers/RecursiveScheduler.swift; sourceTree = ""; }; - 991AB91BD9AFEC0939936D4D91083DA9 /* DefaultIfEmpty.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DefaultIfEmpty.swift; path = RxSwift/Observables/DefaultIfEmpty.swift; sourceTree = ""; }; - 991D2CD16B3194CA4599C283DBE54B90 /* Alamofire-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Alamofire-dummy.m"; sourceTree = ""; }; - 994EB2413C190238B4D314ECB0A2C6E4 /* SubscriptionDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SubscriptionDisposable.swift; path = RxSwift/Disposables/SubscriptionDisposable.swift; sourceTree = ""; }; - 99BDD186EF36401951391CA36F2BD69D /* DisposeBag.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DisposeBag.swift; path = RxSwift/Disposables/DisposeBag.swift; sourceTree = ""; }; - 9B3A97CA5979AE7A4872B044A506709B /* _RXObjCRuntime.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = _RXObjCRuntime.m; path = RxCocoa/Runtime/_RXObjCRuntime.m; sourceTree = ""; }; - 9C6594A8E2D7855C99BD23EBC9EFE4F5 /* Signal.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Signal.swift; path = RxCocoa/Traits/Signal/Signal.swift; sourceTree = ""; }; - 9C7FB4FD7CE785118A94BC728E538524 /* DelaySubscription.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DelaySubscription.swift; path = RxSwift/Observables/DelaySubscription.swift; sourceTree = ""; }; - 9CC684A247E2C996A5D7B318E5400CD6 /* Event.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Event.swift; path = RxSwift/Event.swift; sourceTree = ""; }; + 98FB87ECA069BA6F525BE852477801F8 /* Generate.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Generate.swift; path = RxSwift/Observables/Generate.swift; sourceTree = ""; }; + 9981BCDBEBC277C4997CD0A9C283BF05 /* UIPageControl+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIPageControl+Rx.swift"; path = "RxCocoa/iOS/UIPageControl+Rx.swift"; sourceTree = ""; }; + 99D287487AD77AFB75AE28B736B355DE /* RLMSyncSession.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMSyncSession.h; path = include/RLMSyncSession.h; sourceTree = ""; }; + 99D459801D0303FB7E4BE5D22AD2AB46 /* DispatchQueue+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "DispatchQueue+Extensions.swift"; path = "Platform/DispatchQueue+Extensions.swift"; sourceTree = ""; }; + 99F09ED9AD8D1B90AEBBEB42D6F5C9E4 /* RxRelay-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RxRelay-umbrella.h"; sourceTree = ""; }; + 9A3A47252A95931ECB57904A7424A230 /* ElementAt.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ElementAt.swift; path = RxSwift/Observables/ElementAt.swift; sourceTree = ""; }; + 9A40596A661F48EEFADF158E97613659 /* Buffer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Buffer.swift; path = RxSwift/Observables/Buffer.swift; sourceTree = ""; }; + 9B754E74CA288E296A9522650713612D /* RxAlamofire.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxAlamofire.swift; path = Sources/RxAlamofire/RxAlamofire.swift; sourceTree = ""; }; + 9C10C065206C7FD92976DAF5D1A6E328 /* network_reachability_observer.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = network_reachability_observer.cpp; path = Realm/ObjectStore/src/sync/impl/apple/network_reachability_observer.cpp; sourceTree = ""; }; + 9C11273D45259641CB6C9E72C2CF25B0 /* Errors.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Errors.swift; path = RxSwift/Errors.swift; sourceTree = ""; }; + 9C2045674F4DE6D2F4B178A9AC7E39BB /* RxCollectionViewDataSourceType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxCollectionViewDataSourceType.swift; path = RxCocoa/iOS/Protocols/RxCollectionViewDataSourceType.swift; sourceTree = ""; }; + 9D3E3CC8D7E1F0271CFA0868904F5EC8 /* Skip.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Skip.swift; path = RxSwift/Observables/Skip.swift; sourceTree = ""; }; + 9D60527BC85D168C986AD2CFF1D51998 /* ObservableType+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ObservableType+Extensions.swift"; path = "RxSwift/ObservableType+Extensions.swift"; sourceTree = ""; }; 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; - 9DA3AB3AE025125F455612E4434A6CBB /* NSView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSView+Rx.swift"; path = "RxCocoa/macOS/NSView+Rx.swift"; sourceTree = ""; }; - 9EEB6ACC4990BC62F16F093FC4BC9F70 /* SubjectType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SubjectType.swift; path = RxSwift/Subjects/SubjectType.swift; sourceTree = ""; }; - 9F1740E9CFCA048D3262400BFDF050F4 /* NSObject+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSObject+Rx.swift"; path = "RxCocoa/Foundation/NSObject+Rx.swift"; sourceTree = ""; }; - 9FE9880124CA212A9F3C74349C1DE066 /* UIView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIView+Rx.swift"; path = "RxCocoa/iOS/UIView+Rx.swift"; sourceTree = ""; }; - A183A6FC3E9F3E14E10154C6FE034A12 /* Response.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Response.swift; path = Source/Response.swift; sourceTree = ""; }; - A1C293648167E9015382D1EED1250993 /* Empty.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Empty.swift; path = RxSwift/Observables/Empty.swift; sourceTree = ""; }; - A2132119D8C2BB8C831F159760E17596 /* SchedulerServices+Emulation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "SchedulerServices+Emulation.swift"; path = "RxSwift/Schedulers/SchedulerServices+Emulation.swift"; sourceTree = ""; }; - A317AB05AFFC477434FBA792F54107C3 /* Bag.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Bag.swift; path = Platform/DataStructures/Bag.swift; sourceTree = ""; }; + 9DAA9230E36A2125FEA32C5242589513 /* AlamofireExtended.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AlamofireExtended.swift; path = Source/AlamofireExtended.swift; sourceTree = ""; }; + 9DF5D58B19C6C63A65143A3E6532029F /* CachedResponseHandler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CachedResponseHandler.swift; path = Source/CachedResponseHandler.swift; sourceTree = ""; }; + 9E291AE3C1521D154766FC3F863C0556 /* SharedSequence+Operators+arity.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "SharedSequence+Operators+arity.swift"; path = "RxCocoa/Traits/SharedSequence/SharedSequence+Operators+arity.swift"; sourceTree = ""; }; + 9E5630F16244E3A4DB87FBDF960B6315 /* UIPickerView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIPickerView+Rx.swift"; path = "RxCocoa/iOS/UIPickerView+Rx.swift"; sourceTree = ""; }; + 9EB4FFCEC0440FD27F0D6CAFED9F09BF /* ScheduledItemType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ScheduledItemType.swift; path = RxSwift/Schedulers/Internal/ScheduledItemType.swift; sourceTree = ""; }; + 9EC5F0B44C2299F90E6115EA3E9D09A1 /* UITextField+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UITextField+Rx.swift"; path = "RxCocoa/iOS/UITextField+Rx.swift"; sourceTree = ""; }; + A06041313ED286E457B40CA0D4F4555E /* RxSearchControllerDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxSearchControllerDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxSearchControllerDelegateProxy.swift; sourceTree = ""; }; + A159B91671189A11B7F92DC40A3B59E4 /* Single.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Single.swift; path = RxSwift/Traits/Single.swift; sourceTree = ""; }; + A163402F2A974483FDCA5F628E8E8AFE /* Queue.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Queue.swift; path = Platform/DataStructures/Queue.swift; sourceTree = ""; }; + A21415F38D7146BDCAFA9B3D201988C6 /* RLMObjectStore.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMObjectStore.mm; path = Realm/RLMObjectStore.mm; sourceTree = ""; }; + A2191E9AE1CD599F32FC4A21A9D0518C /* SerialDispatchQueueScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SerialDispatchQueueScheduler.swift; path = RxSwift/Schedulers/SerialDispatchQueueScheduler.swift; sourceTree = ""; }; + A38454798CDA8D34D056C8B5E0BA22C1 /* ObserverType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObserverType.swift; path = RxSwift/ObserverType.swift; sourceTree = ""; }; + A3D619D046F8DE72E051111E696902B4 /* Bag+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Bag+Rx.swift"; path = "RxSwift/Extensions/Bag+Rx.swift"; sourceTree = ""; }; A4288CA2B164000A29B4CA6754ED4A47 /* Pods-Darner-dan-uh-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-Darner-dan-uh-dummy.m"; sourceTree = ""; }; - A48757BF4BCF0F643D13CB8D15325E28 /* RxTabBarControllerDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTabBarControllerDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxTabBarControllerDelegateProxy.swift; sourceTree = ""; }; - A5440CF35EA37D0984E060E233A0AA89 /* UIBarButtonItem+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIBarButtonItem+Rx.swift"; path = "RxCocoa/iOS/UIBarButtonItem+Rx.swift"; sourceTree = ""; }; - A569CB8DDCF470136457D1CEF4A37441 /* Session.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Session.swift; path = Source/Session.swift; sourceTree = ""; }; - A58C9E012BFF1E7FF4FAF4572C0CA7CD /* RxScrollViewDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxScrollViewDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxScrollViewDelegateProxy.swift; sourceTree = ""; }; - A58CA2588C08F08FF6CAC6A6FBFB2699 /* UILabel+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UILabel+Rx.swift"; path = "RxCocoa/iOS/UILabel+Rx.swift"; sourceTree = ""; }; - A5BF571F992C56D9D573ED8DC09C4C60 /* ObservableType+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ObservableType+Extensions.swift"; path = "RxSwift/ObservableType+Extensions.swift"; sourceTree = ""; }; - A5DB93213D8F24A4193F7FC23804F47B /* Filter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Filter.swift; path = RxSwift/Observables/Filter.swift; sourceTree = ""; }; - A6B8C420AAA1BE4BC3151D7D96707BF0 /* UIActivityIndicatorView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIActivityIndicatorView+Rx.swift"; path = "RxCocoa/iOS/UIActivityIndicatorView+Rx.swift"; sourceTree = ""; }; - A8739FB420371A1A2154926841001385 /* MultipartFormData.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MultipartFormData.swift; path = Source/MultipartFormData.swift; sourceTree = ""; }; - A8AF8FDF5A19CA461972C062BFC6A2B4 /* Single.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Single.swift; path = RxSwift/Traits/Single.swift; sourceTree = ""; }; - A9906331734777309DFC58F7387FF429 /* ConnectableObservableType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConnectableObservableType.swift; path = RxSwift/ConnectableObservableType.swift; sourceTree = ""; }; - AA6709C059CE7E7AE6B666EC6A288782 /* Concat.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Concat.swift; path = RxSwift/Observables/Concat.swift; sourceTree = ""; }; - AABC376B1A706EB2C475BA1F3EC6C4B7 /* CompactMap.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CompactMap.swift; path = RxSwift/Observables/CompactMap.swift; sourceTree = ""; }; - AB4EF579F5A621FEEEB03F3B4B7DDB7B /* RxSwift-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "RxSwift-dummy.m"; sourceTree = ""; }; - AC32F440BB6CD7FAA9A95920E6307107 /* Enumerated.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Enumerated.swift; path = RxSwift/Observables/Enumerated.swift; sourceTree = ""; }; - AD5B005E3CB1E9CBE5F6C8F98D79819A /* Alamofire.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Alamofire.swift; path = Source/Alamofire.swift; sourceTree = ""; }; - AD6F8038569074A1C5850081F2BCC3C8 /* RxTextViewDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTextViewDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxTextViewDelegateProxy.swift; sourceTree = ""; }; - AD70AA8FF2276F495F6B026715273D18 /* Delay.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Delay.swift; path = RxSwift/Observables/Delay.swift; sourceTree = ""; }; - ADB12FD54E0F26373ED16E17F0940E6A /* RxRelay.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = RxRelay.release.xcconfig; sourceTree = ""; }; - AE06908A1B2870327F0ADF60A1C33E5A /* Platform.Linux.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Platform.Linux.swift; path = Platform/Platform.Linux.swift; sourceTree = ""; }; - AEB60E16D234FEBD84C815DB4B29B409 /* Platform.Darwin.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Platform.Darwin.swift; path = Platform/Platform.Darwin.swift; sourceTree = ""; }; - AEF73DB487C51BE3B8089E98680DEEE6 /* MainScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MainScheduler.swift; path = RxSwift/Schedulers/MainScheduler.swift; sourceTree = ""; }; - B0163143A6F2D322EA65C9B165D5E219 /* AsMaybe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AsMaybe.swift; path = RxSwift/Observables/AsMaybe.swift; sourceTree = ""; }; - B084E4A57E92EDDCD3161350DB5BE5AA /* Maybe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Maybe.swift; path = RxSwift/Traits/Maybe.swift; sourceTree = ""; }; - B17B623FDAEFC8D30D3F4F29375FDAB5 /* SwiftSupport.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SwiftSupport.swift; path = RxSwift/SwiftSupport/SwiftSupport.swift; sourceTree = ""; }; - B1A80F5DB2A0494A55847777AEE35124 /* NSTextView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSTextView+Rx.swift"; path = "RxCocoa/macOS/NSTextView+Rx.swift"; sourceTree = ""; }; - B1D59A00FC3C9EAA5DFF54F7800DF5A7 /* NSTextField+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSTextField+Rx.swift"; path = "RxCocoa/macOS/NSTextField+Rx.swift"; sourceTree = ""; }; - B32163A93EBC883865AD6CDA2D382ECD /* SynchronizedDisposeType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SynchronizedDisposeType.swift; path = RxSwift/Concurrency/SynchronizedDisposeType.swift; sourceTree = ""; }; - B36F13BFA7EC28D766E2FA035715D267 /* _RXKVOObserver.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = _RXKVOObserver.h; path = RxCocoa/Runtime/include/_RXKVOObserver.h; sourceTree = ""; }; - B376F5D8698FF8188D605CA8DE79020A /* PublishSubject.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PublishSubject.swift; path = RxSwift/Subjects/PublishSubject.swift; sourceTree = ""; }; - B38ABF51BABC1CD386D2BFB4A0F07773 /* AsyncLock.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AsyncLock.swift; path = RxSwift/Concurrency/AsyncLock.swift; sourceTree = ""; }; - B4EDD858C4EEB5E289F8FB564D33194C /* RxMutableBox.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxMutableBox.swift; path = RxSwift/RxMutableBox.swift; sourceTree = ""; }; - B50080BBC3721DEBF83123B05531A6FE /* RxCocoa.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = RxCocoa.debug.xcconfig; sourceTree = ""; }; - B5BECC5023B1D8885F941AFAB93B43EB /* ConcurrentMainScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConcurrentMainScheduler.swift; path = RxSwift/Schedulers/ConcurrentMainScheduler.swift; sourceTree = ""; }; - B63E4587F295EA0C56BFB2091E93A0E8 /* Observable+Bind.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Observable+Bind.swift"; path = "RxCocoa/Common/Observable+Bind.swift"; sourceTree = ""; }; - B683310889B53BE8E6A34F95BA755E46 /* WKWebView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "WKWebView+Rx.swift"; path = "RxCocoa/iOS/WKWebView+Rx.swift"; sourceTree = ""; }; - B6A92861B69C4DDFEE1EE0D9FAC74DC1 /* NSImageView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSImageView+Rx.swift"; path = "RxCocoa/macOS/NSImageView+Rx.swift"; sourceTree = ""; }; - B6E997AD6AFEFECCF482609975D11D56 /* RxSwift-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RxSwift-prefix.pch"; sourceTree = ""; }; - B8013AA35BA7A79039E7A97B8CD16095 /* BooleanDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BooleanDisposable.swift; path = RxSwift/Disposables/BooleanDisposable.swift; sourceTree = ""; }; - B8F3C4D6343FB0C676E369EA9EC36663 /* ControlTarget.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ControlTarget.swift; path = RxCocoa/Common/ControlTarget.swift; sourceTree = ""; }; - B917E5DBB06B2BDB021DDE3F5FA1C7E2 /* Platform.Linux.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Platform.Linux.swift; path = Platform/Platform.Linux.swift; sourceTree = ""; }; - BA4D142FFB629B426F6F7629322ED1F8 /* Queue.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Queue.swift; path = Platform/DataStructures/Queue.swift; sourceTree = ""; }; - BABE3A3C32E1CB864B5DC70654B3671D /* NSButton+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSButton+Rx.swift"; path = "RxCocoa/macOS/NSButton+Rx.swift"; sourceTree = ""; }; + A43E908FDEB66EAF5CDC0C08CA8F2E9D /* app_credentials.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = app_credentials.cpp; path = Realm/ObjectStore/src/sync/app_credentials.cpp; sourceTree = ""; }; + A4BBBF627F4F3772693F6C60F062DC8D /* PublishRelay.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PublishRelay.swift; path = RxRelay/PublishRelay.swift; sourceTree = ""; }; + A53B942D095FBCA857D477D52867F35B /* RLMResults_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMResults_Private.h; path = include/RLMResults_Private.h; sourceTree = ""; }; + A54BC7BDCBA78BF1EC20099D31AA1404 /* _RXDelegateProxy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = _RXDelegateProxy.m; path = RxCocoa/Runtime/_RXDelegateProxy.m; sourceTree = ""; }; + A54DEEC664B55294338630DE37A09A15 /* RLMRealm_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMRealm_Private.h; path = include/RLMRealm_Private.h; sourceTree = ""; }; + A59FC8CE00F882551C57698AA53BD31E /* RLMMongoClient.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMMongoClient.h; path = include/RLMMongoClient.h; sourceTree = ""; }; + A5BC3FDB21CAE5641FA35481DB4757A8 /* RLMSyncSession.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMSyncSession.mm; path = Realm/RLMSyncSession.mm; sourceTree = ""; }; + A5D1AF23DFAB1570FDB2C341191ABB1B /* RxRelay-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "RxRelay-Info.plist"; sourceTree = ""; }; + A5E3D87CB1399F7F29B712144448C62F /* Disposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Disposable.swift; path = RxSwift/Disposable.swift; sourceTree = ""; }; + A5FF27F873A36ADC87621F49D7A03109 /* RLMRealm+Sync.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = "RLMRealm+Sync.mm"; path = "Realm/RLMRealm+Sync.mm"; sourceTree = ""; }; + A61255D6036F7ACBE0D1DD5F407E59A6 /* UIBarButtonItem+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIBarButtonItem+Rx.swift"; path = "RxCocoa/iOS/UIBarButtonItem+Rx.swift"; sourceTree = ""; }; + A6422EAD5E456128AF6EF8B6214E9EB6 /* App.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = App.swift; path = RealmSwift/App.swift; sourceTree = ""; }; + A653A9A03EC868233496EB1538F067D2 /* RLMUser.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMUser.h; path = include/RLMUser.h; sourceTree = ""; }; + A65BD2C9DED18F75BF3E55EDDE4E56DE /* URLConvertible+URLRequestConvertible.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "URLConvertible+URLRequestConvertible.swift"; path = "Source/URLConvertible+URLRequestConvertible.swift"; sourceTree = ""; }; + A72D1251AA1B04F052725F5E84FA7BF6 /* RLMObject.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMObject.mm; path = Realm/RLMObject.mm; sourceTree = ""; }; + A73ACA6C4773FFAEE78D2D3064620C3C /* Object.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Object.swift; path = RealmSwift/Object.swift; sourceTree = ""; }; + A7520BC1DB4FCDDDD0D2A161F23A099E /* Bag.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Bag.swift; path = Platform/DataStructures/Bag.swift; sourceTree = ""; }; + A7B4151FE9541C0467D4D77981FA35F1 /* Delay.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Delay.swift; path = RxSwift/Observables/Delay.swift; sourceTree = ""; }; + A8635041539346B94338CE166995E9AC /* UITextView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UITextView+Rx.swift"; path = "RxCocoa/iOS/UITextView+Rx.swift"; sourceTree = ""; }; + A8BFDC432C055B3060BC610A590B6D65 /* Alamofire-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Alamofire-dummy.m"; sourceTree = ""; }; + A91049B03ECD97F4BA7F35F3BEA12C2C /* SynchronizedOnType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SynchronizedOnType.swift; path = RxSwift/Concurrency/SynchronizedOnType.swift; sourceTree = ""; }; + AA0E41562C17ECFEDF9457B13567040C /* RLMObjectSchema.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMObjectSchema.h; path = include/RLMObjectSchema.h; sourceTree = ""; }; + AA3127E6EA50E54BE683A4640BA3B1B5 /* RLMApp.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMApp.mm; path = Realm/RLMApp.mm; sourceTree = ""; }; + AA9C81E6BB6A6F3847C6095D3138A200 /* DispatchQueue+Alamofire.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "DispatchQueue+Alamofire.swift"; path = "Source/DispatchQueue+Alamofire.swift"; sourceTree = ""; }; + AAB5C19EDDB71F30C96CF216AEB6881D /* Filter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Filter.swift; path = RxSwift/Observables/Filter.swift; sourceTree = ""; }; + AC6A4C73F2B6D7B0FE5FC3A55E9945AF /* RealmSwift.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = RealmSwift.debug.xcconfig; sourceTree = ""; }; + AC703B02DE4D059FEC238525C3FDB6E5 /* UIStepper+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIStepper+Rx.swift"; path = "RxCocoa/iOS/UIStepper+Rx.swift"; sourceTree = ""; }; + ACC8191ACD24F00F9C2FE8AFEBFFE08B /* RLMOptionalBase.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMOptionalBase.h; path = include/RLMOptionalBase.h; sourceTree = ""; }; + ACD3F71760CCCD9557A8FF00B70177A6 /* RLMObjectStore.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMObjectStore.h; path = include/RLMObjectStore.h; sourceTree = ""; }; + AD289ADC86E68CB5843E0F3E137F584F /* AnonymousDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AnonymousDisposable.swift; path = RxSwift/Disposables/AnonymousDisposable.swift; sourceTree = ""; }; + AE0507016D5F581EF3C0C205AAD4AAE3 /* CurrentThreadScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CurrentThreadScheduler.swift; path = RxSwift/Schedulers/CurrentThreadScheduler.swift; sourceTree = ""; }; + AF497AEA1642B013BDE723091AD4EDB7 /* Event.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Event.swift; path = RxSwift/Event.swift; sourceTree = ""; }; + B0076057252637CB1FC2A28D7CE35B90 /* schema.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = schema.cpp; path = Realm/ObjectStore/src/schema.cpp; sourceTree = ""; }; + B02FFA9C7277B2B22A3A03CCE21A1F17 /* RLMUpdateResult.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMUpdateResult.mm; path = Realm/RLMUpdateResult.mm; sourceTree = ""; }; + B0CD33ADC2C6492EFB2A1C9865747647 /* ControlEvent+Driver.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ControlEvent+Driver.swift"; path = "RxCocoa/Traits/Driver/ControlEvent+Driver.swift"; sourceTree = ""; }; + B11C58CFC4921C01B180D0818D31F1CE /* UITabBarItem+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UITabBarItem+Rx.swift"; path = "RxCocoa/iOS/UITabBarItem+Rx.swift"; sourceTree = ""; }; + B148AEF0FF207D58212857BDEAE15A60 /* UISlider+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UISlider+Rx.swift"; path = "RxCocoa/iOS/UISlider+Rx.swift"; sourceTree = ""; }; + B15981EDF03C1DC3630AEB39AB9743D4 /* Enumerated.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Enumerated.swift; path = RxSwift/Observables/Enumerated.swift; sourceTree = ""; }; + B1DC237BF5D2B86D015539248B204916 /* RLMThreadSafeReference.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMThreadSafeReference.mm; path = Realm/RLMThreadSafeReference.mm; sourceTree = ""; }; + B28FC641132526433C317123A996D97C /* RLMObservation.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMObservation.mm; path = Realm/RLMObservation.mm; sourceTree = ""; }; + B3EAA1E9622A8BD4F96A0A7C126C124E /* SwiftVersion.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SwiftVersion.swift; path = RealmSwift/SwiftVersion.swift; sourceTree = ""; }; + B3ECE590EC23040201BA4796C26E4E8F /* RLMRealmConfiguration.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMRealmConfiguration.mm; path = Realm/RLMRealmConfiguration.mm; sourceTree = ""; }; + B443A7D6ADC2F4D60D93FC877D5DBE0A /* collection_notifications.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = collection_notifications.cpp; path = Realm/ObjectStore/src/collection_notifications.cpp; sourceTree = ""; }; + B5025DCDB5381F0BAF26FFB5E92DAB4E /* BooleanDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BooleanDisposable.swift; path = RxSwift/Disposables/BooleanDisposable.swift; sourceTree = ""; }; + B55A44F27CEFEDAA349EA939F261EBAB /* UINavigationItem+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UINavigationItem+Rx.swift"; path = "RxCocoa/iOS/UINavigationItem+Rx.swift"; sourceTree = ""; }; + B64A231448882D94B15129D5A86DDAA8 /* NSControl+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSControl+Rx.swift"; path = "RxCocoa/macOS/NSControl+Rx.swift"; sourceTree = ""; }; + B67CCC5A38EEFC7FF284A0D814489035 /* AtomicInt.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AtomicInt.swift; path = Platform/AtomicInt.swift; sourceTree = ""; }; + B724B3052D7141BAB931AD7DDA4BE476 /* Driver+Subscription.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Driver+Subscription.swift"; path = "RxCocoa/Traits/Driver/Driver+Subscription.swift"; sourceTree = ""; }; + B7778D9E3B0FE3705C43E723A322774A /* Optional.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Optional.swift; path = RealmSwift/Optional.swift; sourceTree = ""; }; + B9C9E72E22DF33D178D158F6A4918D07 /* VirtualTimeConverterType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = VirtualTimeConverterType.swift; path = RxSwift/Schedulers/VirtualTimeConverterType.swift; sourceTree = ""; }; + BA44B6692F790A5D43E3F201979ED665 /* RLMSchema.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMSchema.mm; path = Realm/RLMSchema.mm; sourceTree = ""; }; + BA487887F86C2E5E0C2C260131CD673E /* RLMConstants.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMConstants.h; path = include/RLMConstants.h; sourceTree = ""; }; BB22D2AF0D6F32A250C45EC2E571E494 /* Pods-Darner-dan-uh.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-Darner-dan-uh.release.xcconfig"; sourceTree = ""; }; - BBAF82A3A34CD99B5EDF793E626273EE /* NSObject+Rx+KVORepresentable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSObject+Rx+KVORepresentable.swift"; path = "RxCocoa/Foundation/NSObject+Rx+KVORepresentable.swift"; sourceTree = ""; }; - BBCBE12D3F58BBE9E47A986996E6BC27 /* Optional.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Optional.swift; path = RxSwift/Observables/Optional.swift; sourceTree = ""; }; - BBD157BE8BD65CAD1F1FD75AEB41A744 /* AsSingle.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AsSingle.swift; path = RxSwift/Observables/AsSingle.swift; sourceTree = ""; }; + BBFE582250E3905047D7584AABB79C71 /* RLMManagedArray.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMManagedArray.mm; path = Realm/RLMManagedArray.mm; sourceTree = ""; }; + BC071B2000C8A95778E4A22701CB8FEC /* AsyncLock.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AsyncLock.swift; path = RxSwift/Concurrency/AsyncLock.swift; sourceTree = ""; }; BC432FD48A5932251F1CAFBC4BF74894 /* RxCocoa.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = RxCocoa.framework; path = RxCocoa.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - BD66064D172EAC9E7AF1EEA0B9036F9B /* TakeLast.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TakeLast.swift; path = RxSwift/Observables/TakeLast.swift; sourceTree = ""; }; - BD8044D97D4AC1C614E59023516FABA6 /* RetryWhen.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RetryWhen.swift; path = RxSwift/Observables/RetryWhen.swift; sourceTree = ""; }; - BD80F9951E58EFC6FB6F971323560447 /* Observable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Observable.swift; path = RxSwift/Observable.swift; sourceTree = ""; }; - BF14D9E05169A85F309D5DBE3E472064 /* Logging.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Logging.swift; path = RxCocoa/Foundation/Logging.swift; sourceTree = ""; }; - BF24B42CA8FF2095D4128F7C54728014 /* SkipWhile.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SkipWhile.swift; path = RxSwift/Observables/SkipWhile.swift; sourceTree = ""; }; - BF5989B02E82DCF650D22F04BEF8CD45 /* CombineLatest+arity.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "CombineLatest+arity.swift"; path = "RxSwift/Observables/CombineLatest+arity.swift"; sourceTree = ""; }; - C0E33457BFEC7056E08761A33142749B /* RefCountDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RefCountDisposable.swift; path = RxSwift/Disposables/RefCountDisposable.swift; sourceTree = ""; }; + BCFFD2140D45F12ABBE22FD0596DACF9 /* UISearchController+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UISearchController+Rx.swift"; path = "RxCocoa/iOS/UISearchController+Rx.swift"; sourceTree = ""; }; + BDCACDC74AD6B5FDD41F5741D751047B /* remote_mongo_collection.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = remote_mongo_collection.cpp; path = Realm/ObjectStore/src/sync/remote_mongo_collection.cpp; sourceTree = ""; }; + BE07BE828DE8E46170E7B5BA08E44997 /* RLMResults.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMResults.h; path = include/RLMResults.h; sourceTree = ""; }; + BE62C08E4BA287B456905415665C63B3 /* RLMObjectSchema.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMObjectSchema.mm; path = Realm/RLMObjectSchema.mm; sourceTree = ""; }; + C0233CB52B3C3FD4DF91769E2264AF71 /* RLMFindOneAndModifyOptions.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMFindOneAndModifyOptions.h; path = include/RLMFindOneAndModifyOptions.h; sourceTree = ""; }; + C04721533F2879C525420717BB0FEFAA /* MongoClient.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MongoClient.swift; path = RealmSwift/MongoClient.swift; sourceTree = ""; }; + C10DC21EBAD81BA7D22A5EA5F096D256 /* SwiftSupport.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SwiftSupport.swift; path = RxSwift/SwiftSupport/SwiftSupport.swift; sourceTree = ""; }; + C1D7A021E82ABD94264468585CA188F2 /* UIProgressView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIProgressView+Rx.swift"; path = "RxCocoa/iOS/UIProgressView+Rx.swift"; sourceTree = ""; }; C1DCC7F7F58397F1C7D7D137C608195F /* Pods-Darner-dan-uh.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-Darner-dan-uh.debug.xcconfig"; sourceTree = ""; }; - C2CE2C996E16841660D5D11A174F1C0D /* SerialDispatchQueueScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SerialDispatchQueueScheduler.swift; path = RxSwift/Schedulers/SerialDispatchQueueScheduler.swift; sourceTree = ""; }; - C3D61F86484FDA362AEE65D3A0E407BC /* TailRecursiveSink.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TailRecursiveSink.swift; path = RxSwift/Observers/TailRecursiveSink.swift; sourceTree = ""; }; - C48DD79407F9BCFED2215FF574C4480E /* UISlider+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UISlider+Rx.swift"; path = "RxCocoa/iOS/UISlider+Rx.swift"; sourceTree = ""; }; - C5F453AE3E9261B221BC01E1E7937973 /* RxNavigationControllerDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxNavigationControllerDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxNavigationControllerDelegateProxy.swift; sourceTree = ""; }; - C632BE09D9C554BF44A8323190FEC8C8 /* RxTableViewDataSourcePrefetchingProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTableViewDataSourcePrefetchingProxy.swift; path = RxCocoa/iOS/Proxies/RxTableViewDataSourcePrefetchingProxy.swift; sourceTree = ""; }; - C669CA7E16725DF7F9C79E88797A2EFC /* Alamofire-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Alamofire-umbrella.h"; sourceTree = ""; }; - C78763BE0913F286921ABF4148DBD215 /* _RXKVOObserver.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = _RXKVOObserver.m; path = RxCocoa/Runtime/_RXKVOObserver.m; sourceTree = ""; }; - C7A2D3F3FB22FE1D134D6E6DC6CF50CE /* PriorityQueue.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PriorityQueue.swift; path = Platform/DataStructures/PriorityQueue.swift; sourceTree = ""; }; - C8CBD89F412EBC0575A328F5B8A71350 /* RxSwift-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RxSwift-umbrella.h"; sourceTree = ""; }; - CC960F0E19C0206FFA0D32C0374AB02E /* RequestTaskMap.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RequestTaskMap.swift; path = Source/RequestTaskMap.swift; sourceTree = ""; }; - CD61E97AA208CB51580A44C98AED1A57 /* ObservableConvertibleType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObservableConvertibleType.swift; path = RxSwift/ObservableConvertibleType.swift; sourceTree = ""; }; - CDCD59A387DF8B278151EF546C7219A6 /* UITextField+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UITextField+Rx.swift"; path = "RxCocoa/iOS/UITextField+Rx.swift"; sourceTree = ""; }; - CE61BF1C347838ECDC5CA622A6258781 /* Disposables.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Disposables.swift; path = RxSwift/Disposables/Disposables.swift; sourceTree = ""; }; - CEE931632251E7215CB2A71E60D0FD55 /* SessionDelegate.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SessionDelegate.swift; path = Source/SessionDelegate.swift; sourceTree = ""; }; - D1FA7686F3834AC433C853E5F4A78990 /* WithLatestFrom.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = WithLatestFrom.swift; path = RxSwift/Observables/WithLatestFrom.swift; sourceTree = ""; }; - D27DC19B8134DEAE3D1C8C556C7A2E59 /* StringEncoding+Alamofire.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "StringEncoding+Alamofire.swift"; path = "Source/StringEncoding+Alamofire.swift"; sourceTree = ""; }; - D2DBFDFBE48A0BFE84CDF28D07A087E4 /* RxCocoa.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = RxCocoa.release.xcconfig; sourceTree = ""; }; - D4F5CAC3DFDC297B2C56D647BF7C7813 /* RxSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RxSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + C21D1AD327A53F52AF328CF9FE041331 /* NetworkReachabilityManager.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = NetworkReachabilityManager.swift; path = Source/NetworkReachabilityManager.swift; sourceTree = ""; }; + C25F0805D73DBCBD7D42D8A9FA10F93A /* RLMEmailPasswordAuth.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMEmailPasswordAuth.mm; path = Realm/RLMEmailPasswordAuth.mm; sourceTree = ""; }; + C286E268C8D65C8396BF5333623B2BD8 /* thread_safe_reference.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = thread_safe_reference.cpp; path = Realm/ObjectStore/src/thread_safe_reference.cpp; sourceTree = ""; }; + C2A30AA03471E53D83530069F50267BB /* RxRelay-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "RxRelay-dummy.m"; sourceTree = ""; }; + C359882BC848E9114C2412C4A30DF333 /* SkipWhile.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SkipWhile.swift; path = RxSwift/Observables/SkipWhile.swift; sourceTree = ""; }; + C3B7CA57C3CC37B2B5613266C1C279A1 /* RLMSyncUtil_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMSyncUtil_Private.h; path = include/RLMSyncUtil_Private.h; sourceTree = ""; }; + C3B988408D8F0CA517A4AEEF864A7269 /* RLMSyncUtil.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMSyncUtil.h; path = include/RLMSyncUtil.h; sourceTree = ""; }; + C3DCFD52DE80EE3972E9D0E88FE4F085 /* RxSearchBarDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxSearchBarDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxSearchBarDelegateProxy.swift; sourceTree = ""; }; + C493112951F78B37A5FADF7CD6C5ADE6 /* Timer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Timer.swift; path = RxSwift/Observables/Timer.swift; sourceTree = ""; }; + C6F55429E4F5A3684B1B610EEB9CBC83 /* Binder.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Binder.swift; path = RxCocoa/Common/Binder.swift; sourceTree = ""; }; + C7488D788771D2CF319A3829C4B15900 /* AuthenticationInterceptor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AuthenticationInterceptor.swift; path = Source/AuthenticationInterceptor.swift; sourceTree = ""; }; + C8D3CD52C0F4520B98B15311A415FF67 /* GroupedObservable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = GroupedObservable.swift; path = RxSwift/GroupedObservable.swift; sourceTree = ""; }; + C970CE56C0F1DBB25C6F1EF915C69BA7 /* ControlEvent.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ControlEvent.swift; path = RxCocoa/Traits/ControlEvent.swift; sourceTree = ""; }; + C98B5E2E7BE8BD9F769092DB3824B607 /* First.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = First.swift; path = RxSwift/Observables/First.swift; sourceTree = ""; }; + C9F7414E32FE518A8A46C0FEA75BF241 /* RLMAPIKeyAuth.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMAPIKeyAuth.mm; path = Realm/RLMAPIKeyAuth.mm; sourceTree = ""; }; + CB6BD43736BD0C82C82EF813563DF749 /* RLMUser.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMUser.mm; path = Realm/RLMUser.mm; sourceTree = ""; }; + CC3611FA4C931ADB12C3874BD2CF9CA1 /* Combine.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Combine.swift; path = Source/Combine.swift; sourceTree = ""; }; + CCE49DA992BF8ABA11EE69E00DB44AED /* UIAlertAction+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIAlertAction+Rx.swift"; path = "RxCocoa/iOS/UIAlertAction+Rx.swift"; sourceTree = ""; }; + CCFCAF09367C94F7CDBFE09DBB92CF09 /* Using.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Using.swift; path = RxSwift/Observables/Using.swift; sourceTree = ""; }; + CD78931CCDDC97455EC35D57F5094C62 /* remote_mongo_database.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = remote_mongo_database.cpp; path = Realm/ObjectStore/src/sync/remote_mongo_database.cpp; sourceTree = ""; }; + CDC4582D4D70B00FB4390B77B2D1AAF2 /* LinkingObjects.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LinkingObjects.swift; path = RealmSwift/LinkingObjects.swift; sourceTree = ""; }; + CDEFA4D6E74CA20A41AD1D24A53B544D /* RLMAccessor.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMAccessor.h; path = include/RLMAccessor.h; sourceTree = ""; }; + CF42A2B7D6A7DE5BFD6EF860E0F25DAC /* RLMDecimal128.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMDecimal128.mm; path = Realm/RLMDecimal128.mm; sourceTree = ""; }; + CF9A0FF08CFBC930B36000A057A774A9 /* Platform.Linux.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Platform.Linux.swift; path = Platform/Platform.Linux.swift; sourceTree = ""; }; + CFF30630BEEB8097918CA55E8575BDF1 /* SchedulerType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SchedulerType.swift; path = RxSwift/SchedulerType.swift; sourceTree = ""; }; + D03BC09ABD830E4801045FC998EF817E /* RLMAccessor.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMAccessor.mm; path = Realm/RLMAccessor.mm; sourceTree = ""; }; + D07911509368876C1EB24C2947E4CAA2 /* SynchronizedDisposeType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SynchronizedDisposeType.swift; path = RxSwift/Concurrency/SynchronizedDisposeType.swift; sourceTree = ""; }; + D09D63DDBDEBE7C181B504886AC7819C /* CompositeDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CompositeDisposable.swift; path = RxSwift/Disposables/CompositeDisposable.swift; sourceTree = ""; }; + D0B0E4DBE82AB38A449D35BA4C6CF1CF /* RecursiveLock.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RecursiveLock.swift; path = Platform/RecursiveLock.swift; sourceTree = ""; }; + D0BF79B957BC253B9F9F622E3DA26AEE /* Producer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Producer.swift; path = RxSwift/Observables/Producer.swift; sourceTree = ""; }; + D1697E1FF125ED99D1216B93E66EAF5B /* AsyncSubject.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AsyncSubject.swift; path = RxSwift/Subjects/AsyncSubject.swift; sourceTree = ""; }; + D1809FC8B4516DAD5F0624F299B5D42D /* InfiniteSequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = InfiniteSequence.swift; path = Platform/DataStructures/InfiniteSequence.swift; sourceTree = ""; }; + D1E961D09AA076899B1338AB10A23759 /* RLMSchema.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMSchema.h; path = include/RLMSchema.h; sourceTree = ""; }; + D256F37F99E6AAC79FEEE9508D19F476 /* RxCocoa.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = RxCocoa.debug.xcconfig; sourceTree = ""; }; + D2C742FC85CDE50CD28E5956F0ADDB74 /* DispatchQueue+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "DispatchQueue+Extensions.swift"; path = "Platform/DispatchQueue+Extensions.swift"; sourceTree = ""; }; + D336EE10741FE93C320CD500327840F5 /* bson.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = bson.cpp; path = Realm/ObjectStore/src/util/bson/bson.cpp; sourceTree = ""; }; + D3A38977C4921EC3D67E5DC9A87F1E46 /* NopDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = NopDisposable.swift; path = RxSwift/Disposables/NopDisposable.swift; sourceTree = ""; }; + D3CCF36EE801B8EF56E263EAD2E92A08 /* SubscriptionDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SubscriptionDisposable.swift; path = RxSwift/Disposables/SubscriptionDisposable.swift; sourceTree = ""; }; + D4DE8D9E1178FA21D2894BA5913D157A /* RealmSwift-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RealmSwift-prefix.pch"; sourceTree = ""; }; + D53FF47C70573D21E73A4729008A809E /* RLMObjectSchema_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMObjectSchema_Private.h; path = include/RLMObjectSchema_Private.h; sourceTree = ""; }; + D57411E3F5D1FE6F06C45BB8BE6ABAE9 /* KeyPathBinder.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = KeyPathBinder.swift; path = RxCocoa/Common/KeyPathBinder.swift; sourceTree = ""; }; + D5BB9F8C6B4BDAC5D8317DFF3602B0F7 /* URLRequest+Alamofire.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "URLRequest+Alamofire.swift"; path = "Source/URLRequest+Alamofire.swift"; sourceTree = ""; }; + D5BEE546D9C98D268006E154C4DC5116 /* VirtualTimeScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = VirtualTimeScheduler.swift; path = RxSwift/Schedulers/VirtualTimeScheduler.swift; sourceTree = ""; }; + D5D3ACF1D878E195BDF9F514B113B776 /* SerialDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SerialDisposable.swift; path = RxSwift/Disposables/SerialDisposable.swift; sourceTree = ""; }; + D616E8A716D3275DEDB55B9E7F3FDA20 /* PriorityQueue.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PriorityQueue.swift; path = Platform/DataStructures/PriorityQueue.swift; sourceTree = ""; }; + D62459D303A3950966A418BDE2EF5E9D /* RxScrollViewDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxScrollViewDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxScrollViewDelegateProxy.swift; sourceTree = ""; }; D64D3EB6A4D2338F078AABB9C4B29006 /* Pods-Darner-dan-uh-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-Darner-dan-uh-acknowledgements.markdown"; sourceTree = ""; }; - D7B70AB67697E4837993DBE6B65020DB /* RxCocoa-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "RxCocoa-dummy.m"; sourceTree = ""; }; - D7D2B542D62F95B89FE0D38ED224B69E /* SynchronizedOnType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SynchronizedOnType.swift; path = RxSwift/Concurrency/SynchronizedOnType.swift; sourceTree = ""; }; + D6510CD41689DBE8602E63A8D32D93B2 /* BSON.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BSON.swift; path = RealmSwift/BSON.swift; sourceTree = ""; }; + D6B556D760F8D3AEE8A5F67DCDA5CEBF /* SortDescriptor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SortDescriptor.swift; path = RealmSwift/SortDescriptor.swift; sourceTree = ""; }; + D7079AEAB9A6E700D8AF5363DF851A2B /* RxTableViewDataSourceProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTableViewDataSourceProxy.swift; path = RxCocoa/iOS/Proxies/RxTableViewDataSourceProxy.swift; sourceTree = ""; }; + D71A83BE43E28CBF5D49703E7B114BA2 /* Platform.Linux.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Platform.Linux.swift; path = Platform/Platform.Linux.swift; sourceTree = ""; }; + D76B0D404FF9222A46B821BC2AEC07E3 /* Error.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Error.swift; path = RxSwift/Observables/Error.swift; sourceTree = ""; }; + D78FEDFFFE184B705D7E7C191AACECED /* Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Rx.swift; path = RxSwift/Rx.swift; sourceTree = ""; }; + D7BDFC60B45FCC326C52B21834773793 /* Response.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Response.swift; path = Source/Response.swift; sourceTree = ""; }; D7F42A0444759368C9C4FE7CE64E5808 /* Pods-Darner-dan-uh-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-Darner-dan-uh-frameworks.sh"; sourceTree = ""; }; - D802C03FC94B91638F7A8452AB0970DE /* AlamofireExtended.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AlamofireExtended.swift; path = Source/AlamofireExtended.swift; sourceTree = ""; }; - D9B462D6F9C2C32D5DD9210644F9E967 /* DelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DelegateProxy.swift; path = RxCocoa/Common/DelegateProxy.swift; sourceTree = ""; }; - DA38E9C97C704EC0F6A501CF4EA1F1D8 /* Debounce.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Debounce.swift; path = RxSwift/Observables/Debounce.swift; sourceTree = ""; }; - DAE78A5532DB23CBCA9FCC6ECE84C1ED /* Date+Dispatch.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Date+Dispatch.swift"; path = "RxSwift/Date+Dispatch.swift"; sourceTree = ""; }; - DD24F9D5D6B34277BF30AFF8F36FF456 /* MultipartUpload.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MultipartUpload.swift; path = Source/MultipartUpload.swift; sourceTree = ""; }; - DDC8939562013BBA0ACEB61DEC872127 /* RxCocoa.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = RxCocoa.modulemap; sourceTree = ""; }; - DDD62DE9F4F21A0A1D91A38E27DADD72 /* Driver+Subscription.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Driver+Subscription.swift"; path = "RxCocoa/Traits/Driver/Driver+Subscription.swift"; sourceTree = ""; }; - DEA3CBC33CA6668F8AA4B50FF68D5182 /* CombineLatest.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CombineLatest.swift; path = RxSwift/Observables/CombineLatest.swift; sourceTree = ""; }; - DED7C8308F5FF721B477BAA89146DBD3 /* URLConvertible+URLRequestConvertible.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "URLConvertible+URLRequestConvertible.swift"; path = "Source/URLConvertible+URLRequestConvertible.swift"; sourceTree = ""; }; - DF2AB4533884DD0CDF831A515C462271 /* Range.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Range.swift; path = RxSwift/Observables/Range.swift; sourceTree = ""; }; - DFB6810C06A88D9886C197FF72A4BFF6 /* HistoricalSchedulerTimeConverter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HistoricalSchedulerTimeConverter.swift; path = RxSwift/Schedulers/HistoricalSchedulerTimeConverter.swift; sourceTree = ""; }; - E00EC1055B4D6FC9311F59964E9DBAFE /* ParameterEncoding.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ParameterEncoding.swift; path = Source/ParameterEncoding.swift; sourceTree = ""; }; - E077EDF056ED4CC7D87B68F795366060 /* _RXDelegateProxy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = _RXDelegateProxy.m; path = RxCocoa/Runtime/_RXDelegateProxy.m; sourceTree = ""; }; - E146C0BF7BD9F63449F05D956A7582FE /* RxCocoa-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RxCocoa-umbrella.h"; sourceTree = ""; }; - E1757F396E51EFEFA58511C903B926C7 /* RxRelay.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = RxRelay.debug.xcconfig; sourceTree = ""; }; - E1DA49D0D0E1848191BFBDFF1115D0FD /* RxCocoa-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RxCocoa-prefix.pch"; sourceTree = ""; }; - E2228729E07329BC7A9BAC6C2F232715 /* Platform.Darwin.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Platform.Darwin.swift; path = Platform/Platform.Darwin.swift; sourceTree = ""; }; - E352BDFF2115C51292AB8586490ED568 /* InvocableType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = InvocableType.swift; path = RxSwift/Schedulers/Internal/InvocableType.swift; sourceTree = ""; }; - E475D56DD17EEA4776F97F15675B7FC9 /* AddRef.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AddRef.swift; path = RxSwift/Observables/AddRef.swift; sourceTree = ""; }; - E49206FA7A03E65E86919B0D459CE145 /* Lock.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Lock.swift; path = RxSwift/Concurrency/Lock.swift; sourceTree = ""; }; - E4D8EC26F7663976A02C5C91105B1955 /* RxTableViewDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTableViewDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxTableViewDelegateProxy.swift; sourceTree = ""; }; - E64B5D5BECB58F8396FB393EA62C09B6 /* RxRelay.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = RxRelay.modulemap; sourceTree = ""; }; - E7AE4D23E0388E575CFC29BEE9137092 /* RxCocoaRuntime.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RxCocoaRuntime.h; path = RxCocoa/Runtime/include/RxCocoaRuntime.h; sourceTree = ""; }; - E7D752C895BA6DE13734367372FBE34D /* Deferred.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Deferred.swift; path = RxSwift/Observables/Deferred.swift; sourceTree = ""; }; - E7F8070F6E169181CC8FF298703849CA /* DispatchQueueConfiguration.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DispatchQueueConfiguration.swift; path = RxSwift/Schedulers/Internal/DispatchQueueConfiguration.swift; sourceTree = ""; }; - E9A8EBE1012F49AF81A9AA577843D1B2 /* Request.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Request.swift; path = Source/Request.swift; sourceTree = ""; }; - EAF04A13053CD1DF27E37D06B154FA99 /* UISearchBar+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UISearchBar+Rx.swift"; path = "RxCocoa/iOS/UISearchBar+Rx.swift"; sourceTree = ""; }; - EBF95597E8C41B20BE5BD5A60256886A /* Validation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Validation.swift; path = Source/Validation.swift; sourceTree = ""; }; + D94963727939C0F7D500399F2C8178BD /* Realm.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Realm.debug.xcconfig; sourceTree = ""; }; + DA3598979CE772D50E44DD120ED96A26 /* RLMApp.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMApp.h; path = include/RLMApp.h; sourceTree = ""; }; + DC9BCB20DF73819810C2E781C03CA3F5 /* LockOwnerType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LockOwnerType.swift; path = RxSwift/Concurrency/LockOwnerType.swift; sourceTree = ""; }; + DCAB5D7A477412E48B74F60F519DC73F /* HTTPMethod.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HTTPMethod.swift; path = Source/HTTPMethod.swift; sourceTree = ""; }; + DDFE63997FF8C1AE2617A1BC92C4E1BE /* RetryPolicy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RetryPolicy.swift; path = Source/RetryPolicy.swift; sourceTree = ""; }; + DF0BD4151C0E4A0190952BFF69D011D9 /* SkipUntil.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SkipUntil.swift; path = RxSwift/Observables/SkipUntil.swift; sourceTree = ""; }; + DF1B0D9D0F144EA76A970202FBA81679 /* RxCocoa.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = RxCocoa.release.xcconfig; sourceTree = ""; }; + DFD3A4F8CD51D3B9F9B303137A7D436D /* object_notifier.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = object_notifier.cpp; path = Realm/ObjectStore/src/impl/object_notifier.cpp; sourceTree = ""; }; + E08C704F7CD7533F4E2B2A0B74F8A786 /* Alamofire.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Alamofire.swift; path = Source/Alamofire.swift; sourceTree = ""; }; + E0A2AA962931BB09A9089FEC7D8A1E30 /* UILabel+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UILabel+Rx.swift"; path = "RxCocoa/iOS/UILabel+Rx.swift"; sourceTree = ""; }; + E18421398E99489371ED0FFD97473558 /* RxTableViewDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTableViewDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxTableViewDelegateProxy.swift; sourceTree = ""; }; + E19615B9A1BDAE31426AE13F76B0863B /* InfiniteSequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = InfiniteSequence.swift; path = Platform/DataStructures/InfiniteSequence.swift; sourceTree = ""; }; + E1B03021B1EFA35F821B99376BEAB3E5 /* RLMProperty_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMProperty_Private.h; path = include/RLMProperty_Private.h; sourceTree = ""; }; + E34C1373861581DDF0256BE646DCE7B7 /* UIButton+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIButton+Rx.swift"; path = "RxCocoa/iOS/UIButton+Rx.swift"; sourceTree = ""; }; + E3845E9FA4FDBDCE093112D811EA05B6 /* sync_file.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = sync_file.cpp; path = Realm/ObjectStore/src/sync/impl/sync_file.cpp; sourceTree = ""; }; + E396837EA8B140BEE2C9712CA5D7C855 /* async_open_task.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = async_open_task.cpp; path = Realm/ObjectStore/src/sync/async_open_task.cpp; sourceTree = ""; }; + E3AD1821877DA40E0007A480B71794B6 /* UIGestureRecognizer+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIGestureRecognizer+Rx.swift"; path = "RxCocoa/iOS/UIGestureRecognizer+Rx.swift"; sourceTree = ""; }; + E40B4BC9B3ADB2F167F2CD1BADA00C3B /* AnyObserver.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AnyObserver.swift; path = RxSwift/AnyObserver.swift; sourceTree = ""; }; + E4BA811ABA1EEBC0D4084E3469D31939 /* Date+Dispatch.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Date+Dispatch.swift"; path = "RxSwift/Date+Dispatch.swift"; sourceTree = ""; }; + E4CCB369D05C229C176B9F89E63D0202 /* Deprecated.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Deprecated.swift; path = RxCocoa/Deprecated.swift; sourceTree = ""; }; + E5A7027385985B7AE9F3DCD243487913 /* RLMSyncConfiguration_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMSyncConfiguration_Private.h; path = include/RLMSyncConfiguration_Private.h; sourceTree = ""; }; + E617414E007DAF8549B6F6E1177385B7 /* RxSwift.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = RxSwift.debug.xcconfig; sourceTree = ""; }; + E6B16B29794E989049ED056119609AD2 /* object_changeset.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = object_changeset.cpp; path = Realm/ObjectStore/src/object_changeset.cpp; sourceTree = ""; }; + E6BDE8A8A7F672F687F13615707178F2 /* RLMPushClient.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMPushClient.mm; path = Realm/RLMPushClient.mm; sourceTree = ""; }; + E6E3240C5482DA163A54D2D6674527F8 /* RxMutableBox.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxMutableBox.swift; path = RxSwift/RxMutableBox.swift; sourceTree = ""; }; + E79832AF9F4498DB60827C8FD193A224 /* Alamofire.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = Alamofire.modulemap; sourceTree = ""; }; + E7A5C3E41BA9D9DADDCD330F668DDF2C /* PublishRelay+Signal.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "PublishRelay+Signal.swift"; path = "RxCocoa/Traits/Signal/PublishRelay+Signal.swift"; sourceTree = ""; }; + E7C1743DFA2101E0EEF4044DFE0AF806 /* Error.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Error.swift; path = RealmSwift/Error.swift; sourceTree = ""; }; + E7C3A5B6C8097F3302E2D59329A8090B /* Notifications.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Notifications.swift; path = Source/Notifications.swift; sourceTree = ""; }; + E7C60E74C9D0F38FC7FC0B6E61907DB3 /* Realm-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Realm-Info.plist"; sourceTree = ""; }; + E7FD872F1EDC128CFFAD6F841A90F6AF /* Realm.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Realm.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + E829B940061EA02DBFC78ACD6DC4908A /* RxPickerViewDataSourceProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxPickerViewDataSourceProxy.swift; path = RxCocoa/iOS/Proxies/RxPickerViewDataSourceProxy.swift; sourceTree = ""; }; + E83B6C534733423F02985C506A911F49 /* AsSingle.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AsSingle.swift; path = RxSwift/Observables/AsSingle.swift; sourceTree = ""; }; + E8429204616E055CBD82FD738DC17DB1 /* RxTableViewReactiveArrayDataSource.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTableViewReactiveArrayDataSource.swift; path = RxCocoa/iOS/DataSources/RxTableViewReactiveArrayDataSource.swift; sourceTree = ""; }; + E8A86E54BF1F17E2E4F94C724E812FF5 /* RLMSwiftSupport.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RLMSwiftSupport.m; path = Realm/RLMSwiftSupport.m; sourceTree = ""; }; + E8C296B43EC37369C8F90E4070E1A3AC /* RLMUserAPIKey.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMUserAPIKey.h; path = include/RLMUserAPIKey.h; sourceTree = ""; }; + E9568E57C0E585A32EE7E2863AD45A12 /* NSTextView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSTextView+Rx.swift"; path = "RxCocoa/macOS/NSTextView+Rx.swift"; sourceTree = ""; }; + E976DC771B75E8F4C938E082D2DC67E9 /* ControlProperty+Driver.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ControlProperty+Driver.swift"; path = "RxCocoa/Traits/Driver/ControlProperty+Driver.swift"; sourceTree = ""; }; + E9C21DE52F2543B4CBA30DFA7D153125 /* NSObject+Rx+RawRepresentable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSObject+Rx+RawRepresentable.swift"; path = "RxCocoa/Foundation/NSObject+Rx+RawRepresentable.swift"; sourceTree = ""; }; + E9FE377B8B9D00BE6088A6D9BBE2CD67 /* RLMListBase.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMListBase.mm; path = Realm/RLMListBase.mm; sourceTree = ""; }; + EA516D24BB56BA4C75C278EF40971A4A /* Observable+Bind.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Observable+Bind.swift"; path = "RxCocoa/Common/Observable+Bind.swift"; sourceTree = ""; }; + EA7DFB8251965F74E154260AC1B1C118 /* Util.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Util.swift; path = RealmSwift/Util.swift; sourceTree = ""; }; + EB4E75C2A8E07889C7E2FF8D4BF35FD9 /* RLMNetworkTransport.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMNetworkTransport.mm; path = Realm/RLMNetworkTransport.mm; sourceTree = ""; }; + EB9D165744F522C3327959949201497A /* RxCocoa-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "RxCocoa-dummy.m"; sourceTree = ""; }; + EC2DBA6FA3B5F0017EAA6CDA39A7EB73 /* _RXObjCRuntime.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = _RXObjCRuntime.h; path = RxCocoa/Runtime/include/_RXObjCRuntime.h; sourceTree = ""; }; + ECF4A10D2278E7683FAF28C4118469C9 /* _RXDelegateProxy.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = _RXDelegateProxy.h; path = RxCocoa/Runtime/include/_RXDelegateProxy.h; sourceTree = ""; }; + EDF43D98B673E5BD269472020316C22D /* Utils.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Utils.swift; path = RxRelay/Utils.swift; sourceTree = ""; }; EE3BADDC405C8AE26B9B4E46189885EF /* Pods-Darner-dan-uh-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-Darner-dan-uh-acknowledgements.plist"; sourceTree = ""; }; - EFD86B77C2B2C4EB905B878E78BAEB49 /* BehaviorRelay+Driver.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "BehaviorRelay+Driver.swift"; path = "RxCocoa/Traits/Driver/BehaviorRelay+Driver.swift"; sourceTree = ""; }; - EFE1CB5CD9AB2B1456DF66F04802FB88 /* RxRelay-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RxRelay-umbrella.h"; sourceTree = ""; }; - EFFD32926EA4BD2FE54020AEF89AF043 /* AFError.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AFError.swift; path = Source/AFError.swift; sourceTree = ""; }; - F0937A0C174A8902E89AECBFF3DC0B0A /* AsyncSubject.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AsyncSubject.swift; path = RxSwift/Subjects/AsyncSubject.swift; sourceTree = ""; }; - F0FB17359AB6A988872D730206FFEBD8 /* CurrentThreadScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CurrentThreadScheduler.swift; path = RxSwift/Schedulers/CurrentThreadScheduler.swift; sourceTree = ""; }; - F137248CF855D03E9C99C333CC2EC7C7 /* _RX.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = _RX.m; path = RxCocoa/Runtime/_RX.m; sourceTree = ""; }; - F2A94F072357E44438225A4EDB084B20 /* UITabBar+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UITabBar+Rx.swift"; path = "RxCocoa/iOS/UITabBar+Rx.swift"; sourceTree = ""; }; - F2B1AF1AE00E323A2E2686D324D76D42 /* AtomicInt.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AtomicInt.swift; path = Platform/AtomicInt.swift; sourceTree = ""; }; - F39428AAD1A8C28477229F95C566692C /* InfiniteSequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = InfiniteSequence.swift; path = Platform/DataStructures/InfiniteSequence.swift; sourceTree = ""; }; - F3B5DC9315EC4C7837FEE02A29842F21 /* UIViewController+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIViewController+Rx.swift"; path = "RxCocoa/iOS/UIViewController+Rx.swift"; sourceTree = ""; }; - F45F941037CC8A4B549EB846D4E8A16C /* Deprecated.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Deprecated.swift; path = RxSwift/Deprecated.swift; sourceTree = ""; }; - F5FFF26103E94AD4A7D0FC160FBB109D /* Observable+Bind.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Observable+Bind.swift"; path = "RxRelay/Observable+Bind.swift"; sourceTree = ""; }; - F6A5D86D62C130F07B87521EC453E5AC /* RxCocoa.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RxCocoa.h; path = RxCocoa/RxCocoa.h; sourceTree = ""; }; - F781B391DCFF6B77F0E2AF4C6837C1FD /* RxRelay-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "RxRelay-dummy.m"; sourceTree = ""; }; - F7C09FCBBBE54CC96607AD5FEA3E1BBE /* Binder.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Binder.swift; path = RxCocoa/Common/Binder.swift; sourceTree = ""; }; - F8E687F68A8DB2E9F866809491177BF6 /* Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Rx.swift; path = RxSwift/Rx.swift; sourceTree = ""; }; - FA22C9E930D6202E623EDBBF50205501 /* _RXObjCRuntime.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = _RXObjCRuntime.h; path = RxCocoa/Runtime/include/_RXObjCRuntime.h; sourceTree = ""; }; - FB3D9A1711AA366FD5F09FEA00DE390C /* URLSessionConfiguration+Alamofire.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "URLSessionConfiguration+Alamofire.swift"; path = "Source/URLSessionConfiguration+Alamofire.swift"; sourceTree = ""; }; - FBB241B5200E6C6633679983A73E86A8 /* Signal+Subscription.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Signal+Subscription.swift"; path = "RxCocoa/Traits/Signal/Signal+Subscription.swift"; sourceTree = ""; }; - FBECBCED3E2BF4E98A2BF45ADA22CE63 /* URLSession+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "URLSession+Rx.swift"; path = "RxCocoa/Foundation/URLSession+Rx.swift"; sourceTree = ""; }; - FC49BC33E21E74FBF76137DA8666F343 /* ObserveOn.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObserveOn.swift; path = RxSwift/Observables/ObserveOn.swift; sourceTree = ""; }; - FC4BEA2E92ED8D2F5D72FBE3819F6DCD /* URLRequest+Alamofire.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "URLRequest+Alamofire.swift"; path = "Source/URLRequest+Alamofire.swift"; sourceTree = ""; }; - FE852069019561008E4F1D17B2D8A82C /* Reactive.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Reactive.swift; path = RxSwift/Reactive.swift; sourceTree = ""; }; + EE3FF4B388652B33DDD06D2496327330 /* NSError+RLMSync.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "NSError+RLMSync.h"; path = "include/NSError+RLMSync.h"; sourceTree = ""; }; + EE580AFDE74A4970B85874EF92F68E55 /* RxCocoaObjCRuntimeError+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "RxCocoaObjCRuntimeError+Extensions.swift"; path = "RxCocoa/Common/RxCocoaObjCRuntimeError+Extensions.swift"; sourceTree = ""; }; + EECDA48CF4FF1C4C110AF794275ED748 /* RLMOptionalBase.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMOptionalBase.mm; path = Realm/RLMOptionalBase.mm; sourceTree = ""; }; + EF1E92FCED708D7E4565A3867B965CEA /* Session.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Session.swift; path = Source/Session.swift; sourceTree = ""; }; + F0506E6B74E3BA42E9372DEE4243E6E5 /* RLMAnalytics.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMAnalytics.mm; path = Realm/RLMAnalytics.mm; sourceTree = ""; }; + F0AB722C3C0CD69B263401F5156BCE96 /* RLMMongoDatabase.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMMongoDatabase.h; path = include/RLMMongoDatabase.h; sourceTree = ""; }; + F0B9E37063F2A18ADE927C78193C3C17 /* SingleAssignmentDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SingleAssignmentDisposable.swift; path = RxSwift/Disposables/SingleAssignmentDisposable.swift; sourceTree = ""; }; + F32BA08422C23AB8697543BF4EE4A6EF /* ConcurrentMainScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConcurrentMainScheduler.swift; path = RxSwift/Schedulers/ConcurrentMainScheduler.swift; sourceTree = ""; }; + F350DB4C798D0F260C3AE1891ECEEAF6 /* Logging.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Logging.swift; path = RxCocoa/Foundation/Logging.swift; sourceTree = ""; }; + F39CD0793FF148ED71A50FF908326D1C /* UISwitch+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UISwitch+Rx.swift"; path = "RxCocoa/iOS/UISwitch+Rx.swift"; sourceTree = ""; }; + F3DFF0752CD021478CF09DE2604A4F00 /* Aliases.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Aliases.swift; path = RealmSwift/Aliases.swift; sourceTree = ""; }; + F440813566CE4FEBB85A775215C2B1C1 /* Switch.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Switch.swift; path = RxSwift/Observables/Switch.swift; sourceTree = ""; }; + F4B9ABAE1767714182046DFA8A95ADB3 /* SharedSequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SharedSequence.swift; path = RxCocoa/Traits/SharedSequence/SharedSequence.swift; sourceTree = ""; }; + F5BDCEE005C5A46BC2C40BA42571EC23 /* RxRelay.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = RxRelay.debug.xcconfig; sourceTree = ""; }; + F5D1E68D8A1529F9E5FE1179FF21A6A8 /* AFError.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AFError.swift; path = Source/AFError.swift; sourceTree = ""; }; + F61EBC120DB0824119271C50578D5E34 /* DelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DelegateProxy.swift; path = RxCocoa/Common/DelegateProxy.swift; sourceTree = ""; }; + F66800F860EEF91C7FD4EE6DAF26617E /* UIRefreshControl+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIRefreshControl+Rx.swift"; path = "RxCocoa/iOS/UIRefreshControl+Rx.swift"; sourceTree = ""; }; + F6D933CEA78AFF25F8238B2086E0141E /* sync_session.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = sync_session.cpp; path = Realm/ObjectStore/src/sync/sync_session.cpp; sourceTree = ""; }; + F6DA322294286F1B63182F5BBF223970 /* Property.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Property.swift; path = RealmSwift/Property.swift; sourceTree = ""; }; + F6EC00D8A01B8A46996F24C44D7E9AEB /* app_utils.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = app_utils.cpp; path = Realm/ObjectStore/src/sync/app_utils.cpp; sourceTree = ""; }; + F8216BA641FC62DCBDFC9C0268B56873 /* RLMPlatform.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMPlatform.h; path = include/RLMPlatform.h; sourceTree = ""; }; + F8FBEFAD40A3F50A73E9886A885DED2A /* SchedulerServices+Emulation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "SchedulerServices+Emulation.swift"; path = "RxSwift/Schedulers/SchedulerServices+Emulation.swift"; sourceTree = ""; }; + F937B33AB2349728EAEBE30B14ACC732 /* MainScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MainScheduler.swift; path = RxSwift/Schedulers/MainScheduler.swift; sourceTree = ""; }; + F9CCD49060C94F7804A9AC7735C7092F /* ServerTrustEvaluation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ServerTrustEvaluation.swift; path = Source/ServerTrustEvaluation.swift; sourceTree = ""; }; + FA1E5A489614197B059BD7EF0B219DC0 /* TakeUntil.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TakeUntil.swift; path = RxSwift/Observables/TakeUntil.swift; sourceTree = ""; }; + FA76328C537A503C1B77311D0A2C3533 /* PrimitiveSequence+Zip+arity.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "PrimitiveSequence+Zip+arity.swift"; path = "RxSwift/Traits/PrimitiveSequence+Zip+arity.swift"; sourceTree = ""; }; + FA85CDF926CEB090AC0FA2E804C63579 /* RealmSwift.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = RealmSwift.release.xcconfig; sourceTree = ""; }; + FAE53A746F752DD65ED349FBDF528401 /* SessionDelegate.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SessionDelegate.swift; path = Source/SessionDelegate.swift; sourceTree = ""; }; + FB985A53F39481FA23B528D7486A0188 /* Driver.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Driver.swift; path = RxCocoa/Traits/Driver/Driver.swift; sourceTree = ""; }; + FB9B48285BCCDF74DAAC90326D85758F /* RLMConstants.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RLMConstants.m; path = Realm/RLMConstants.m; sourceTree = ""; }; + FBAD0D294AEAE312E17C2C83086A8B1E /* RxAlamofire-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "RxAlamofire-Info.plist"; sourceTree = ""; }; + FBAEE5BB4EA38C59A455590BED8D03F0 /* RLMPredicateUtil.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMPredicateUtil.mm; path = Realm/RLMPredicateUtil.mm; sourceTree = ""; }; + FC0213C64A67607536CA92B3B9EDC152 /* binding_callback_thread_observer.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = binding_callback_thread_observer.cpp; path = Realm/ObjectStore/src/binding_callback_thread_observer.cpp; sourceTree = ""; }; + FC46534386377743676587034A95CBB9 /* EventMonitor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = EventMonitor.swift; path = Source/EventMonitor.swift; sourceTree = ""; }; + FCB6E9B1FB99D7F09E19DB476EDAE289 /* Empty.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Empty.swift; path = RxSwift/Observables/Empty.swift; sourceTree = ""; }; + FD5CA30B727DEEFA619FD1BBCFB85F1C /* UIScrollView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIScrollView+Rx.swift"; path = "RxCocoa/iOS/UIScrollView+Rx.swift"; sourceTree = ""; }; + FE3831D5F8E37757EFBABC495A6FBCA7 /* SharedSequence+Operators.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "SharedSequence+Operators.swift"; path = "RxCocoa/Traits/SharedSequence/SharedSequence+Operators.swift"; sourceTree = ""; }; + FE7B05FF864BAFF2C284FC3444530D77 /* Migration.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Migration.swift; path = RealmSwift/Migration.swift; sourceTree = ""; }; + FEE52232218966D95056A2B60A630CB3 /* URLSessionConfiguration+Alamofire.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "URLSessionConfiguration+Alamofire.swift"; path = "Source/URLSessionConfiguration+Alamofire.swift"; sourceTree = ""; }; + FEF1973B4E9C40CAAAB341CD3C57C779 /* RLMUpdateResult.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMUpdateResult.h; path = include/RLMUpdateResult.h; sourceTree = ""; }; FF8B264DFE802855D5D67E7CDDABFC3C /* RxRelay.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = RxRelay.framework; path = RxRelay.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + FF9E866F54DE7EC41EC272983D1A5357 /* TextInput.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TextInput.swift; path = RxCocoa/Common/TextInput.swift; sourceTree = ""; }; + FFCE456C658E2F0004F7194F0677A751 /* ConnectableObservableType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConnectableObservableType.swift; path = RxSwift/ConnectableObservableType.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ - 2255531EBE8D50554450E2F565BACEAF /* Frameworks */ = { + 057906F6EC29C9F709DE046EDDB48C46 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 8C1C0B1D783B20B65C19D3BA181A0FDA /* Foundation.framework in Frameworks */, - FB063097DA98E40D353B2ABFD8407226 /* RxSwift.framework in Frameworks */, + A8FF5A60B4CF0B1CAA86AC209A6E01EA /* Alamofire.framework in Frameworks */, + 7C2436D7801191C2D662E3A0F8B63C14 /* Foundation.framework in Frameworks */, + B675A06F34FA4D0B0BE9BDFE839B5B02 /* RxSwift.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -768,263 +1364,195 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 078528915ABA677900726FAE8A8D0D05 /* Foundation.framework in Frameworks */, + A9357EBC2D7A15D3E3891A27CC8FE8CA /* Foundation.framework in Frameworks */, 598FFFD4D64B8A54CD141F10274D8F4F /* RxRelay.framework in Frameworks */, 7B89A3FFC01803E264A95FEC8BC0605C /* RxSwift.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; - 9590D3FE7A79CD7CBEE3F346E8C19D4D /* Frameworks */ = { + 52D162688CCA712D71B4749012FE8B3B /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + EC2C05D6ADBA912231F8410FA423231B /* Foundation.framework in Frameworks */, + EF8315A2DB22F71F180696A79E9FF10A /* Security.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 6E214DBF83D08F1F24944DC4EB113FDD /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B68444C69EC1FEC73B45800AC2441E1D /* Foundation.framework in Frameworks */, + 18E51599DD624389FA38167F927EBDBD /* RxSwift.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 7AED940AC55E9545F0718C44CB713A9D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + EE1C2E504E036D334BDE2EBBE58452D8 /* Foundation.framework in Frameworks */, + 8FEC9AAFEC18ECC0FFA72C6FB5344CF2 /* Realm.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 9088A551B5300E32D3C328B75D0646E8 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - A738C2A39C0150BBA7EA5EC19B95F03E /* CFNetwork.framework in Frameworks */, - F6B16DC8CADA07287C6A372AC8AD787C /* Foundation.framework in Frameworks */, + 2D4A41728C9E40252BFA4AFD7D5C4D5B /* Foundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; - D3B43FC517723ACC12C89F4A46FDFD51 /* Frameworks */ = { + 9590D3FE7A79CD7CBEE3F346E8C19D4D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 42FF7C3D0686E7AE441F757528BD18B3 /* Foundation.framework in Frameworks */, + A9C7B29D4878F1690BBE3F8195CF0313 /* CFNetwork.framework in Frameworks */, + 476D5F33E25386C60D6BD75C4FA97C67 /* Foundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; - E8763B3979EF0B32E216122982C7987D /* Frameworks */ = { + AC578672F4D30A165E966BE1FC1E79D7 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - FA9D389454C2CBABD95D657BCE7C3595 /* Foundation.framework in Frameworks */, + 27C1FD437952EC44DA722CA3E38D4F39 /* Foundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 251798CE4B89C4EF770C7E95A96D19F5 /* Alamofire */ = { + 054547898E4BCFD63AD5ECC79517AB20 /* Support Files */ = { isa = PBXGroup; children = ( - EFFD32926EA4BD2FE54020AEF89AF043 /* AFError.swift */, - AD5B005E3CB1E9CBE5F6C8F98D79819A /* Alamofire.swift */, - D802C03FC94B91638F7A8452AB0970DE /* AlamofireExtended.swift */, - 201FBAFD4A9D9FD6A838B9F963C76795 /* AuthenticationInterceptor.swift */, - 43A58125D39C8209160D767B9FCD6715 /* CachedResponseHandler.swift */, - 7D82EFD974A7B79DCB06387BFA6925C9 /* Combine.swift */, - 2A045B4142C036B090AF9E5756BB4564 /* DispatchQueue+Alamofire.swift */, - 64B2FF80E466BCBACC87D06E77E7DE42 /* EventMonitor.swift */, - 68CD61BA0DC293FEC7C65FEABFC9CF7B /* HTTPHeaders.swift */, - 2671F655EE04D6C0885DE056312A4A03 /* HTTPMethod.swift */, - A8739FB420371A1A2154926841001385 /* MultipartFormData.swift */, - DD24F9D5D6B34277BF30AFF8F36FF456 /* MultipartUpload.swift */, - 96FF3C3F6E5DD44B9D6F1953F267234B /* NetworkReachabilityManager.swift */, - 8CEC26A7701127C819179F739A292434 /* Notifications.swift */, - 5399BBECE22553D36BE196941994439E /* OperationQueue+Alamofire.swift */, - 47FFFD359F4E6910FBFA61F227E03B31 /* ParameterEncoder.swift */, - E00EC1055B4D6FC9311F59964E9DBAFE /* ParameterEncoding.swift */, - 39DCD13C6B63A7BC27F88C977C14B2D8 /* Protected.swift */, - 63F81B444952A4A8B726B8F7E7F2DCB4 /* RedirectHandler.swift */, - E9A8EBE1012F49AF81A9AA577843D1B2 /* Request.swift */, - 2C25F1A4546932BF5BD6CDB8F6D03DE9 /* RequestInterceptor.swift */, - CC960F0E19C0206FFA0D32C0374AB02E /* RequestTaskMap.swift */, - A183A6FC3E9F3E14E10154C6FE034A12 /* Response.swift */, - 6BC6717EFA577FA1D6989094852AB703 /* ResponseSerialization.swift */, - 264FA160F97784840AFDE866D4E3409D /* Result+Alamofire.swift */, - 847E8C3BE479BE92FDDC97E5D40D4DCE /* RetryPolicy.swift */, - 3E7397B9BB16FC5807B0C849884DED48 /* ServerTrustEvaluation.swift */, - A569CB8DDCF470136457D1CEF4A37441 /* Session.swift */, - CEE931632251E7215CB2A71E60D0FD55 /* SessionDelegate.swift */, - D27DC19B8134DEAE3D1C8C556C7A2E59 /* StringEncoding+Alamofire.swift */, - DED7C8308F5FF721B477BAA89146DBD3 /* URLConvertible+URLRequestConvertible.swift */, - 7E5D3D875EA46CC50F03F97C512911F0 /* URLEncodedFormEncoder.swift */, - FC4BEA2E92ED8D2F5D72FBE3819F6DCD /* URLRequest+Alamofire.swift */, - FB3D9A1711AA366FD5F09FEA00DE390C /* URLSessionConfiguration+Alamofire.swift */, - EBF95597E8C41B20BE5BD5A60256886A /* Validation.swift */, - 2E4B290D55308E9EA12B4AC1969138B6 /* Support Files */, + 351FE5E0BB710A20BA562FAA785B977A /* RxSwift.modulemap */, + 398354D20FA08BCFAF261A15A601B056 /* RxSwift-dummy.m */, + 4B4DC0F0B575AE2E7C0CB9D6293F8333 /* RxSwift-Info.plist */, + 413A00C1692E2DBDCF425033FC1A5200 /* RxSwift-prefix.pch */, + 202EAEE640EB38B4F0DFDFD11149CDB4 /* RxSwift-umbrella.h */, + E617414E007DAF8549B6F6E1177385B7 /* RxSwift.debug.xcconfig */, + 1BBAA07630A36165CB5BFE215FF727E2 /* RxSwift.release.xcconfig */, ); - name = Alamofire; - path = Alamofire; + name = "Support Files"; + path = "../Target Support Files/RxSwift"; sourceTree = ""; }; - 2E4B290D55308E9EA12B4AC1969138B6 /* Support Files */ = { + 0E9CD0ACB2EF441FE7BD12C20133DD57 /* Support Files */ = { isa = PBXGroup; children = ( - 32835977A2758FB8C93C35BC8AF41145 /* Alamofire.modulemap */, - 991D2CD16B3194CA4599C283DBE54B90 /* Alamofire-dummy.m */, - 369F2D26E42DB35A68DD079DB5EC8CE0 /* Alamofire-Info.plist */, - 313153C53456E2FB1F84D5E8C9ED46FC /* Alamofire-prefix.pch */, - C669CA7E16725DF7F9C79E88797A2EFC /* Alamofire-umbrella.h */, - 2E187C471E348C73FE75C9A27421B443 /* Alamofire.debug.xcconfig */, - 66D915A4C32A6B2AE8EA8CDD952CCF81 /* Alamofire.release.xcconfig */, + E79832AF9F4498DB60827C8FD193A224 /* Alamofire.modulemap */, + A8BFDC432C055B3060BC610A590B6D65 /* Alamofire-dummy.m */, + 3C97DEF2379317945ADFDFD934CC62FA /* Alamofire-Info.plist */, + 8474F500BF2F1D1E0C3B2C645C25E944 /* Alamofire-prefix.pch */, + 2A1F51107743C21D53321F2E4C3C2B12 /* Alamofire-umbrella.h */, + 3A40B0E7398EBDFA5BB36A1A3D484D15 /* Alamofire.debug.xcconfig */, + 4C01E6FADE447436D88928C88EC55978 /* Alamofire.release.xcconfig */, ); name = "Support Files"; path = "../Target Support Files/Alamofire"; sourceTree = ""; }; - 37D13EE4114B0876CB8A107C47F2C26D /* RxSwift */ = { + 1093C52C2C9A4662BB939F211CCCA46F /* Core */ = { isa = PBXGroup; children = ( - E475D56DD17EEA4776F97F15675B7FC9 /* AddRef.swift */, - 33861B0287E2C5260CA418BDE89B675D /* Amb.swift */, - 214A58EDDB0F4A08D69BC72243ACE4A8 /* AnonymousDisposable.swift */, - 808E993F2D6447824333774C0C6EF094 /* AnonymousObserver.swift */, - 3A6FB965F9F761670F3AE2F6485D5E11 /* AnyObserver.swift */, - B0163143A6F2D322EA65C9B165D5E219 /* AsMaybe.swift */, - BBD157BE8BD65CAD1F1FD75AEB41A744 /* AsSingle.swift */, - B38ABF51BABC1CD386D2BFB4A0F07773 /* AsyncLock.swift */, - F0937A0C174A8902E89AECBFF3DC0B0A /* AsyncSubject.swift */, - F2B1AF1AE00E323A2E2686D324D76D42 /* AtomicInt.swift */, - 8FFF273E60390BCB4D3FDF0CF08E2348 /* Bag.swift */, - 700A4CD2C06E3944CED95A0F3210EDC2 /* Bag+Rx.swift */, - 6C2486F75744B1FC4A37CD9456E933D8 /* BehaviorSubject.swift */, - 5D51CA2749FDF55B4FCB399B3C2D0CD2 /* BinaryDisposable.swift */, - B8013AA35BA7A79039E7A97B8CD16095 /* BooleanDisposable.swift */, - 96D5C46415477108721579DE2581D8B8 /* Buffer.swift */, - 43EE4AC30D4D78D61696489C29D9CC3E /* Cancelable.swift */, - 4E45254E5CC9E0AC1386E062A11CF266 /* Catch.swift */, - DEA3CBC33CA6668F8AA4B50FF68D5182 /* CombineLatest.swift */, - BF5989B02E82DCF650D22F04BEF8CD45 /* CombineLatest+arity.swift */, - 1C4249898DAC7D8426ECFEB9568ECE08 /* CombineLatest+Collection.swift */, - AABC376B1A706EB2C475BA1F3EC6C4B7 /* CompactMap.swift */, - 5AB7D69D293E93ED1C08B79BA59670FF /* Completable.swift */, - 1D7F5512735FA9C93F058AB1204177B7 /* Completable+AndThen.swift */, - 65E6B5B902603AF8C36756D07E7024DB /* CompositeDisposable.swift */, - AA6709C059CE7E7AE6B666EC6A288782 /* Concat.swift */, - 895A56F29AE70279A3FEDF60F962626C /* ConcurrentDispatchQueueScheduler.swift */, - B5BECC5023B1D8885F941AFAB93B43EB /* ConcurrentMainScheduler.swift */, - A9906331734777309DFC58F7387FF429 /* ConnectableObservableType.swift */, - 2D3DB0FAE03FDA2754ED33CD92F81F37 /* Create.swift */, - F0FB17359AB6A988872D730206FFEBD8 /* CurrentThreadScheduler.swift */, - DAE78A5532DB23CBCA9FCC6ECE84C1ED /* Date+Dispatch.swift */, - DA38E9C97C704EC0F6A501CF4EA1F1D8 /* Debounce.swift */, - 7EBCC7FF0F228A25D24C5FB31329EB64 /* Debug.swift */, - 991AB91BD9AFEC0939936D4D91083DA9 /* DefaultIfEmpty.swift */, - E7D752C895BA6DE13734367372FBE34D /* Deferred.swift */, - AD70AA8FF2276F495F6B026715273D18 /* Delay.swift */, - 9C7FB4FD7CE785118A94BC728E538524 /* DelaySubscription.swift */, - 12D504CEC3F2DA1041E43AFAE3A3CE89 /* Dematerialize.swift */, - F45F941037CC8A4B549EB846D4E8A16C /* Deprecated.swift */, - 08877CA69F0BFBF0E65E49E70100C379 /* DispatchQueue+Extensions.swift */, - E7F8070F6E169181CC8FF298703849CA /* DispatchQueueConfiguration.swift */, - 386FAD9AC5C475D7BA99FC1A87649B67 /* Disposable.swift */, - CE61BF1C347838ECDC5CA622A6258781 /* Disposables.swift */, - 99BDD186EF36401951391CA36F2BD69D /* DisposeBag.swift */, - 1A9C779046CE2DFB9920B383771BF3E8 /* DisposeBase.swift */, - 55D718D09D4BA0E6833E730CA280D373 /* DistinctUntilChanged.swift */, - 8ADD934EFC16C04986525A256FAF54FC /* Do.swift */, - 0D82BAC61F2EC7EFD05AB9698294168C /* ElementAt.swift */, - A1C293648167E9015382D1EED1250993 /* Empty.swift */, - AC32F440BB6CD7FAA9A95920E6307107 /* Enumerated.swift */, - 2053CBA7F32D1B5DD6A732548723F7CA /* Error.swift */, - 7118B325E21EA425E6E5598213DEB350 /* Errors.swift */, - 9CC684A247E2C996A5D7B318E5400CD6 /* Event.swift */, - A5DB93213D8F24A4193F7FC23804F47B /* Filter.swift */, - 1751F9AB9C2E25B9A71A82CDE9604A55 /* First.swift */, - 2647AC98C4E44EA259D099263375ABA1 /* Generate.swift */, - 69272EAAED861BAC838702AA74D4304E /* GroupBy.swift */, - 3AE97F55029A327A68BA15B8A7E84BE6 /* GroupedObservable.swift */, - 77BAE41DE8F15764B25F01E46AFBF15E /* HistoricalScheduler.swift */, - DFB6810C06A88D9886C197FF72A4BFF6 /* HistoricalSchedulerTimeConverter.swift */, - 8C2C0BA6DCCAC653154B4C7C85BFC951 /* ImmediateSchedulerType.swift */, - F39428AAD1A8C28477229F95C566692C /* InfiniteSequence.swift */, - 7E09A0E2396C110A208EC13C7433F660 /* InvocableScheduledItem.swift */, - E352BDFF2115C51292AB8586490ED568 /* InvocableType.swift */, - 5C8DFF242FF6AD0B5D39025559BF1464 /* Just.swift */, - E49206FA7A03E65E86919B0D459CE145 /* Lock.swift */, - 2DFCDEDCDD5FC14895A9DD21AD8A2F2B /* LockOwnerType.swift */, - AEF73DB487C51BE3B8089E98680DEEE6 /* MainScheduler.swift */, - 7C190B94A6B2940D3FB8792AF205241E /* Map.swift */, - 02BD2CD95E38D6D07BFF1A50CEC190D6 /* Materialize.swift */, - B084E4A57E92EDDCD3161350DB5BE5AA /* Maybe.swift */, - 491B91C5AEEA5379C8161A8EF83C2201 /* Merge.swift */, - 3D09F935DC494553C710F412276A8499 /* Multicast.swift */, - 0F67A48D75B65978C9945E4A75695F2A /* Never.swift */, - 92E284F02D192F4D40930B6436D1FF91 /* NopDisposable.swift */, - BD80F9951E58EFC6FB6F971323560447 /* Observable.swift */, - CD61E97AA208CB51580A44C98AED1A57 /* ObservableConvertibleType.swift */, - 46DD6E7421FD83F1CBB2CE3D863ECDC6 /* ObservableType.swift */, - A5BF571F992C56D9D573ED8DC09C4C60 /* ObservableType+Extensions.swift */, - 5BDAE5B5F0CEA445E64668F0AE99F0A0 /* ObservableType+PrimitiveSequence.swift */, - FC49BC33E21E74FBF76137DA8666F343 /* ObserveOn.swift */, - 0EE5C65DE35ECFA7A169D5510D5465E3 /* ObserverBase.swift */, - 4523C7B556A036033B3A5F949125AFC7 /* ObserverType.swift */, - 12E97525EE22ADCF0B33275E0AD936D9 /* OperationQueueScheduler.swift */, - BBCBE12D3F58BBE9E47A986996E6BC27 /* Optional.swift */, - E2228729E07329BC7A9BAC6C2F232715 /* Platform.Darwin.swift */, - AE06908A1B2870327F0ADF60A1C33E5A /* Platform.Linux.swift */, - 5AB20C0696C90368521BC8C5D30941FF /* PrimitiveSequence.swift */, - 89F07902A639D9463D1E12EF99A9B561 /* PrimitiveSequence+Zip+arity.swift */, - 2AB367DA9D4CDE24360F2925BA4C2586 /* PriorityQueue.swift */, - 90E10AF3A7B96FE0920F8B8DE86C4219 /* Producer.swift */, - B376F5D8698FF8188D605CA8DE79020A /* PublishSubject.swift */, - BA4D142FFB629B426F6F7629322ED1F8 /* Queue.swift */, - DF2AB4533884DD0CDF831A515C462271 /* Range.swift */, - FE852069019561008E4F1D17B2D8A82C /* Reactive.swift */, - 32D297EFE0811B032CE8EA6F153CDF2E /* RecursiveLock.swift */, - 98EA88CC63643B3A84D3750A2A6E4BAD /* RecursiveScheduler.swift */, - 6649FD173A631AE0DF45F9BD4F0394AA /* Reduce.swift */, - C0E33457BFEC7056E08761A33142749B /* RefCountDisposable.swift */, - 3F2C7582BCAF3FDBE0408C5CE66746BE /* Repeat.swift */, - 247F0BADDB1F0001E7029E0B9B69BEEF /* ReplaySubject.swift */, - BD8044D97D4AC1C614E59023516FABA6 /* RetryWhen.swift */, - F8E687F68A8DB2E9F866809491177BF6 /* Rx.swift */, - B4EDD858C4EEB5E289F8FB564D33194C /* RxMutableBox.swift */, - 910E3E80559F53D4F796EE8F57AA99C8 /* Sample.swift */, - 1201972BFD824158C893EEEB86C162B4 /* Scan.swift */, - 970BA40FE81A997797A75CA0790B616A /* ScheduledDisposable.swift */, - 5798BC6E0D346B973EED8805BD8294C5 /* ScheduledItem.swift */, - 8F827C8190D1956882FEDB02BF7DA311 /* ScheduledItemType.swift */, - A2132119D8C2BB8C831F159760E17596 /* SchedulerServices+Emulation.swift */, - 29C241C94E36BC9D91A93A0A7A171DBD /* SchedulerType.swift */, - 035E0AE5379C0D0DF641A79DF7AFC5B5 /* Sequence.swift */, - C2CE2C996E16841660D5D11A174F1C0D /* SerialDispatchQueueScheduler.swift */, - 96F2CC4F3C17654C39122D70966D11A1 /* SerialDisposable.swift */, - 75CA936BEB05C9F8DDCA3F8C09F3FD0D /* ShareReplayScope.swift */, - A8AF8FDF5A19CA461972C062BFC6A2B4 /* Single.swift */, - 722CD18502E18B8FCB01DF7B127ECDBA /* SingleAssignmentDisposable.swift */, - 8562E45AECE2A39A478C87F465CA781E /* SingleAsync.swift */, - 51EE13A170006C38AA759AC268753B9A /* Sink.swift */, - 0672041CFD2E8E368862BC23B86B5FC6 /* Skip.swift */, - 17612A8C6862BA406B34D6804B974582 /* SkipUntil.swift */, - BF24B42CA8FF2095D4128F7C54728014 /* SkipWhile.swift */, - 8298B6CF3236C82E2CAD1913C751A27A /* StartWith.swift */, - 9EEB6ACC4990BC62F16F093FC4BC9F70 /* SubjectType.swift */, - 13A19DFD85A5A97950972F5201F6BEDC /* SubscribeOn.swift */, - 994EB2413C190238B4D314ECB0A2C6E4 /* SubscriptionDisposable.swift */, - B17B623FDAEFC8D30D3F4F29375FDAB5 /* SwiftSupport.swift */, - 0013B094868C3362596DB752534FA46D /* Switch.swift */, - 87A259B0B87DE94E12C68F977565F77E /* SwitchIfEmpty.swift */, - B32163A93EBC883865AD6CDA2D382ECD /* SynchronizedDisposeType.swift */, - D7D2B542D62F95B89FE0D38ED224B69E /* SynchronizedOnType.swift */, - 76EDB2CA5901A84A6295300BFF0991EB /* SynchronizedUnsubscribeType.swift */, - C3D61F86484FDA362AEE65D3A0E407BC /* TailRecursiveSink.swift */, - 734FC1CAA915693F4537D08A4A8D8268 /* Take.swift */, - BD66064D172EAC9E7AF1EEA0B9036F9B /* TakeLast.swift */, - 7468EC0CFAB9F0DAE3E4C9ABD87F9835 /* TakeUntil.swift */, - 3AFABBBFA80EA15962031B302097CA32 /* TakeWhile.swift */, - 0A7EABE903FA94A1A4C7BCE0C7FA3792 /* Throttle.swift */, - 7C64D7DFFFAF12902AD0718F6F2F6C6B /* Timeout.swift */, - 39C5C966A2E80796DAC4539D2C64490F /* Timer.swift */, - 724C773201D9539EF9D9CFF6D6513A87 /* ToArray.swift */, - 1F18C9B7B688EDE42CA6057820E17CF4 /* Using.swift */, - 429F241033F18A4B1C77E5B96EC83B8B /* VirtualTimeConverterType.swift */, - 7EEF27C2DCA3ADEB3B8D204BF95F3CEC /* VirtualTimeScheduler.swift */, - 04C814DE3552E1C0885EB29AE5F93775 /* Window.swift */, - D1FA7686F3834AC433C853E5F4A78990 /* WithLatestFrom.swift */, - 2F5BD2B31A5F1E29F8CDF82E49560F2C /* Zip.swift */, - 61F51B59B445C72F183D9CD178727B31 /* Zip+arity.swift */, - 95FBECA2920D68E70F2D918ED16EE65F /* Zip+Collection.swift */, - 8B58DEF2CABDE356FD011EEA8BBC35C5 /* Support Files */, + 9B754E74CA288E296A9522650713612D /* RxAlamofire.swift */, ); - name = RxSwift; - path = RxSwift; + name = Core; + sourceTree = ""; + }; + 14188A08879EE9FCA461843D2C310E1A /* Pods */ = { + isa = PBXGroup; + children = ( + B9FE6F570C2D19DBDEA55D2EC96B3CCD /* Alamofire */, + 6E17329D41C2C2C1E81B87A25B8C3DEF /* Realm */, + 2CD89A440317CD1369590A9759630338 /* RealmSwift */, + 909CC5A86D62DACC9154F00229146F13 /* RxAlamofire */, + D5A1A43FED298FBAA62B259669553394 /* RxCocoa */, + DDCF6E743B7BEC34751E3000CE5E93A0 /* RxRelay */, + CD204CF1317F8AEEFBC1DE4CB3599436 /* RxSwift */, + ); + name = Pods; + sourceTree = ""; + }; + 2CD89A440317CD1369590A9759630338 /* RealmSwift */ = { + isa = PBXGroup; + children = ( + F3DFF0752CD021478CF09DE2604A4F00 /* Aliases.swift */, + A6422EAD5E456128AF6EF8B6214E9EB6 /* App.swift */, + D6510CD41689DBE8602E63A8D32D93B2 /* BSON.swift */, + 38ACC5B4987910374BEBC50EBEC37F85 /* Combine.swift */, + 56071D6A7FAAD47EDEE69ABCC81232D0 /* Decimal128.swift */, + 2C227BE1AC1012FDEA2508280A710B85 /* EmbeddedObject.swift */, + E7C1743DFA2101E0EEF4044DFE0AF806 /* Error.swift */, + CDC4582D4D70B00FB4390B77B2D1AAF2 /* LinkingObjects.swift */, + 38BCA73981CA09129A31DC7B76307E1D /* List.swift */, + FE7B05FF864BAFF2C284FC3444530D77 /* Migration.swift */, + C04721533F2879C525420717BB0FEFAA /* MongoClient.swift */, + A73ACA6C4773FFAEE78D2D3064620C3C /* Object.swift */, + 392210D1A703D4FBF3F414E4EEA4B01C /* ObjectId.swift */, + 035A8B85F74A119913219BDD87EEBCFB /* ObjectiveCSupport.swift */, + 15B15F53FD84C0A717006B124E115B1C /* ObjectiveCSupport+BSON.swift */, + 9645FC628D296BC5A54B036A9DF35F9F /* ObjectiveCSupport+Sync.swift */, + 507E063CA30A2126D999BD8DD729A4FD /* ObjectSchema.swift */, + B7778D9E3B0FE3705C43E723A322774A /* Optional.swift */, + F6DA322294286F1B63182F5BBF223970 /* Property.swift */, + 01249979DC8733446D96910BD960244A /* Realm.swift */, + 1CD2BC359B1E50F0F0731770BCA42949 /* RealmCollection.swift */, + 7F68B8830F1AF80F4EA87E62B55CD11F /* RealmConfiguration.swift */, + 1968A5FAFECDCC7C761C774AF269DD2F /* Results.swift */, + 4D35DDC112BDC5FFC671470DD73ECC07 /* Schema.swift */, + D6B556D760F8D3AEE8A5F67DCDA5CEBF /* SortDescriptor.swift */, + B3EAA1E9622A8BD4F96A0A7C126C124E /* SwiftVersion.swift */, + 697BC47AE64E2A2BC38671AAD282C4A4 /* Sync.swift */, + 058AEEE4D4897A46CF0584F64E3439FF /* ThreadSafeReference.swift */, + EA7DFB8251965F74E154260AC1B1C118 /* Util.swift */, + 4533EAD4E5506F1D42D2D2DAECCAF6CC /* Support Files */, + ); + name = RealmSwift; + path = RealmSwift; sourceTree = ""; }; - 566B90552B785A871DC0FF7D5350D062 /* Products */ = { + 4533EAD4E5506F1D42D2D2DAECCAF6CC /* Support Files */ = { + isa = PBXGroup; + children = ( + 0BA872B8A6E73C01CAEEF644283CAADE /* RealmSwift.modulemap */, + 0EFA3387D6930CFB27424B1C2E421920 /* RealmSwift-dummy.m */, + 9321A74C66CB2C438FF080AD05E16A91 /* RealmSwift-Info.plist */, + D4DE8D9E1178FA21D2894BA5913D157A /* RealmSwift-prefix.pch */, + 0A69D6A299ACFC1ACBA8B6D05065F9B0 /* RealmSwift-umbrella.h */, + AC6A4C73F2B6D7B0FE5FC3A55E9945AF /* RealmSwift.debug.xcconfig */, + FA85CDF926CEB090AC0FA2E804C63579 /* RealmSwift.release.xcconfig */, + ); + name = "Support Files"; + path = "../Target Support Files/RealmSwift"; + sourceTree = ""; + }; + 46EAFDC299EEC61B6E0A1A974FE737B5 /* Support Files */ = { + isa = PBXGroup; + children = ( + 3D07F541D43757522E39C49E24343496 /* RxCocoa.modulemap */, + EB9D165744F522C3327959949201497A /* RxCocoa-dummy.m */, + 154052D7E94D80A2BCB9C64AAF2548E2 /* RxCocoa-Info.plist */, + 776C91B3873938A23ED3424F3518F119 /* RxCocoa-prefix.pch */, + 7B83B53F912C1DDF4F1CDD642DFB2F3D /* RxCocoa-umbrella.h */, + D256F37F99E6AAC79FEEE9508D19F476 /* RxCocoa.debug.xcconfig */, + DF1B0D9D0F144EA76A970202FBA81679 /* RxCocoa.release.xcconfig */, + ); + name = "Support Files"; + path = "../Target Support Files/RxCocoa"; + sourceTree = ""; + }; + 4BE88BEC1E83DCD0C869A3A57C48FC5A /* Products */ = { isa = PBXGroup; children = ( 5D797E9A5C5782CE845840781FA1CC81 /* Alamofire.framework */, 6AB5594F15BA137C18F182717955CB2E /* Pods_Darner_dan_uh.framework */, + 921BE4A82C4A7A5C72A0C6F8B8FEF200 /* Realm.framework */, + 437919EE08EC6BFCCBAC3BD346309742 /* RealmSwift.framework */, + 82F1475AA0F9C33F7EA4A1459305D2AB /* RxAlamofire.framework */, BC432FD48A5932251F1CAFBC4BF74894 /* RxCocoa.framework */, FF8B264DFE802855D5D67E7CDDABFC3C /* RxRelay.framework */, 809C5FAB588354C9BA37DC3EAB8CB45C /* RxSwift.framework */, @@ -1032,160 +1560,206 @@ name = Products; sourceTree = ""; }; - 71D0CA6CAAE622D50FFD3D3881DE33F8 /* RxCocoa */ = { + 597E94F72189AF013DDD9B1D2A55D016 /* Headers */ = { isa = PBXGroup; children = ( - 4433B551F7F37D4C8EF24EE7E6CEDFD7 /* _RX.h */, - F137248CF855D03E9C99C333CC2EC7C7 /* _RX.m */, - 35CD46DE65AF42A722F77B020C46D90C /* _RXDelegateProxy.h */, - E077EDF056ED4CC7D87B68F795366060 /* _RXDelegateProxy.m */, - B36F13BFA7EC28D766E2FA035715D267 /* _RXKVOObserver.h */, - C78763BE0913F286921ABF4148DBD215 /* _RXKVOObserver.m */, - FA22C9E930D6202E623EDBBF50205501 /* _RXObjCRuntime.h */, - 9B3A97CA5979AE7A4872B044A506709B /* _RXObjCRuntime.m */, - A317AB05AFFC477434FBA792F54107C3 /* Bag.swift */, - EFD86B77C2B2C4EB905B878E78BAEB49 /* BehaviorRelay+Driver.swift */, - F7C09FCBBBE54CC96607AD5FEA3E1BBE /* Binder.swift */, - 24C9AE967D758E6AB98C25E5D66EE0A2 /* ControlEvent.swift */, - 91F209C3C5BD5EA95444DC72928A82C5 /* ControlEvent+Driver.swift */, - 58E09376519428A591949F090A35B864 /* ControlEvent+Signal.swift */, - 225CD57AAC4DAEE8605668C406DE44C3 /* ControlProperty.swift */, - 4569C98C4590D9EC3361D848DCB582C8 /* ControlProperty+Driver.swift */, - B8F3C4D6343FB0C676E369EA9EC36663 /* ControlTarget.swift */, - D9B462D6F9C2C32D5DD9210644F9E967 /* DelegateProxy.swift */, - 48F9D5B73C10CD49B315100BEE5DA548 /* DelegateProxyType.swift */, - 8A2DBFDEF94D9662C5B07A332E73688E /* Deprecated.swift */, - 746ECD0F77098F9DA6B011D51999C74D /* DispatchQueue+Extensions.swift */, - 82222D308116F3DD1A7671C934667A99 /* Driver.swift */, - DDD62DE9F4F21A0A1D91A38E27DADD72 /* Driver+Subscription.swift */, - 2AE26FCFCEC8888CF9E2D904C2DEA925 /* InfiniteSequence.swift */, - 13DF7EFF2C06C91C70FBB6FDCE714A0A /* ItemEvents.swift */, - 78F0A6654B98B62DC64FA1664AD7FACF /* KeyPathBinder.swift */, - 0C4466009D7802687DC3BAB221CDD73F /* KVORepresentable.swift */, - 3BA20BD3717079A8B70018B2E2B847A4 /* KVORepresentable+CoreGraphics.swift */, - 4EDB5B83E7753170C64A678FD75B51C2 /* KVORepresentable+Swift.swift */, - BF14D9E05169A85F309D5DBE3E472064 /* Logging.swift */, - 5180C903E0EECAD555BDF74DDFE1EC53 /* NotificationCenter+Rx.swift */, - BABE3A3C32E1CB864B5DC70654B3671D /* NSButton+Rx.swift */, - 17C92B3843A03204045F53BC32AE8085 /* NSControl+Rx.swift */, - B6A92861B69C4DDFEE1EE0D9FAC74DC1 /* NSImageView+Rx.swift */, - 3596906DE866446245B777C72B463CA7 /* NSLayoutConstraint+Rx.swift */, - 9F1740E9CFCA048D3262400BFDF050F4 /* NSObject+Rx.swift */, - BBAF82A3A34CD99B5EDF793E626273EE /* NSObject+Rx+KVORepresentable.swift */, - 48F1B0D43C35A06740FE33CFC6A0F5D3 /* NSObject+Rx+RawRepresentable.swift */, - 22CF210C57601A6AE86C178E90663A6A /* NSSlider+Rx.swift */, - B1D59A00FC3C9EAA5DFF54F7800DF5A7 /* NSTextField+Rx.swift */, - 01D78531DC748E29CAE6A300625FE73A /* NSTextStorage+Rx.swift */, - B1A80F5DB2A0494A55847777AEE35124 /* NSTextView+Rx.swift */, - 9DA3AB3AE025125F455612E4434A6CBB /* NSView+Rx.swift */, - B63E4587F295EA0C56BFB2091E93A0E8 /* Observable+Bind.swift */, - 194A03463DA0EA64C8D837D89C6AE963 /* ObservableConvertibleType+Driver.swift */, - 7B24C8DC7CFE2282E35EB7B1BAFD5AD2 /* ObservableConvertibleType+SharedSequence.swift */, - 1591824CD4A57EFF831752B2B7707D77 /* ObservableConvertibleType+Signal.swift */, - AEB60E16D234FEBD84C815DB4B29B409 /* Platform.Darwin.swift */, - B917E5DBB06B2BDB021DDE3F5FA1C7E2 /* Platform.Linux.swift */, - C7A2D3F3FB22FE1D134D6E6DC6CF50CE /* PriorityQueue.swift */, - 3A4B1BFFB33A19ABE0476723FF458911 /* PublishRelay+Signal.swift */, - 9755430B399C67DC347AC34EB3CB5BB1 /* Queue.swift */, - 5BBBD32E7904C793C4B7CE8BBD493CF4 /* RecursiveLock.swift */, - F6A5D86D62C130F07B87521EC453E5AC /* RxCocoa.h */, - 5010F104E06C52D713C0FEA244872C4B /* RxCocoa.swift */, - 556A6CF39F72E28DD01FC3C31B0C116D /* RxCocoaObjCRuntimeError+Extensions.swift */, - E7AE4D23E0388E575CFC29BEE9137092 /* RxCocoaRuntime.h */, - 14F9E1DCBECDDD03F849344E1F7DEB4B /* RxCollectionViewDataSourcePrefetchingProxy.swift */, - 75CB38A7C83A94843D8DAF65E964D744 /* RxCollectionViewDataSourceProxy.swift */, - 79BE01F296E7734CBB0F06D590545AB6 /* RxCollectionViewDataSourceType.swift */, - 986E10F6FB6A0D91ACBD54436DEE367D /* RxCollectionViewDelegateProxy.swift */, - 8C9BCC3F17727084979A31BEF7947939 /* RxCollectionViewReactiveArrayDataSource.swift */, - C5F453AE3E9261B221BC01E1E7937973 /* RxNavigationControllerDelegateProxy.swift */, - 91EACAB565BF2BFEA11F77968AC8DE14 /* RxPickerViewAdapter.swift */, - 71338F1DF2F29A6EE619AF0A7C9C7311 /* RxPickerViewDataSourceProxy.swift */, - 4D1A4773C251551DBF3256469BDA716E /* RxPickerViewDataSourceType.swift */, - 35959D5AA25F9D8D128B66392E2910EC /* RxPickerViewDelegateProxy.swift */, - A58C9E012BFF1E7FF4FAF4572C0CA7CD /* RxScrollViewDelegateProxy.swift */, - 841FA2717197F3826D2C1BE1E8A19A1B /* RxSearchBarDelegateProxy.swift */, - 14B18705C3C90C8DA76954AF87DFEAFF /* RxSearchControllerDelegateProxy.swift */, - A48757BF4BCF0F643D13CB8D15325E28 /* RxTabBarControllerDelegateProxy.swift */, - 329C2C237E5807C5D2E690EF5670A8FD /* RxTabBarDelegateProxy.swift */, - C632BE09D9C554BF44A8323190FEC8C8 /* RxTableViewDataSourcePrefetchingProxy.swift */, - 0E85F83E3D8DC015C0BB6EE0E366E7F7 /* RxTableViewDataSourceProxy.swift */, - 248FFF5E776294F366C883410A62F0FC /* RxTableViewDataSourceType.swift */, - E4D8EC26F7663976A02C5C91105B1955 /* RxTableViewDelegateProxy.swift */, - 185C3CBCE6CB4F1F71D86AE370EA8EA2 /* RxTableViewReactiveArrayDataSource.swift */, - 12EC4A82840213156D80A772AC628749 /* RxTarget.swift */, - 0F93ED208D338D0391C8DAA1B16D9F1B /* RxTextStorageDelegateProxy.swift */, - AD6F8038569074A1C5850081F2BCC3C8 /* RxTextViewDelegateProxy.swift */, - 5144D49C296E97677FB28CA7B6A74D08 /* RxWKNavigationDelegateProxy.swift */, - 5D3B3309D720B6FF46FCAA66C89D18E8 /* SchedulerType+SharedSequence.swift */, - 825187DCC64EE46B0EFA0A41454B8172 /* SectionedViewDataSourceType.swift */, - 86C1631C4A90FA9150FA3655A6719B66 /* SharedSequence.swift */, - 5C6DD10F6A9C17A249C1E425DA10B8AF /* SharedSequence+Operators.swift */, - 1EEF839E1B9A94BD94894E8610B796B2 /* SharedSequence+Operators+arity.swift */, - 9C6594A8E2D7855C99BD23EBC9EFE4F5 /* Signal.swift */, - FBB241B5200E6C6633679983A73E86A8 /* Signal+Subscription.swift */, - 68D3944E9EFF58CCE1B9DCAB666EDD71 /* TextInput.swift */, - A6B8C420AAA1BE4BC3151D7D96707BF0 /* UIActivityIndicatorView+Rx.swift */, - 84BF31B4F35220C06C94D6486C204AE2 /* UIAlertAction+Rx.swift */, - 4FE45E4A160BBBF16808F12971CC5A89 /* UIApplication+Rx.swift */, - A5440CF35EA37D0984E060E233A0AA89 /* UIBarButtonItem+Rx.swift */, - 29A777BD3705A34957AB2A6F52F7C8B9 /* UIButton+Rx.swift */, - 8C025AFFED9E62D011484129DF62E696 /* UICollectionView+Rx.swift */, - 695B8FEB2CE2E58AC36323480D088515 /* UIControl+Rx.swift */, - 83CCEE94FAB38943A2870279FA91DFE3 /* UIDatePicker+Rx.swift */, - 72FB3EEC19F1F948F81C181D6FBFC668 /* UIGestureRecognizer+Rx.swift */, - 1512A6A21B4C585CBD85B24F18ECAAB5 /* UIImageView+Rx.swift */, - A58CA2588C08F08FF6CAC6A6FBFB2699 /* UILabel+Rx.swift */, - 59F13789F4CF993E4174281BADA9FE5C /* UINavigationController+Rx.swift */, - 2159023945A21C8A29D239741B1B810E /* UINavigationItem+Rx.swift */, - 390ADDE880682922C795B8C9F7EF4C6B /* UIPageControl+Rx.swift */, - 1111B7A662732DE1675B573658011958 /* UIPickerView+Rx.swift */, - 3731D6B5F5645F219064F326F5DBBC0D /* UIProgressView+Rx.swift */, - 3316846B050A463A0CBDF297D8B28ED3 /* UIRefreshControl+Rx.swift */, - 7A11A7403C8F81B77F8C11652F2506DE /* UIScrollView+Rx.swift */, - EAF04A13053CD1DF27E37D06B154FA99 /* UISearchBar+Rx.swift */, - 91584B212EE8EEDC31D307A6B76CFEF5 /* UISearchController+Rx.swift */, - 1946A1418516CE741E8B311BC7C2E91A /* UISegmentedControl+Rx.swift */, - C48DD79407F9BCFED2215FF574C4480E /* UISlider+Rx.swift */, - 48C8732A69884F45E5C836FB0D58C7A1 /* UIStepper+Rx.swift */, - 00BFA1AFA8DBDD22DDA9DD08DF848644 /* UISwitch+Rx.swift */, - F2A94F072357E44438225A4EDB084B20 /* UITabBar+Rx.swift */, - 63BB583E7867A580C3470AC51FF64304 /* UITabBarController+Rx.swift */, - 671EDE771550EBC0A957B46405BEA906 /* UITabBarItem+Rx.swift */, - 87A84A65C3F2568A97179656B9AF632F /* UITableView+Rx.swift */, - CDCD59A387DF8B278151EF546C7219A6 /* UITextField+Rx.swift */, - 8C5C5E1306EC265A2A7887CE3A3F9671 /* UITextView+Rx.swift */, - 9FE9880124CA212A9F3C74349C1DE066 /* UIView+Rx.swift */, - F3B5DC9315EC4C7837FEE02A29842F21 /* UIViewController+Rx.swift */, - FBECBCED3E2BF4E98A2BF45ADA22CE63 /* URLSession+Rx.swift */, - B683310889B53BE8E6A34F95BA755E46 /* WKWebView+Rx.swift */, - CD252DE2549242FBC918AF9937F9A0F9 /* Support Files */, + EE3FF4B388652B33DDD06D2496327330 /* NSError+RLMSync.h */, + 8D5D2EE19CA67D347686A2E578910C66 /* Realm.h */, + 02AC92A155B36A82731B0043B39919A6 /* RLMAPIKeyAuth.h */, + DA3598979CE772D50E44DD120ED96A26 /* RLMApp.h */, + 2792D1140DA9A6D5A0AE6C7D26CE34DE /* RLMArray.h */, + 0AD4B936BBEA39E12AF6795CED6E9EBA /* RLMBSON.h */, + 339215A49D0EE00F18DAD73C85C8CB04 /* RLMCollection.h */, + BA487887F86C2E5E0C2C260131CD673E /* RLMConstants.h */, + 6652A6E7278B0F41CBFCE6520A354FC7 /* RLMCredentials.h */, + 597BC46EC61C37E53FF2B9A3DFDD76CC /* RLMDecimal128.h */, + 64C4A169FCD8C606185D6CB50AE9ADF6 /* RLMEmailPasswordAuth.h */, + 21154A52CE37F60FB2E8149FB1B840DF /* RLMEmbeddedObject.h */, + C0233CB52B3C3FD4DF91769E2264AF71 /* RLMFindOneAndModifyOptions.h */, + 45B647ABF0A00004F68914CBADFB5B27 /* RLMFindOptions.h */, + 1C16195CFF5969D14EC6DEA689F73205 /* RLMMigration.h */, + A59FC8CE00F882551C57698AA53BD31E /* RLMMongoClient.h */, + 747A3C76800A1F6EC0D6086DFC8CB10E /* RLMMongoCollection.h */, + F0AB722C3C0CD69B263401F5156BCE96 /* RLMMongoDatabase.h */, + 888D23E446A07C3A3365606FF924FBDA /* RLMNetworkTransport.h */, + 1353548A4397B700D6C86BF0E496F8C3 /* RLMObject.h */, + 6924294AB88A4FA6537B15BA0B6F297D /* RLMObjectBase.h */, + 66EDB9DF199CC9BF81C564719B0E75AC /* RLMObjectBase_Dynamic.h */, + 48E379072BB61DABCB5FDA0E8A8E8EB9 /* RLMObjectId.h */, + AA0E41562C17ECFEDF9457B13567040C /* RLMObjectSchema.h */, + F8216BA641FC62DCBDFC9C0268B56873 /* RLMPlatform.h */, + 2AE4ED8FA170DF993930A077F70FA6E7 /* RLMProperty.h */, + 9412756A303D90418C6D9386101C3738 /* RLMProviderClient.h */, + 72842ABA9A87A415D9DA5339DCC9B4BD /* RLMPushClient.h */, + 59497FB083F1C96E811BF0ADD11511B9 /* RLMRealm.h */, + 84E405EFB78E63F9D2F57CA86CA6BC4D /* RLMRealm+Sync.h */, + 474B55CB2CC0E9BAE21E4A0D1DD8D50A /* RLMRealm_Dynamic.h */, + 30B878398E136A1052ECEC59EB9A252D /* RLMRealmConfiguration.h */, + 24BE49CFC9CEDC6E3FB1D1D9519FFB6D /* RLMRealmConfiguration+Sync.h */, + BE07BE828DE8E46170E7B5BA08E44997 /* RLMResults.h */, + D1E961D09AA076899B1338AB10A23759 /* RLMSchema.h */, + 6B7A5B0F7FA13D2ED0C0C194C5E8EECB /* RLMSyncConfiguration.h */, + 2A659C5B4905F50CF069CBEC4BA23D5A /* RLMSyncManager.h */, + 99D287487AD77AFB75AE28B736B355DE /* RLMSyncSession.h */, + C3B988408D8F0CA517A4AEEF864A7269 /* RLMSyncUtil.h */, + 01E829750D016D1BB8739C7D6C8B7E1C /* RLMThreadSafeReference.h */, + FEF1973B4E9C40CAAAB341CD3C57C779 /* RLMUpdateResult.h */, + A653A9A03EC868233496EB1538F067D2 /* RLMUser.h */, + E8C296B43EC37369C8F90E4070E1A3AC /* RLMUserAPIKey.h */, ); - name = RxCocoa; - path = RxCocoa; + name = Headers; sourceTree = ""; }; - 7FEDF627E50C1BA14950EEAEB5E835E3 /* iOS */ = { + 5DE597AD3436977FDDB23A3824958CBB /* Frameworks */ = { isa = PBXGroup; children = ( - 0555E02157B458CA4C5B3AE6D65FCD3F /* CFNetwork.framework */, - 169AAA422E46B126BBAD577E53742277 /* Foundation.framework */, + 768B96ADE27F4305ED123B2603C54787 /* Alamofire.framework */, + E7FD872F1EDC128CFFAD6F841A90F6AF /* Realm.framework */, + 2678655DA16D1C91C49D41DFDA5870FA /* RxRelay.framework */, + 4524CEDB98A45F635C925EEFC4AC4D3A /* RxSwift.framework */, + BDF3E04E13205B645AFD9B48C3CFDB0B /* iOS */, ); - name = iOS; + name = Frameworks; sourceTree = ""; }; - 8B58DEF2CABDE356FD011EEA8BBC35C5 /* Support Files */ = { + 6E17329D41C2C2C1E81B87A25B8C3DEF /* Realm */ = { isa = PBXGroup; children = ( - 1A95BD137A895FECF14F78F441F63293 /* RxSwift.modulemap */, - AB4EF579F5A621FEEEB03F3B4B7DDB7B /* RxSwift-dummy.m */, - 1DBBEBCD60ACE2D70FF6C9BCDA9AE8D3 /* RxSwift-Info.plist */, - B6E997AD6AFEFECCF482609975D11D56 /* RxSwift-prefix.pch */, - C8CBD89F412EBC0575A328F5B8A71350 /* RxSwift-umbrella.h */, - 1DC46D98E3D4A6854B4D3ACD807CDFE2 /* RxSwift.debug.xcconfig */, - 82CF61945D38FCF90C8205EF6C6049E6 /* RxSwift.release.xcconfig */, + 7FF061165F98F4381C924039DC3469FB /* app.cpp */, + A43E908FDEB66EAF5CDC0C08CA8F2E9D /* app_credentials.cpp */, + F6EC00D8A01B8A46996F24C44D7E9AEB /* app_utils.cpp */, + E396837EA8B140BEE2C9712CA5D7C855 /* async_open_task.cpp */, + FC0213C64A67607536CA92B3B9EDC152 /* binding_callback_thread_observer.cpp */, + D336EE10741FE93C320CD500327840F5 /* bson.cpp */, + 42C7AFF87F4881919AEDE31682621C65 /* collection_change_builder.cpp */, + B443A7D6ADC2F4D60D93FC877D5DBE0A /* collection_notifications.cpp */, + 1F013734C88EBE1D69DEAD484ECADACE /* collection_notifier.cpp */, + 0A113A1381D58B977ABC03AF0C169267 /* external_commit_helper.cpp */, + 72A2153FA40633D4FF37728672DFCC9C /* generic_network_transport.cpp */, + 8A193A9805AD36F6923C1094E275C8F3 /* index_set.cpp */, + 1AC464F34523709BD1E60BA27CDE8842 /* keychain_helper.cpp */, + 6781794A3C328F78F4B8FD5954B94C05 /* list.cpp */, + 0D8B391ECFBBB1D945E878B3A2DB5B1C /* list_notifier.cpp */, + 9C10C065206C7FD92976DAF5D1A6E328 /* network_reachability_observer.cpp */, + 7EFE079604B17211ADC0DBD90895F0F7 /* NSError+RLMSync.m */, + 357BCD5C989B4B1386A6534171E16B6B /* object.cpp */, + E6B16B29794E989049ED056119609AD2 /* object_changeset.cpp */, + DFD3A4F8CD51D3B9F9B303137A7D436D /* object_notifier.cpp */, + 97E523BCD01E85E993214379AEB68DE6 /* object_schema.cpp */, + 123A19C0627E923D071BEE6553C1E5FA /* object_store.cpp */, + 3F3E96D01CCFEFD7A748E4B5C5D839D8 /* placeholder.cpp */, + 685C0AD8CD4FEC498B803EBEAB9D460C /* push_client.cpp */, + 2E3BFA2B1FE0ED598F6CD11830FCC6EA /* realm_coordinator.cpp */, + 651FA28CF0389AA0022093E86CDC588E /* regular_expression.cpp */, + 79CA8D74CEF50C0C13559089D0DEA8A3 /* remote_mongo_client.cpp */, + BDCACDC74AD6B5FDD41F5741D751047B /* remote_mongo_collection.cpp */, + CD78931CCDDC97455EC35D57F5094C62 /* remote_mongo_database.cpp */, + 712C52F8298ACFE9974537269740BA0D /* results.cpp */, + 4ADCB6FD187409DE26C251F11D5BB1BC /* results_notifier.cpp */, + CDEFA4D6E74CA20A41AD1D24A53B544D /* RLMAccessor.h */, + D03BC09ABD830E4801045FC998EF817E /* RLMAccessor.mm */, + F0506E6B74E3BA42E9372DEE4243E6E5 /* RLMAnalytics.mm */, + C9F7414E32FE518A8A46C0FEA75BF241 /* RLMAPIKeyAuth.mm */, + AA3127E6EA50E54BE683A4640BA3B1B5 /* RLMApp.mm */, + 35B19D09D0DB2E94A7249C68294BD24E /* RLMArray.mm */, + 6008D806F7FE06FEE6315C1A586CBE38 /* RLMArray_Private.h */, + 2EC0428FE529F2A45EE29C2AAD2A467C /* RLMBSON.mm */, + 97114D5DB038834C71DF6D35894881E3 /* RLMClassInfo.mm */, + 0E90F43735FD12DCC9A88FD5186FF829 /* RLMCollection.mm */, + 880083C6631CCDD9FCFB3D3742A37D59 /* RLMCollection_Private.h */, + FB9B48285BCCDF74DAAC90326D85758F /* RLMConstants.m */, + 73C10FBD152E2E4CC495ABBFFDA46BF0 /* RLMCredentials.mm */, + CF42A2B7D6A7DE5BFD6EF860E0F25DAC /* RLMDecimal128.mm */, + C25F0805D73DBCBD7D42D8A9FA10F93A /* RLMEmailPasswordAuth.mm */, + 71A6EDA338F7DA1AA89C3FAF02FBB03B /* RLMEmbeddedObject.mm */, + 00A74A3256B9E1379A4DD01AD0BC8511 /* RLMFindOneAndModifyOptions.mm */, + 29622D1F2C8710735FC606C6C7AB068C /* RLMFindOptions.mm */, + 1C8B3A7FA064FA49FA28D62F6971AD96 /* RLMListBase.h */, + E9FE377B8B9D00BE6088A6D9BBE2CD67 /* RLMListBase.mm */, + BBFE582250E3905047D7584AABB79C71 /* RLMManagedArray.mm */, + 07156FB16C3FAFFC2E1D0A15BDC44256 /* RLMMigration.mm */, + 36A621775AD2772E5FEEDCE7B4C00609 /* RLMMongoClient.mm */, + 5B667C049F3C637F0B9FBA40721F2DCA /* RLMMongoCollection.mm */, + EB4E75C2A8E07889C7E2FF8D4BF35FD9 /* RLMNetworkTransport.mm */, + A72D1251AA1B04F052725F5E84FA7BF6 /* RLMObject.mm */, + 57D26DE88762BD941DD60CB00B72DA3D /* RLMObject_Private.h */, + 27B99BE284348A1148EC9971A44FE17A /* RLMObjectBase.mm */, + 37D024D0F04AAD55C5660DD29517DE6C /* RLMObjectBase_Private.h */, + 44D3FFDDA0AB5DE8F05DECEEBDEB12AF /* RLMObjectId.mm */, + BE62C08E4BA287B456905415665C63B3 /* RLMObjectSchema.mm */, + D53FF47C70573D21E73A4729008A809E /* RLMObjectSchema_Private.h */, + ACD3F71760CCCD9557A8FF00B70177A6 /* RLMObjectStore.h */, + A21415F38D7146BDCAFA9B3D201988C6 /* RLMObjectStore.mm */, + B28FC641132526433C317123A996D97C /* RLMObservation.mm */, + ACC8191ACD24F00F9C2FE8AFEBFFE08B /* RLMOptionalBase.h */, + EECDA48CF4FF1C4C110AF794275ED748 /* RLMOptionalBase.mm */, + FBAEE5BB4EA38C59A455590BED8D03F0 /* RLMPredicateUtil.mm */, + 5E4DC26BFD994975A4452321FEE2E86D /* RLMProperty.mm */, + E1B03021B1EFA35F821B99376BEAB3E5 /* RLMProperty_Private.h */, + 2EFFF14B7584C9C947179DA2BC659A44 /* RLMProviderClient.mm */, + E6BDE8A8A7F672F687F13615707178F2 /* RLMPushClient.mm */, + 444FCF6395FE1FD628DE5A8E7D80B3E5 /* RLMQueryUtil.mm */, + 8E98590E803C6C2C41CAE017D38F9FFE /* RLMRealm.mm */, + A5FF27F873A36ADC87621F49D7A03109 /* RLMRealm+Sync.mm */, + A54DEEC664B55294338630DE37A09A15 /* RLMRealm_Private.h */, + B3ECE590EC23040201BA4796C26E4E8F /* RLMRealmConfiguration.mm */, + 869B025D18E382BEA868469B62E768EF /* RLMRealmConfiguration+Sync.mm */, + 78BD15A38C1C2292CA446D8971F118FE /* RLMRealmConfiguration_Private.h */, + 73459032C7AED3F87C065F092BFDC3ED /* RLMRealmUtil.mm */, + 23B95E3E4BB5C2C0F727D6DCAA4EFD16 /* RLMResults.mm */, + A53B942D095FBCA857D477D52867F35B /* RLMResults_Private.h */, + BA44B6692F790A5D43E3F201979ED665 /* RLMSchema.mm */, + 7FEB4D9BA45A0D280A2E12721EDDE69A /* RLMSchema_Private.h */, + E8A86E54BF1F17E2E4F94C724E812FF5 /* RLMSwiftSupport.m */, + 0E96D5A2409E16D07F6C178C89CA716A /* RLMSyncConfiguration.mm */, + E5A7027385985B7AE9F3DCD243487913 /* RLMSyncConfiguration_Private.h */, + 9131396FAB541FDAB151AB74DBB27C00 /* RLMSyncManager.mm */, + A5BC3FDB21CAE5641FA35481DB4757A8 /* RLMSyncSession.mm */, + 6A6C8E21EBFBFFCDA1933049C170A78C /* RLMSyncUtil.mm */, + C3B7CA57C3CC37B2B5613266C1C279A1 /* RLMSyncUtil_Private.h */, + B1DC237BF5D2B86D015539248B204916 /* RLMThreadSafeReference.mm */, + 3489ECAB322E95680C288808406928E2 /* RLMUpdateChecker.mm */, + B02FFA9C7277B2B22A3A03CCE21A1F17 /* RLMUpdateResult.mm */, + CB6BD43736BD0C82C82EF813563DF749 /* RLMUser.mm */, + 1B0DAB86A5C35706335569585D6C0D74 /* RLMUserAPIKey.mm */, + 514EDB50B37C0BA31EE0FF3E4DB2C0FC /* RLMUtil.mm */, + 2BD4FCE00CFCBE8E98C06E5C3A0495E7 /* scheduler.cpp */, + B0076057252637CB1FC2A28D7CE35B90 /* schema.cpp */, + 4FA07826EC4D168DA6EC97F9164EA43F /* shared_realm.cpp */, + E3845E9FA4FDBDCE093112D811EA05B6 /* sync_file.cpp */, + 1942CCAEE67C1D9C588B1197A0D9C2C8 /* sync_manager.cpp */, + 6A6DFD2E3086F70BABF4D552F3F82567 /* sync_metadata.cpp */, + F6D933CEA78AFF25F8238B2086E0141E /* sync_session.cpp */, + 83D5D07DBB1E6BEFC0FA713727BD7111 /* sync_user.cpp */, + 620007ED9E8C608CA8206880D8995253 /* system_configuration.cpp */, + C286E268C8D65C8396BF5333623B2BD8 /* thread_safe_reference.cpp */, + 6DBD72C6356BDA4CBF5FFA393F9D6B9E /* transact_log_handler.cpp */, + 8D9F194E31435BDE8CF3925BAFF22F43 /* uuid.cpp */, + 90520370565051AB89C191544C3D53CE /* weak_realm_notifier.cpp */, + 79B7F3BC3293CE8CB52D98F10CDD7807 /* Frameworks */, + 597E94F72189AF013DDD9B1D2A55D016 /* Headers */, + E721FF0E7B773D9A6D14DF0159C6B7F4 /* Support Files */, ); - name = "Support Files"; - path = "../Target Support Files/RxSwift"; + name = Realm; + path = Realm; + sourceTree = ""; + }; + 79B7F3BC3293CE8CB52D98F10CDD7807 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 65553F09D06098FE8A398224ED2104A4 /* realm-sync.xcframework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 909CC5A86D62DACC9154F00229146F13 /* RxAlamofire */ = { + isa = PBXGroup; + children = ( + 1093C52C2C9A4662BB939F211CCCA46F /* Core */, + FB4DEA7BA784B3F5788979CAE8979264 /* Support Files */, + ); + name = RxAlamofire; + path = RxAlamofire; sourceTree = ""; }; 96BC156766F71A682F6BFAF6B9E5B4C8 /* Pods-Darner-dan-uh */ = { @@ -1205,160 +1779,641 @@ path = "Target Support Files/Pods-Darner-dan-uh"; sourceTree = ""; }; - A6EEDDCEDADF3C175A8BCD2F569758F4 /* Frameworks */ = { + AEFC2A38B89EC70AE260239DCE6FD4FF /* Targets Support Files */ = { isa = PBXGroup; children = ( - 83D73284DCEE4FE8C76234DE2ACCD393 /* RxRelay.framework */, - D4F5CAC3DFDC297B2C56D647BF7C7813 /* RxSwift.framework */, - 7FEDF627E50C1BA14950EEAEB5E835E3 /* iOS */, + 96BC156766F71A682F6BFAF6B9E5B4C8 /* Pods-Darner-dan-uh */, ); - name = Frameworks; + name = "Targets Support Files"; sourceTree = ""; }; - AEFC2A38B89EC70AE260239DCE6FD4FF /* Targets Support Files */ = { + B9FE6F570C2D19DBDEA55D2EC96B3CCD /* Alamofire */ = { isa = PBXGroup; children = ( - 96BC156766F71A682F6BFAF6B9E5B4C8 /* Pods-Darner-dan-uh */, + F5D1E68D8A1529F9E5FE1179FF21A6A8 /* AFError.swift */, + E08C704F7CD7533F4E2B2A0B74F8A786 /* Alamofire.swift */, + 9DAA9230E36A2125FEA32C5242589513 /* AlamofireExtended.swift */, + C7488D788771D2CF319A3829C4B15900 /* AuthenticationInterceptor.swift */, + 9DF5D58B19C6C63A65143A3E6532029F /* CachedResponseHandler.swift */, + CC3611FA4C931ADB12C3874BD2CF9CA1 /* Combine.swift */, + AA9C81E6BB6A6F3847C6095D3138A200 /* DispatchQueue+Alamofire.swift */, + FC46534386377743676587034A95CBB9 /* EventMonitor.swift */, + 395BA47D1C6A5F1B244D5486B0BE5279 /* HTTPHeaders.swift */, + DCAB5D7A477412E48B74F60F519DC73F /* HTTPMethod.swift */, + 24A78EE46C9AB6747F7EAE6E3FDA5DD3 /* MultipartFormData.swift */, + 528B9C2D3C3B86EDE0CF0FCD180ADD76 /* MultipartUpload.swift */, + C21D1AD327A53F52AF328CF9FE041331 /* NetworkReachabilityManager.swift */, + E7C3A5B6C8097F3302E2D59329A8090B /* Notifications.swift */, + 5B2E877567298339EF627B1FF714AE0C /* OperationQueue+Alamofire.swift */, + 5DC72A276813FE5860E1E696B9AB591D /* ParameterEncoder.swift */, + 10B64935EC02FE6B379CB2F93E79814A /* ParameterEncoding.swift */, + 45A889D4629D068E1484C1D3DF16D952 /* Protected.swift */, + 672BD61565B17E3649CB5C53F72C117C /* RedirectHandler.swift */, + 5EF5469A5815CD32CD6EDDCE7D18638E /* Request.swift */, + 0D6E0185990293F9B45806EBD2A593FF /* RequestInterceptor.swift */, + 2EA417896E98F2FA28958FEFBBFAC5B2 /* RequestTaskMap.swift */, + D7BDFC60B45FCC326C52B21834773793 /* Response.swift */, + 089F8F00402B7AD96A67301E78DE0707 /* ResponseSerialization.swift */, + 2034C81E59E1F1EF6E36D917E0936861 /* Result+Alamofire.swift */, + DDFE63997FF8C1AE2617A1BC92C4E1BE /* RetryPolicy.swift */, + F9CCD49060C94F7804A9AC7735C7092F /* ServerTrustEvaluation.swift */, + EF1E92FCED708D7E4565A3867B965CEA /* Session.swift */, + FAE53A746F752DD65ED349FBDF528401 /* SessionDelegate.swift */, + 4DB882D96AE746E55CFCDEEA459DA375 /* StringEncoding+Alamofire.swift */, + A65BD2C9DED18F75BF3E55EDDE4E56DE /* URLConvertible+URLRequestConvertible.swift */, + 1A8BDABAB4E71F301AF4556EADC00F11 /* URLEncodedFormEncoder.swift */, + D5BB9F8C6B4BDAC5D8317DFF3602B0F7 /* URLRequest+Alamofire.swift */, + FEE52232218966D95056A2B60A630CB3 /* URLSessionConfiguration+Alamofire.swift */, + 0FFAF63ACD970F79684D7C896D99C860 /* Validation.swift */, + 0E9CD0ACB2EF441FE7BD12C20133DD57 /* Support Files */, ); - name = "Targets Support Files"; + name = Alamofire; + path = Alamofire; sourceTree = ""; }; - C8245AA98277AE6F5D82C8A1CD8C5DF9 /* Support Files */ = { + BDF3E04E13205B645AFD9B48C3CFDB0B /* iOS */ = { isa = PBXGroup; children = ( - E64B5D5BECB58F8396FB393EA62C09B6 /* RxRelay.modulemap */, - F781B391DCFF6B77F0E2AF4C6837C1FD /* RxRelay-dummy.m */, - 3D10EA8BD2DCC28FFB44502861805167 /* RxRelay-Info.plist */, - 1918212E050BE431A6831619552F853A /* RxRelay-prefix.pch */, - EFE1CB5CD9AB2B1456DF66F04802FB88 /* RxRelay-umbrella.h */, - E1757F396E51EFEFA58511C903B926C7 /* RxRelay.debug.xcconfig */, - ADB12FD54E0F26373ED16E17F0940E6A /* RxRelay.release.xcconfig */, + 5BA07F30960653B557BD112DFE0FA2FD /* CFNetwork.framework */, + 3C3AF2E791EE67E3DF385C1781D769A1 /* Foundation.framework */, + 42A4B9682D6833BEBF451FE680D4EAF3 /* Security.framework */, ); - name = "Support Files"; - path = "../Target Support Files/RxRelay"; + name = iOS; sourceTree = ""; }; - CD252DE2549242FBC918AF9937F9A0F9 /* Support Files */ = { + CD204CF1317F8AEEFBC1DE4CB3599436 /* RxSwift */ = { isa = PBXGroup; children = ( - DDC8939562013BBA0ACEB61DEC872127 /* RxCocoa.modulemap */, - D7B70AB67697E4837993DBE6B65020DB /* RxCocoa-dummy.m */, - 5A59821B4014E4768C966D6250EC7415 /* RxCocoa-Info.plist */, - E1DA49D0D0E1848191BFBDFF1115D0FD /* RxCocoa-prefix.pch */, - E146C0BF7BD9F63449F05D956A7582FE /* RxCocoa-umbrella.h */, - B50080BBC3721DEBF83123B05531A6FE /* RxCocoa.debug.xcconfig */, - D2DBFDFBE48A0BFE84CDF28D07A087E4 /* RxCocoa.release.xcconfig */, + 8A99B37E50B6E39B7CD160179B1048DF /* AddRef.swift */, + 21346E0C05D36D3AD36B91ACB9011DD0 /* Amb.swift */, + AD289ADC86E68CB5843E0F3E137F584F /* AnonymousDisposable.swift */, + 43628ED44C9AA3D3503458B602E82696 /* AnonymousObserver.swift */, + E40B4BC9B3ADB2F167F2CD1BADA00C3B /* AnyObserver.swift */, + 49F9716687BE37F18CD9BFE6A52FD2DA /* AsMaybe.swift */, + E83B6C534733423F02985C506A911F49 /* AsSingle.swift */, + BC071B2000C8A95778E4A22701CB8FEC /* AsyncLock.swift */, + D1697E1FF125ED99D1216B93E66EAF5B /* AsyncSubject.swift */, + B67CCC5A38EEFC7FF284A0D814489035 /* AtomicInt.swift */, + A7520BC1DB4FCDDDD0D2A161F23A099E /* Bag.swift */, + A3D619D046F8DE72E051111E696902B4 /* Bag+Rx.swift */, + 07EDFC981426B815ACDAA00D3F9F3621 /* BehaviorSubject.swift */, + 7365074ECE61B11E251379CA978A43A5 /* BinaryDisposable.swift */, + B5025DCDB5381F0BAF26FFB5E92DAB4E /* BooleanDisposable.swift */, + 9A40596A661F48EEFADF158E97613659 /* Buffer.swift */, + 8A83EEE7FF87AE4434072CD2E879BAB8 /* Cancelable.swift */, + 27B03A18EA69A32F4FCD8E7A5D342674 /* Catch.swift */, + 5EA93CB577014200856DD7108C1B0220 /* CombineLatest.swift */, + 663782B983674097667AA655877DE251 /* CombineLatest+arity.swift */, + 434FC690A867299DE9E7360140680714 /* CombineLatest+Collection.swift */, + 31099800731F7C7C9E93FCD519007B12 /* CompactMap.swift */, + 1427066B3F5B6E4ED399EB45CD534C6A /* Completable.swift */, + 7D8A38AE011A373694F41430F9242A03 /* Completable+AndThen.swift */, + D09D63DDBDEBE7C181B504886AC7819C /* CompositeDisposable.swift */, + 3E2548ECC06C74EA7204E04959046038 /* Concat.swift */, + 6155D234BBD32E52148B0991435CB0E5 /* ConcurrentDispatchQueueScheduler.swift */, + F32BA08422C23AB8697543BF4EE4A6EF /* ConcurrentMainScheduler.swift */, + FFCE456C658E2F0004F7194F0677A751 /* ConnectableObservableType.swift */, + 8BEF15345C60B26DE20F2B3F14A965C5 /* Create.swift */, + AE0507016D5F581EF3C0C205AAD4AAE3 /* CurrentThreadScheduler.swift */, + E4BA811ABA1EEBC0D4084E3469D31939 /* Date+Dispatch.swift */, + 13116BBDD71E1181921DE495E7CDA6BC /* Debounce.swift */, + 75901C59B7444C2042CFE3AE5FD1990D /* Debug.swift */, + 8FBE3C34D8D3B16941AB50B4CC5848B1 /* DefaultIfEmpty.swift */, + 74979024C8AA2EBCEA8080A78F40EEBF /* Deferred.swift */, + A7B4151FE9541C0467D4D77981FA35F1 /* Delay.swift */, + 006BF5370268B8E8C77AC37824764B9A /* DelaySubscription.swift */, + 462749C51F01BD979C5B7601F7EDCB60 /* Dematerialize.swift */, + 1E9AA4AE06C1A4752179DC22A2DA027C /* Deprecated.swift */, + 99D459801D0303FB7E4BE5D22AD2AB46 /* DispatchQueue+Extensions.swift */, + 5346001597BAFBB0875B82142214C534 /* DispatchQueueConfiguration.swift */, + A5E3D87CB1399F7F29B712144448C62F /* Disposable.swift */, + 273D1C710EAED20857E1D3D9F2D58709 /* Disposables.swift */, + 2550C023355B7965233A026416E78B0E /* DisposeBag.swift */, + 35E1C5A9B4B09EE53C0486B10DCAB3D9 /* DisposeBase.swift */, + 3A3C70D050B1B4B178ADA00B9AA4F6AA /* DistinctUntilChanged.swift */, + 7018E4C3E8A75A113B688D25BC4EAE63 /* Do.swift */, + 9A3A47252A95931ECB57904A7424A230 /* ElementAt.swift */, + FCB6E9B1FB99D7F09E19DB476EDAE289 /* Empty.swift */, + B15981EDF03C1DC3630AEB39AB9743D4 /* Enumerated.swift */, + D76B0D404FF9222A46B821BC2AEC07E3 /* Error.swift */, + 9C11273D45259641CB6C9E72C2CF25B0 /* Errors.swift */, + AF497AEA1642B013BDE723091AD4EDB7 /* Event.swift */, + AAB5C19EDDB71F30C96CF216AEB6881D /* Filter.swift */, + C98B5E2E7BE8BD9F769092DB3824B607 /* First.swift */, + 98FB87ECA069BA6F525BE852477801F8 /* Generate.swift */, + 2A784BB19543BE7255AA56FA7E88E1E0 /* GroupBy.swift */, + C8D3CD52C0F4520B98B15311A415FF67 /* GroupedObservable.swift */, + 1C976161CEA8E0CD52FB77B418D4EDA1 /* HistoricalScheduler.swift */, + 93E8A674D112A59F350E4FA5585AB904 /* HistoricalSchedulerTimeConverter.swift */, + 5F1A25FE11E235D26A2DF9E9B0C5F486 /* ImmediateSchedulerType.swift */, + D1809FC8B4516DAD5F0624F299B5D42D /* InfiniteSequence.swift */, + 4425212D91422CC722267318D089C54F /* InvocableScheduledItem.swift */, + 57DDCE1EB82077DFA8196D502BE48F31 /* InvocableType.swift */, + 15832563E5BD805727075DD666DFCC6C /* Just.swift */, + 5620DEC10EDB32C938A7BCA68FC4785D /* Lock.swift */, + DC9BCB20DF73819810C2E781C03CA3F5 /* LockOwnerType.swift */, + F937B33AB2349728EAEBE30B14ACC732 /* MainScheduler.swift */, + 3F594796D37FA8E4181B6C9837866D3C /* Map.swift */, + 82266C25BBCBD86647BC2B7923D2B33A /* Materialize.swift */, + 66AEF1F18BB09CFF26081204A5716BAB /* Maybe.swift */, + 36B0CAA1E7547C748296D9FF14B3A8F9 /* Merge.swift */, + 3B5C59F9DE41D9B01A435F7BF7BD1E26 /* Multicast.swift */, + 73A9A3EEEFC050E309B1CF7BB6B34EFE /* Never.swift */, + D3A38977C4921EC3D67E5DC9A87F1E46 /* NopDisposable.swift */, + 5E43F537772E258AF502F38A512641D1 /* Observable.swift */, + 296C69A8DA05E42FC09D7342DEA5E30D /* ObservableConvertibleType.swift */, + 54CA22C46BEA679028DABD5E41774F7D /* ObservableType.swift */, + 9D60527BC85D168C986AD2CFF1D51998 /* ObservableType+Extensions.swift */, + 7606F0023754B879718D8B9541F4BF15 /* ObservableType+PrimitiveSequence.swift */, + 77AF92F12F598B9BEED3DFFCDE50EAC8 /* ObserveOn.swift */, + 355631D0FA9773D3CBAD76E466F848DE /* ObserverBase.swift */, + A38454798CDA8D34D056C8B5E0BA22C1 /* ObserverType.swift */, + 1A33295D5CA69066CEB503EAD303E41D /* OperationQueueScheduler.swift */, + 0414807C36F0D262CF9B76EFEB7C975B /* Optional.swift */, + 42BC5BAEE68B463D825B57F887FED7E2 /* Platform.Darwin.swift */, + CF9A0FF08CFBC930B36000A057A774A9 /* Platform.Linux.swift */, + 97C0C3568B5022C6BB1A43D26687A849 /* PrimitiveSequence.swift */, + FA76328C537A503C1B77311D0A2C3533 /* PrimitiveSequence+Zip+arity.swift */, + 51B7DF99F44018B800FB12ACED5FF6DD /* PriorityQueue.swift */, + D0BF79B957BC253B9F9F622E3DA26AEE /* Producer.swift */, + 51733B99E1E51A063736971961F48AF0 /* PublishSubject.swift */, + 3888EEE9DD9958C44FE1090A609BF16F /* Queue.swift */, + 91D0991D750AE18A29982329B999FEDF /* Range.swift */, + 81A4B883DE20BA52DBECF0CE87117416 /* Reactive.swift */, + D0B0E4DBE82AB38A449D35BA4C6CF1CF /* RecursiveLock.swift */, + 8D59A9F196D2018A996B8B5D4092D628 /* RecursiveScheduler.swift */, + 661DBD2189C578AADB4AD2ABECB572D6 /* Reduce.swift */, + 7386464B12C9B9D5D45B6DB16A6EE443 /* RefCountDisposable.swift */, + 886B2C07DFF2C711F399CC43936EAAE6 /* Repeat.swift */, + 1EA27B0FA2BCDEE2E68302FE74F36B0F /* ReplaySubject.swift */, + 97432F3721A1295916E9EE9A63DF61E6 /* RetryWhen.swift */, + D78FEDFFFE184B705D7E7C191AACECED /* Rx.swift */, + E6E3240C5482DA163A54D2D6674527F8 /* RxMutableBox.swift */, + 71C7AD37453C1150D3F33183FFB649B4 /* Sample.swift */, + 9324A6849331CB03EC6A65F1D0181040 /* Scan.swift */, + 23131B8059FE945B73FC34E46F907CD3 /* ScheduledDisposable.swift */, + 65A1C3236E061F091E6E42FC717B46DB /* ScheduledItem.swift */, + 9EB4FFCEC0440FD27F0D6CAFED9F09BF /* ScheduledItemType.swift */, + F8FBEFAD40A3F50A73E9886A885DED2A /* SchedulerServices+Emulation.swift */, + CFF30630BEEB8097918CA55E8575BDF1 /* SchedulerType.swift */, + 0217DDBDC78233930E7B2D4B10A4EF00 /* Sequence.swift */, + A2191E9AE1CD599F32FC4A21A9D0518C /* SerialDispatchQueueScheduler.swift */, + D5D3ACF1D878E195BDF9F514B113B776 /* SerialDisposable.swift */, + 0F38E046E0CD2CB36147067CD98085F7 /* ShareReplayScope.swift */, + A159B91671189A11B7F92DC40A3B59E4 /* Single.swift */, + F0B9E37063F2A18ADE927C78193C3C17 /* SingleAssignmentDisposable.swift */, + 1CD4CA3CDAD3FB75BCFEA79F132F3357 /* SingleAsync.swift */, + 17329B719AEDE982C87AEB16E07F81DB /* Sink.swift */, + 9D3E3CC8D7E1F0271CFA0868904F5EC8 /* Skip.swift */, + DF0BD4151C0E4A0190952BFF69D011D9 /* SkipUntil.swift */, + C359882BC848E9114C2412C4A30DF333 /* SkipWhile.swift */, + 7199CFB5B8CAFD358110536A33C227A4 /* StartWith.swift */, + 7DD046180099B4434D80E9C4EB641390 /* SubjectType.swift */, + 27C2257CED81A269B4F3CFD395A737F8 /* SubscribeOn.swift */, + D3CCF36EE801B8EF56E263EAD2E92A08 /* SubscriptionDisposable.swift */, + C10DC21EBAD81BA7D22A5EA5F096D256 /* SwiftSupport.swift */, + F440813566CE4FEBB85A775215C2B1C1 /* Switch.swift */, + 36BF8A2B8D6FDF8C2D4039E82ED313B0 /* SwitchIfEmpty.swift */, + D07911509368876C1EB24C2947E4CAA2 /* SynchronizedDisposeType.swift */, + A91049B03ECD97F4BA7F35F3BEA12C2C /* SynchronizedOnType.swift */, + 0F568642989B09534F4E2CF34ADE834D /* SynchronizedUnsubscribeType.swift */, + 7917278D67C732EA8824D2F598180959 /* TailRecursiveSink.swift */, + 84A45083FC7449764AF1103A0342E595 /* Take.swift */, + 0EBBFBD808747A32ABC0A9D48272095C /* TakeLast.swift */, + FA1E5A489614197B059BD7EF0B219DC0 /* TakeUntil.swift */, + 68C58BEBFF4071BC2F983B1A9DCAFED4 /* TakeWhile.swift */, + 3735D6A2DD9E0153CCC36C2C9EB50C64 /* Throttle.swift */, + 5B5470E42687026564FABF072383156A /* Timeout.swift */, + C493112951F78B37A5FADF7CD6C5ADE6 /* Timer.swift */, + 3DAB14E2B6EDB1F43829CF2AB53CC4A1 /* ToArray.swift */, + CCFCAF09367C94F7CDBFE09DBB92CF09 /* Using.swift */, + B9C9E72E22DF33D178D158F6A4918D07 /* VirtualTimeConverterType.swift */, + D5BEE546D9C98D268006E154C4DC5116 /* VirtualTimeScheduler.swift */, + 61DF4B6E4DF859118106BF282B06A33C /* Window.swift */, + 6F88EF52999F2464E771FC2D673E42B7 /* WithLatestFrom.swift */, + 1015A80CA0CD30BE28E2D2A3C0F657AB /* Zip.swift */, + 645DF232325867ABB538CC52A0A2A677 /* Zip+arity.swift */, + 2574918564F0C7583E08ECC28A77617E /* Zip+Collection.swift */, + 054547898E4BCFD63AD5ECC79517AB20 /* Support Files */, ); - name = "Support Files"; - path = "../Target Support Files/RxCocoa"; + name = RxSwift; + path = RxSwift; sourceTree = ""; }; CF1408CF629C7361332E53B88F7BD30C = { isa = PBXGroup; children = ( 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */, - A6EEDDCEDADF3C175A8BCD2F569758F4 /* Frameworks */, - E7766C882AD9E1B153ABB47D2BF77964 /* Pods */, - 566B90552B785A871DC0FF7D5350D062 /* Products */, + 5DE597AD3436977FDDB23A3824958CBB /* Frameworks */, + 14188A08879EE9FCA461843D2C310E1A /* Pods */, + 4BE88BEC1E83DCD0C869A3A57C48FC5A /* Products */, AEFC2A38B89EC70AE260239DCE6FD4FF /* Targets Support Files */, ); sourceTree = ""; }; - DCDD3DE20520E2D71DC6DF2B0B31A043 /* RxRelay */ = { + D5A1A43FED298FBAA62B259669553394 /* RxCocoa */ = { isa = PBXGroup; children = ( - 73A9D94E1C53404F1C79C9361B4FE031 /* BehaviorRelay.swift */, - F5FFF26103E94AD4A7D0FC160FBB109D /* Observable+Bind.swift */, - 7158E03F9F9E66C75E4578F6F0D41BB4 /* PublishRelay.swift */, - 144449BF4EA97422477E85516C12E4BD /* Utils.swift */, - C8245AA98277AE6F5D82C8A1CD8C5DF9 /* Support Files */, + 19BA186E169315ABC1A14BB2D6C4B102 /* _RX.h */, + 52C941DCDB3F6B0C1A675A2389D157F8 /* _RX.m */, + ECF4A10D2278E7683FAF28C4118469C9 /* _RXDelegateProxy.h */, + A54BC7BDCBA78BF1EC20099D31AA1404 /* _RXDelegateProxy.m */, + 0B812574628875C8E875DEF8AC3C3B14 /* _RXKVOObserver.h */, + 40B6058E10D64C4CDA4C4003E5F09318 /* _RXKVOObserver.m */, + EC2DBA6FA3B5F0017EAA6CDA39A7EB73 /* _RXObjCRuntime.h */, + 11A904EC64DFA23BCEB1F41261404EC4 /* _RXObjCRuntime.m */, + 79A8CC9EDAA7DFCB1E18EC681B2E22B5 /* Bag.swift */, + 17B9A7F92B5A3E3A3F255E74F08E50FA /* BehaviorRelay+Driver.swift */, + C6F55429E4F5A3684B1B610EEB9CBC83 /* Binder.swift */, + C970CE56C0F1DBB25C6F1EF915C69BA7 /* ControlEvent.swift */, + B0CD33ADC2C6492EFB2A1C9865747647 /* ControlEvent+Driver.swift */, + 784FD3E1244F1A96A68DBAACA9AACFED /* ControlEvent+Signal.swift */, + 723F15F9375F2B593537ECFA203122C1 /* ControlProperty.swift */, + E976DC771B75E8F4C938E082D2DC67E9 /* ControlProperty+Driver.swift */, + 55667AE78EBF92BF3FD083D92F3F038E /* ControlTarget.swift */, + F61EBC120DB0824119271C50578D5E34 /* DelegateProxy.swift */, + 4F9470706D8F36E200A0E14D91125B4E /* DelegateProxyType.swift */, + E4CCB369D05C229C176B9F89E63D0202 /* Deprecated.swift */, + D2C742FC85CDE50CD28E5956F0ADDB74 /* DispatchQueue+Extensions.swift */, + FB985A53F39481FA23B528D7486A0188 /* Driver.swift */, + B724B3052D7141BAB931AD7DDA4BE476 /* Driver+Subscription.swift */, + E19615B9A1BDAE31426AE13F76B0863B /* InfiniteSequence.swift */, + 4EC3085A93400F8B25DEC31B6BB987E8 /* ItemEvents.swift */, + D57411E3F5D1FE6F06C45BB8BE6ABAE9 /* KeyPathBinder.swift */, + 7CB0323D0C93433A2A590C992D5B2C75 /* KVORepresentable.swift */, + 78BF537112F36CF990F71AF86E97C406 /* KVORepresentable+CoreGraphics.swift */, + 09E025DA5339A8DFF424471D99726054 /* KVORepresentable+Swift.swift */, + F350DB4C798D0F260C3AE1891ECEEAF6 /* Logging.swift */, + 6410892B86384E401E39178B508F47B7 /* NotificationCenter+Rx.swift */, + 5119D72B27B8C09312A82E4774AB6C96 /* NSButton+Rx.swift */, + B64A231448882D94B15129D5A86DDAA8 /* NSControl+Rx.swift */, + 46F0BDEBDA102A8F380230089E3DF83A /* NSImageView+Rx.swift */, + 63D68E55920A869C800D56FD98EC9C81 /* NSLayoutConstraint+Rx.swift */, + 9353D0C358A0729BB1BEBEE191E85F7D /* NSObject+Rx.swift */, + 8D859A8A88C5A84E3E4AD9AD9B6B463C /* NSObject+Rx+KVORepresentable.swift */, + E9C21DE52F2543B4CBA30DFA7D153125 /* NSObject+Rx+RawRepresentable.swift */, + 25160B7A5A95101435E2C635A22B4B66 /* NSSlider+Rx.swift */, + 37A0F60CC9D52B64D82BCC6F7CD12FAD /* NSTextField+Rx.swift */, + 94DFF8110F6D1F6DD68850F236420519 /* NSTextStorage+Rx.swift */, + E9568E57C0E585A32EE7E2863AD45A12 /* NSTextView+Rx.swift */, + 5BE4CA9CBC1AD20B27FCF3C637CEC001 /* NSView+Rx.swift */, + EA516D24BB56BA4C75C278EF40971A4A /* Observable+Bind.swift */, + 54304BCBA467BC5A9BADBDEAAEC497B7 /* ObservableConvertibleType+Driver.swift */, + 321F4B543D57E15D74C5F63616BD9783 /* ObservableConvertibleType+SharedSequence.swift */, + 1E1356395FE392C74DC067DC515B2E84 /* ObservableConvertibleType+Signal.swift */, + 299B1BEACD3DC873914E50E57C3E4F43 /* Platform.Darwin.swift */, + D71A83BE43E28CBF5D49703E7B114BA2 /* Platform.Linux.swift */, + D616E8A716D3275DEDB55B9E7F3FDA20 /* PriorityQueue.swift */, + E7A5C3E41BA9D9DADDCD330F668DDF2C /* PublishRelay+Signal.swift */, + A163402F2A974483FDCA5F628E8E8AFE /* Queue.swift */, + 0F212D9E7E87950A9A19CF27D66D6E11 /* RecursiveLock.swift */, + 1047C1ADAC0CEC50E0BD02F90744FF8F /* RxCocoa.h */, + 8B27C2C39ABC4A9CFFDF48A71687A545 /* RxCocoa.swift */, + EE580AFDE74A4970B85874EF92F68E55 /* RxCocoaObjCRuntimeError+Extensions.swift */, + 83DE5521B45742BFD64A13767CBCF9B6 /* RxCocoaRuntime.h */, + 624F02C1F26E3F4651425171FAEE3170 /* RxCollectionViewDataSourcePrefetchingProxy.swift */, + 673B530043EE97D068D4854830529D8F /* RxCollectionViewDataSourceProxy.swift */, + 9C2045674F4DE6D2F4B178A9AC7E39BB /* RxCollectionViewDataSourceType.swift */, + 2D244D7B1DC3CBCF25A32DD82D7F612D /* RxCollectionViewDelegateProxy.swift */, + 518DC531B255B88E40E5651418722E86 /* RxCollectionViewReactiveArrayDataSource.swift */, + 09A35B0CB777BBD88B9DEF06B2BCD249 /* RxNavigationControllerDelegateProxy.swift */, + 6659B577E42EF97A5FDF4BC0E77791C7 /* RxPickerViewAdapter.swift */, + E829B940061EA02DBFC78ACD6DC4908A /* RxPickerViewDataSourceProxy.swift */, + 62D4533872082639E49CC2D812CCA9FF /* RxPickerViewDataSourceType.swift */, + 4FCF57E40DC0EEE76170EA7566F7A93D /* RxPickerViewDelegateProxy.swift */, + D62459D303A3950966A418BDE2EF5E9D /* RxScrollViewDelegateProxy.swift */, + C3DCFD52DE80EE3972E9D0E88FE4F085 /* RxSearchBarDelegateProxy.swift */, + A06041313ED286E457B40CA0D4F4555E /* RxSearchControllerDelegateProxy.swift */, + 8B39675E53AC002A88BF4E125C3B555A /* RxTabBarControllerDelegateProxy.swift */, + 8DE3CA5A0A2191AE9FDC8035DA6936DC /* RxTabBarDelegateProxy.swift */, + 6D7711C205CBF6BCA6CC225854D7D96E /* RxTableViewDataSourcePrefetchingProxy.swift */, + D7079AEAB9A6E700D8AF5363DF851A2B /* RxTableViewDataSourceProxy.swift */, + 9780DFB1A6645BAF294350731A0D5D12 /* RxTableViewDataSourceType.swift */, + E18421398E99489371ED0FFD97473558 /* RxTableViewDelegateProxy.swift */, + E8429204616E055CBD82FD738DC17DB1 /* RxTableViewReactiveArrayDataSource.swift */, + 09D0F36C487638509F0A7E3BC5B96C2C /* RxTarget.swift */, + 3D0180CFE946C46EF8AF4737A4DFAD94 /* RxTextStorageDelegateProxy.swift */, + 2E317DE1BFFB70C4D5832975F2922B01 /* RxTextViewDelegateProxy.swift */, + 5F3DC0EA3882AAC0C73433CD4667975C /* RxWKNavigationDelegateProxy.swift */, + 22C6AE88E774A68F4D2348DE664A96A9 /* SchedulerType+SharedSequence.swift */, + 099B959E823B66AD38AAE961201FBEE2 /* SectionedViewDataSourceType.swift */, + F4B9ABAE1767714182046DFA8A95ADB3 /* SharedSequence.swift */, + FE3831D5F8E37757EFBABC495A6FBCA7 /* SharedSequence+Operators.swift */, + 9E291AE3C1521D154766FC3F863C0556 /* SharedSequence+Operators+arity.swift */, + 59D97F87A443456155F519E2A0FCD855 /* Signal.swift */, + 724255BC9B7D55EC976790CCFA597FD3 /* Signal+Subscription.swift */, + FF9E866F54DE7EC41EC272983D1A5357 /* TextInput.swift */, + 5FFE744FD97312727A9E1589CD8DBE63 /* UIActivityIndicatorView+Rx.swift */, + CCE49DA992BF8ABA11EE69E00DB44AED /* UIAlertAction+Rx.swift */, + 0691AAD52FD34400A3BF78A3A24A58B3 /* UIApplication+Rx.swift */, + A61255D6036F7ACBE0D1DD5F407E59A6 /* UIBarButtonItem+Rx.swift */, + E34C1373861581DDF0256BE646DCE7B7 /* UIButton+Rx.swift */, + 8A2612662E1FE096C9556E86ED4BC8C0 /* UICollectionView+Rx.swift */, + 4AD199BA92F23A99AF5C9029FFE852F6 /* UIControl+Rx.swift */, + 8A46F5C2B8DA96C883B9042D339476E0 /* UIDatePicker+Rx.swift */, + E3AD1821877DA40E0007A480B71794B6 /* UIGestureRecognizer+Rx.swift */, + 82371E956C3016CE2FAB26325FA8263C /* UIImageView+Rx.swift */, + E0A2AA962931BB09A9089FEC7D8A1E30 /* UILabel+Rx.swift */, + 62417B7C7ED038B5F8F43B05FAD2BFE4 /* UINavigationController+Rx.swift */, + B55A44F27CEFEDAA349EA939F261EBAB /* UINavigationItem+Rx.swift */, + 9981BCDBEBC277C4997CD0A9C283BF05 /* UIPageControl+Rx.swift */, + 9E5630F16244E3A4DB87FBDF960B6315 /* UIPickerView+Rx.swift */, + C1D7A021E82ABD94264468585CA188F2 /* UIProgressView+Rx.swift */, + F66800F860EEF91C7FD4EE6DAF26617E /* UIRefreshControl+Rx.swift */, + FD5CA30B727DEEFA619FD1BBCFB85F1C /* UIScrollView+Rx.swift */, + 29043CE1FADE4EECB264248CA6136275 /* UISearchBar+Rx.swift */, + BCFFD2140D45F12ABBE22FD0596DACF9 /* UISearchController+Rx.swift */, + 43BBDAB01E88E016FDB56CAE0E18D1AB /* UISegmentedControl+Rx.swift */, + B148AEF0FF207D58212857BDEAE15A60 /* UISlider+Rx.swift */, + AC703B02DE4D059FEC238525C3FDB6E5 /* UIStepper+Rx.swift */, + F39CD0793FF148ED71A50FF908326D1C /* UISwitch+Rx.swift */, + 2B1917E6A743DBE3D87B9043CACA8435 /* UITabBar+Rx.swift */, + 4D13E474693D288FA9DFD047070BE0C4 /* UITabBarController+Rx.swift */, + B11C58CFC4921C01B180D0818D31F1CE /* UITabBarItem+Rx.swift */, + 8438E4076B74C43E8903AF30E833AD3F /* UITableView+Rx.swift */, + 9EC5F0B44C2299F90E6115EA3E9D09A1 /* UITextField+Rx.swift */, + A8635041539346B94338CE166995E9AC /* UITextView+Rx.swift */, + 53EAC9C5F32183C09D621EB078E77FB8 /* UIView+Rx.swift */, + 4837AB0A4DF18729E0F0A4791CE14A1F /* UIViewController+Rx.swift */, + 6EF4F2B170D864CB87EB954D73D92566 /* URLSession+Rx.swift */, + 7E2F3BC87F104DB09900DB492F6B2079 /* WKWebView+Rx.swift */, + 46EAFDC299EEC61B6E0A1A974FE737B5 /* Support Files */, + ); + name = RxCocoa; + path = RxCocoa; + sourceTree = ""; + }; + DDCF6E743B7BEC34751E3000CE5E93A0 /* RxRelay */ = { + isa = PBXGroup; + children = ( + 6A9EAA3A3F0ADEAA5CA9017D7A367920 /* BehaviorRelay.swift */, + 3792EC9BB21CD2D5F7B80FB23B95039E /* Observable+Bind.swift */, + A4BBBF627F4F3772693F6C60F062DC8D /* PublishRelay.swift */, + EDF43D98B673E5BD269472020316C22D /* Utils.swift */, + F649D7678104EDDCEAE644B404666457 /* Support Files */, ); name = RxRelay; path = RxRelay; sourceTree = ""; }; - E7766C882AD9E1B153ABB47D2BF77964 /* Pods */ = { + E721FF0E7B773D9A6D14DF0159C6B7F4 /* Support Files */ = { isa = PBXGroup; children = ( - 251798CE4B89C4EF770C7E95A96D19F5 /* Alamofire */, - 71D0CA6CAAE622D50FFD3D3881DE33F8 /* RxCocoa */, - DCDD3DE20520E2D71DC6DF2B0B31A043 /* RxRelay */, - 37D13EE4114B0876CB8A107C47F2C26D /* RxSwift */, + 7F4BDF9CDF423C6AE4A6BE7176115309 /* Realm.modulemap */, + 172C400CF391EDD3C0F55DA942FFD7AA /* Realm-dummy.m */, + E7C60E74C9D0F38FC7FC0B6E61907DB3 /* Realm-Info.plist */, + 49E7584983330E54D87E476814915B7B /* Realm-prefix.pch */, + 5A1141A4DC6BF96018F16D5E1D3579D2 /* Realm-xcframeworks.sh */, + D94963727939C0F7D500399F2C8178BD /* Realm.debug.xcconfig */, + 7B5BFEC05FC481CB99545BF0DB1DB91F /* Realm.release.xcconfig */, ); - name = Pods; + name = "Support Files"; + path = "../Target Support Files/Realm"; + sourceTree = ""; + }; + F649D7678104EDDCEAE644B404666457 /* Support Files */ = { + isa = PBXGroup; + children = ( + 2AE88125C2D485771098E31F97DB791B /* RxRelay.modulemap */, + C2A30AA03471E53D83530069F50267BB /* RxRelay-dummy.m */, + A5D1AF23DFAB1570FDB2C341191ABB1B /* RxRelay-Info.plist */, + 9482D73017F85685522CA70803E01C6D /* RxRelay-prefix.pch */, + 99F09ED9AD8D1B90AEBBEB42D6F5C9E4 /* RxRelay-umbrella.h */, + F5BDCEE005C5A46BC2C40BA42571EC23 /* RxRelay.debug.xcconfig */, + 2EA875143B8C27199FCF997B7DB5F566 /* RxRelay.release.xcconfig */, + ); + name = "Support Files"; + path = "../Target Support Files/RxRelay"; + sourceTree = ""; + }; + FB4DEA7BA784B3F5788979CAE8979264 /* Support Files */ = { + isa = PBXGroup; + children = ( + 709CB3C96BE62917AB9B052EAE6A59A4 /* RxAlamofire.modulemap */, + 77F0820D4FCD444B8F0423461352022F /* RxAlamofire-dummy.m */, + FBAD0D294AEAE312E17C2C83086A8B1E /* RxAlamofire-Info.plist */, + 06451B56A62C8C7862514E9B02C54DCB /* RxAlamofire-prefix.pch */, + 8BD9325336D6BFDFCEDBD5E891C35801 /* RxAlamofire-umbrella.h */, + 339AE1A23AF8CB3EC9886CBBF610FEA6 /* RxAlamofire.debug.xcconfig */, + 5E7AC000EA49E075669EE248F2B7E05D /* RxAlamofire.release.xcconfig */, + ); + name = "Support Files"; + path = "../Target Support Files/RxAlamofire"; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ - 1FFD75631C919CFA342F5F757E684346 /* Headers */ = { + 00BE76D6607847CF168B9337DD21470B /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - CB31EE213D63980611F112CDB77E8194 /* Pods-Darner-dan-uh-umbrella.h in Headers */, + 03A244E509AF9D417267A56CCFFCB618 /* RealmSwift-umbrella.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; - 8070B01910C64B9AFD0DB550EDE38D6B /* Headers */ = { + 17ECE33F6E89E8C62E32B8D6481AB352 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 7D3DD4A8BB36733BA15868F7FB8C56CE /* Alamofire-umbrella.h in Headers */, + 3289A76CF193BFE03721AF5CFF61BDDF /* RxAlamofire-umbrella.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; - 986537600D14761579460449DE03C288 /* Headers */ = { + 5AFD247974E9AF0D1F1FC12B3B2C00B8 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 7A93A22BD86309270AC44C644B7501FE /* _RX.h in Headers */, - 95A903FF7AB1A1BA9D09D37DF81A8AB0 /* _RXDelegateProxy.h in Headers */, - 805EEDF5A59400ABD8379567AACA849E /* _RXKVOObserver.h in Headers */, - 87DA86D77902ACF17437E16E77A0D6E0 /* _RXObjCRuntime.h in Headers */, - 23A4EF746AB64504DEB5EFDBA5450492 /* RxCocoa-umbrella.h in Headers */, - 2A8FD3A693CCE3F0B20522C1DD4F82B3 /* RxCocoa.h in Headers */, - 45AFB5D51C5929C8AB5858D694572F91 /* RxCocoaRuntime.h in Headers */, + E15573FC708D5EDC5AAB6AF8B6831C09 /* Pods-Darner-dan-uh-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 72C6DDBD255DC50707BA8A28E11B1F9E /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 1B77E002CB8E1A101F7126393905D01F /* RxSwift-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 7B568F3CC13C856C90ECFC9D9D8C80B7 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 9C4DD39A83D74041F03638E274B8BFD4 /* RxRelay-umbrella.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; - AC7B0A6EFACA41188A22FC6B3D0DE46A /* Headers */ = { + 7F654B80226476B88AF46C3ABE76ADBD /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - FB5A91DB25CAB3F3830F6BC5A7E88648 /* RxRelay-umbrella.h in Headers */, + A62F3672E29207515DEF358DD3F6633E /* NSError+RLMSync.h in Headers */, + 68D2FE7DB60E1387107B50F571744BB0 /* Realm.h in Headers */, + D51D0DFE7C3BCDE4221D5B3260E00224 /* RLMAccessor.h in Headers */, + E90526ABB1CD5261FDE755DD77D0C4D3 /* RLMAPIKeyAuth.h in Headers */, + 346E93481655EF0192EAB2E4F1C6060B /* RLMApp.h in Headers */, + 62D4000E5DD961FF8259F3C6BE1910B8 /* RLMArray.h in Headers */, + 39BEC8314726206A28B069A3A9908EB8 /* RLMArray_Private.h in Headers */, + 44B27CAB9BD2757B9E25BDA500D280C5 /* RLMBSON.h in Headers */, + 3BE1B2274ADA3803F49BF1C18AC27C1D /* RLMCollection.h in Headers */, + FABEE77ACBAE6140333658A06BAF49E4 /* RLMCollection_Private.h in Headers */, + 05A30A07F8C117BD7C39CA6B30467926 /* RLMConstants.h in Headers */, + 7AA2AFAB93B7DE3211F77A7B3FE073B9 /* RLMCredentials.h in Headers */, + 36AD49B08BDA824B92108187E7637D4B /* RLMDecimal128.h in Headers */, + E5A6D595C7534D56FEAD28CE551D9F52 /* RLMEmailPasswordAuth.h in Headers */, + CB0D0F5EFA558F6F88DF7413F90059D8 /* RLMEmbeddedObject.h in Headers */, + 93D01020E99D083DEF43CA8B1B0DBD57 /* RLMFindOneAndModifyOptions.h in Headers */, + 685FFE938626A3F4FDF08226915706E5 /* RLMFindOptions.h in Headers */, + 5693ED494E0695D33945FE54D5B5D675 /* RLMListBase.h in Headers */, + 7C5164249B7B15A1F1CBDD7662DE62E5 /* RLMMigration.h in Headers */, + 2C4BE39B7FBF43196B82140493093D41 /* RLMMongoClient.h in Headers */, + F59A8162BEEDFF3B08D72F884E8C55FA /* RLMMongoCollection.h in Headers */, + B685BE07C94C5F5B95B29A52C9B6C18C /* RLMMongoDatabase.h in Headers */, + 3FAABBFB4027D2DCA706441B19BDADC6 /* RLMNetworkTransport.h in Headers */, + DA535FB04CFB9C4F62208DFD228EDBF4 /* RLMObject.h in Headers */, + 1B054049CA45D1D34ADD6FCD32E93A14 /* RLMObject_Private.h in Headers */, + 7D034C0991497FAA18B16BD219918364 /* RLMObjectBase.h in Headers */, + 1710FFF89E963E5DC286A412749506A0 /* RLMObjectBase_Dynamic.h in Headers */, + A6D7397F93EA53BAEB5EB3ABFC95EC42 /* RLMObjectBase_Private.h in Headers */, + 20B5E5B3607D6CFBBD6F058031FA2090 /* RLMObjectId.h in Headers */, + 7BFF67A9816CAACFEA8C9D58D6B7A4AA /* RLMObjectSchema.h in Headers */, + D0764E3E0F0BFAB09CB05BFAE0A02C48 /* RLMObjectSchema_Private.h in Headers */, + F7AE89A62372E2CD0D50D4F51A2923EE /* RLMObjectStore.h in Headers */, + 8830BDFD242FDAECB9C82C0B3AC7780C /* RLMOptionalBase.h in Headers */, + 2F865C3E487EBDF4F476813284BB5F81 /* RLMPlatform.h in Headers */, + 8BC4D5D2027568EF154309C4C1834682 /* RLMProperty.h in Headers */, + 5C6CD6EC458C64C129D7460EB2228935 /* RLMProperty_Private.h in Headers */, + 7A7706AEA3478A3267331216D8264490 /* RLMProviderClient.h in Headers */, + 0FEC9640238E07A55D59D17C435A5403 /* RLMPushClient.h in Headers */, + 5FC8192C811F9B629ECE5FACD378266F /* RLMRealm+Sync.h in Headers */, + 89E2087ECB337C076F1ED6924E050CD6 /* RLMRealm.h in Headers */, + CB87669275CD6B778DF7BF1E65B44541 /* RLMRealm_Dynamic.h in Headers */, + 8D7DBC4316F288B12023F9C8BF0721FF /* RLMRealm_Private.h in Headers */, + 1D9700FF1D0B3A8088CAD38D4A17C0B8 /* RLMRealmConfiguration+Sync.h in Headers */, + 3E44A8350E62AA3BD996582DCEBB231D /* RLMRealmConfiguration.h in Headers */, + E7831E2B385EBB25849E550A74CD0167 /* RLMRealmConfiguration_Private.h in Headers */, + 20F284C3211D8E1E1BF87C624BDA657E /* RLMResults.h in Headers */, + 6FD6FB33CA60E3EEAC02743F81B2A795 /* RLMResults_Private.h in Headers */, + 2F2F1DFB33A8277A4606E3255191AC19 /* RLMSchema.h in Headers */, + E84407680552F606BCF100C93E99C5B8 /* RLMSchema_Private.h in Headers */, + FA65E7A4D9D79B661920AC61E8663358 /* RLMSyncConfiguration.h in Headers */, + 3C26765F8D546F45BD5742BA408E4AC9 /* RLMSyncConfiguration_Private.h in Headers */, + D20C13087EB9EB20752977D28868A504 /* RLMSyncManager.h in Headers */, + 3B8507630F8F598F244F3E99B25E1ECF /* RLMSyncSession.h in Headers */, + F2D2857797DF878132BA4026511F95D1 /* RLMSyncUtil.h in Headers */, + 13E9FFB9979FC3330603A9F299BD7233 /* RLMSyncUtil_Private.h in Headers */, + 4EE685A7178F6ABC51658C07200BDF40 /* RLMThreadSafeReference.h in Headers */, + 02CC843A3A5A9267FAD5C95335914738 /* RLMUpdateResult.h in Headers */, + 362CBF15761DA90CE183B818C1F4CBE2 /* RLMUser.h in Headers */, + 73413AE360E854E9F9C08B8829C3C1C4 /* RLMUserAPIKey.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; - CB727444D3CF0554E6606EE97EA619CC /* Headers */ = { + 8070B01910C64B9AFD0DB550EDE38D6B /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 7D3DD4A8BB36733BA15868F7FB8C56CE /* Alamofire-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 986537600D14761579460449DE03C288 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - A34D9DA66D7917D23B0D62054478683A /* RxSwift-umbrella.h in Headers */, + 7A93A22BD86309270AC44C644B7501FE /* _RX.h in Headers */, + 95A903FF7AB1A1BA9D09D37DF81A8AB0 /* _RXDelegateProxy.h in Headers */, + 805EEDF5A59400ABD8379567AACA849E /* _RXKVOObserver.h in Headers */, + 87DA86D77902ACF17437E16E77A0D6E0 /* _RXObjCRuntime.h in Headers */, + 23A4EF746AB64504DEB5EFDBA5450492 /* RxCocoa-umbrella.h in Headers */, + 2A8FD3A693CCE3F0B20522C1DD4F82B3 /* RxCocoa.h in Headers */, + 45AFB5D51C5929C8AB5858D694572F91 /* RxCocoaRuntime.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ + 1A538A5499B1706F0983D6826042657B /* RxAlamofire */ = { + isa = PBXNativeTarget; + buildConfigurationList = 19D83A142A5FC0D4D92A907CE6941B75 /* Build configuration list for PBXNativeTarget "RxAlamofire" */; + buildPhases = ( + 17ECE33F6E89E8C62E32B8D6481AB352 /* Headers */, + 47F45A0D0E307BE39C884A5D1FCFC3E6 /* Sources */, + 057906F6EC29C9F709DE046EDDB48C46 /* Frameworks */, + A232E82C5B9AAF5A84E70CA8888DD284 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 743D217C3A4E6C81C00E6247984A7A73 /* PBXTargetDependency */, + CD2C562089B256FDD5ADD654B9AC1142 /* PBXTargetDependency */, + ); + name = RxAlamofire; + productName = RxAlamofire; + productReference = 82F1475AA0F9C33F7EA4A1459305D2AB /* RxAlamofire.framework */; + productType = "com.apple.product-type.framework"; + }; 4622BFEF3DC16E8BD15EEFC30D4D0084 /* RxRelay */ = { isa = PBXNativeTarget; - buildConfigurationList = F71283EE81D71731FDAEB843FC5D0009 /* Build configuration list for PBXNativeTarget "RxRelay" */; + buildConfigurationList = EF6456B7AF7EA9AF5F5E54E9EC597DA1 /* Build configuration list for PBXNativeTarget "RxRelay" */; buildPhases = ( - AC7B0A6EFACA41188A22FC6B3D0DE46A /* Headers */, - E7F0ABE901E7FEB69EF99230B6061091 /* Sources */, - 2255531EBE8D50554450E2F565BACEAF /* Frameworks */, - A5BCDE206988115A055AABF049A07C10 /* Resources */, + 7B568F3CC13C856C90ECFC9D9D8C80B7 /* Headers */, + 6E19EF506F273CB4E029E1D134AC72BC /* Sources */, + 6E214DBF83D08F1F24944DC4EB113FDD /* Frameworks */, + 5ED45E7D6B8AFA91777BBACB2A03284C /* Resources */, ); buildRules = ( ); dependencies = ( - 6818CF147DC7F544793A124E2876DE1F /* PBXTargetDependency */, + 4B7953DADFBFC8B12FAAF48C9D4E96C8 /* PBXTargetDependency */, ); name = RxRelay; productName = RxRelay; productReference = FF8B264DFE802855D5D67E7CDDABFC3C /* RxRelay.framework */; productType = "com.apple.product-type.framework"; }; + 68494F30B4A13F8E5E88BCCAEC25B0A4 /* Realm */ = { + isa = PBXNativeTarget; + buildConfigurationList = 16D5AB567A9830B83428934DBAACEED4 /* Build configuration list for PBXNativeTarget "Realm" */; + buildPhases = ( + 7F654B80226476B88AF46C3ABE76ADBD /* Headers */, + 99CD59F39DEDC66A21E7D0F56129F344 /* Copy . Private Headers */, + AACC4BE359EF2DF8E9DBBCB9DF2A6A67 /* Copy . Public Headers */, + 57A2E3CD896E26D7B0978878DB6B2EAF /* [CP] Copy XCFrameworks */, + 31C090444FDCF38638CDEEC19B562B8E /* Sources */, + 52D162688CCA712D71B4749012FE8B3B /* Frameworks */, + 8D11DAB445DBDFCF20E39CB218793144 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Realm; + productName = Realm; + productReference = 921BE4A82C4A7A5C72A0C6F8B8FEF200 /* Realm.framework */; + productType = "com.apple.product-type.framework"; + }; + 782725687624F8665247B84AB581BEB1 /* RealmSwift */ = { + isa = PBXNativeTarget; + buildConfigurationList = 2D0C38C2045BD02E6E1A280EF6CF131C /* Build configuration list for PBXNativeTarget "RealmSwift" */; + buildPhases = ( + 00BE76D6607847CF168B9337DD21470B /* Headers */, + 987BA66B56817ACD9B7A89C6165E7DC0 /* Sources */, + 7AED940AC55E9545F0718C44CB713A9D /* Frameworks */, + B69C45066754860049C591DA4FFBD0F3 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 832652F97D9464A776DA6DB47A9DDA1F /* PBXTargetDependency */, + ); + name = RealmSwift; + productName = RealmSwift; + productReference = 437919EE08EC6BFCCBAC3BD346309742 /* RealmSwift.framework */; + productType = "com.apple.product-type.framework"; + }; 7AD0C6DCDC9CEC8A3C7C10C7FEE07BE6 /* RxCocoa */ = { isa = PBXNativeTarget; buildConfigurationList = F7028E084333DB57BEE3106A0E5C0DFB /* Build configuration list for PBXNativeTarget "RxCocoa" */; @@ -1371,8 +2426,8 @@ buildRules = ( ); dependencies = ( - 72FDBEDFD6D6E32E2CBCCDAA8F51F899 /* PBXTargetDependency */, - 0F5182513A3C7082E91EC7F7C9649135 /* PBXTargetDependency */, + 138C19B508083C0E4A285F0B219EDD6D /* PBXTargetDependency */, + 3F1DD9B01E60086675D3BD1DC9A3743E /* PBXTargetDependency */, ); name = RxCocoa; productName = RxCocoa; @@ -1381,20 +2436,23 @@ }; C9D3C7FA5AEC5037BB53F3A7ED236C60 /* Pods-Darner-dan-uh */ = { isa = PBXNativeTarget; - buildConfigurationList = F36470E19CC9B4BDA4369A4776800DE7 /* Build configuration list for PBXNativeTarget "Pods-Darner-dan-uh" */; + buildConfigurationList = 9E36B4B9D2DB067E7BD7966187B475EA /* Build configuration list for PBXNativeTarget "Pods-Darner-dan-uh" */; buildPhases = ( - 1FFD75631C919CFA342F5F757E684346 /* Headers */, - 499B7CCDAB1A6504EE40FCD7EE6FD7A9 /* Sources */, - D3B43FC517723ACC12C89F4A46FDFD51 /* Frameworks */, - 9170051942759A5F56EBBC0B7418F061 /* Resources */, + 5AFD247974E9AF0D1F1FC12B3B2C00B8 /* Headers */, + DBA57EC1D88CA688EE56BFB33208383C /* Sources */, + 9088A551B5300E32D3C328B75D0646E8 /* Frameworks */, + AE7D8A82707A9C7E93A9F466C3C2D6AB /* Resources */, ); buildRules = ( ); dependencies = ( - F21487C14FDB0883D8A5B8F61D922F87 /* PBXTargetDependency */, - 2BA25FD1E5B051CD6B1632932DA2E49E /* PBXTargetDependency */, - A0AC1167A7EDC58ED6C5738142E4B56F /* PBXTargetDependency */, - 2354AA506346B4B353C6948422111A93 /* PBXTargetDependency */, + 4CEE07902C2AD32A295BA78A490E25C8 /* PBXTargetDependency */, + 82B99BE3147B5798EA7325B546ED768B /* PBXTargetDependency */, + 29C6EECD957E8525858FF7C600787888 /* PBXTargetDependency */, + D18F8A2579759361D9046C3593BDD0B3 /* PBXTargetDependency */, + A1364262261DAC0871EB98B6F07B0C1F /* PBXTargetDependency */, + BF86C82170854AA5A7AFDD5D1B809D4D /* PBXTargetDependency */, + D5CA75F4974434FD13E3B0CB3AC3EC56 /* PBXTargetDependency */, ); name = "Pods-Darner-dan-uh"; productName = "Pods-Darner-dan-uh"; @@ -1403,12 +2461,12 @@ }; EA9EA43B3B503823EE36C60D9C8A865F /* RxSwift */ = { isa = PBXNativeTarget; - buildConfigurationList = 9B2D8D68CCB5B267F38915E244F92A0C /* Build configuration list for PBXNativeTarget "RxSwift" */; + buildConfigurationList = 9DC209E81355211B7B9357CBE2268AFF /* Build configuration list for PBXNativeTarget "RxSwift" */; buildPhases = ( - CB727444D3CF0554E6606EE97EA619CC /* Headers */, - A10DCE0124B85221CDF4297FAB8692B5 /* Sources */, - E8763B3979EF0B32E216122982C7987D /* Frameworks */, - 799F78865FC9A9D79C2522AB5ED75C36 /* Resources */, + 72C6DDBD255DC50707BA8A28E11B1F9E /* Headers */, + 387BE4231BBE89D567FD30920819A396 /* Sources */, + AC578672F4D30A165E966BE1FC1E79D7 /* Frameworks */, + A854B89FBDCAA36524192536373C1B86 /* Resources */, ); buildRules = ( ); @@ -1447,7 +2505,7 @@ LastUpgradeCheck = 1100; }; buildConfigurationList = 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */; - compatibilityVersion = "Xcode 9.3"; + compatibilityVersion = "Xcode 10.0"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( @@ -1455,12 +2513,15 @@ Base, ); mainGroup = CF1408CF629C7361332E53B88F7BD30C; - productRefGroup = 566B90552B785A871DC0FF7D5350D062 /* Products */; + productRefGroup = 4BE88BEC1E83DCD0C869A3A57C48FC5A /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( EAAA1AD3A8A1B59AB91319EE40752C6D /* Alamofire */, C9D3C7FA5AEC5037BB53F3A7ED236C60 /* Pods-Darner-dan-uh */, + 68494F30B4A13F8E5E88BCCAEC25B0A4 /* Realm */, + 782725687624F8665247B84AB581BEB1 /* RealmSwift */, + 1A538A5499B1706F0983D6826042657B /* RxAlamofire */, 7AD0C6DCDC9CEC8A3C7C10C7FEE07BE6 /* RxCocoa */, 4622BFEF3DC16E8BD15EEFC30D4D0084 /* RxRelay */, EA9EA43B3B503823EE36C60D9C8A865F /* RxSwift */, @@ -1469,7 +2530,7 @@ /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ - 799F78865FC9A9D79C2522AB5ED75C36 /* Resources */ = { + 5ED45E7D6B8AFA91777BBACB2A03284C /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( @@ -1483,7 +2544,7 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 9170051942759A5F56EBBC0B7418F061 /* Resources */ = { + 8D11DAB445DBDFCF20E39CB218793144 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( @@ -1497,7 +2558,28 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - A5BCDE206988115A055AABF049A07C10 /* Resources */ = { + A232E82C5B9AAF5A84E70CA8888DD284 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + A854B89FBDCAA36524192536373C1B86 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + AE7D8A82707A9C7E93A9F466C3C2D6AB /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B69C45066754860049C591DA4FFBD0F3 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( @@ -1506,6 +2588,26 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 57A2E3CD896E26D7B0978878DB6B2EAF /* [CP] Copy XCFrameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Realm/Realm-xcframeworks-input-files.xcfilelist", + ); + name = "[CP] Copy XCFrameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Realm/Realm-xcframeworks-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Realm/Realm-xcframeworks.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 2C8326877F6A9617C2FBE9BD15D95B59 /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -1550,169 +2652,322 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 499B7CCDAB1A6504EE40FCD7EE6FD7A9 /* Sources */ = { + 31C090444FDCF38638CDEEC19B562B8E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + DD5E8C7164EA60B7D90933D5F16E7490 /* app.cpp in Sources */, + A82149A817A79D292769BD47679567E5 /* app_credentials.cpp in Sources */, + B773E038954146A469A44710FE287988 /* app_utils.cpp in Sources */, + 484F15D31F05819E5E3FC3127405B114 /* async_open_task.cpp in Sources */, + 8BEF4FB2B3B83B4294C51BEAA865A2E7 /* binding_callback_thread_observer.cpp in Sources */, + 6108B62490C1C0715783C7CF562B07A7 /* bson.cpp in Sources */, + D791B0382F720B8C4B5D553908009673 /* collection_change_builder.cpp in Sources */, + 90D60900D03D9D9C7CEA26432FDA23E1 /* collection_notifications.cpp in Sources */, + 934E48A9D5A7C869FA3AF497C904B83B /* collection_notifier.cpp in Sources */, + 3BAC7D2129E214B646F9726B82ACBCBD /* external_commit_helper.cpp in Sources */, + 80F4387CB339E32E867FC3FD5D06EDC3 /* generic_network_transport.cpp in Sources */, + 79CB31FA3A1B23D44A0A0471E9C2EE3B /* index_set.cpp in Sources */, + 89A413D8ADFD0197CEB23799710A0BE7 /* keychain_helper.cpp in Sources */, + 16F6617A19B669D4EA139CE3BCEDDD09 /* list.cpp in Sources */, + 95ADC069FEDA015B200EC2CF279BD27A /* list_notifier.cpp in Sources */, + 23F3E10A4DBB9834978661796429B354 /* network_reachability_observer.cpp in Sources */, + 71A3695B1CBA3A936B62EBA9E12D5714 /* NSError+RLMSync.m in Sources */, + E00573EE63B4E0BEA8288B4660ED1AB3 /* object.cpp in Sources */, + 34A809F2EFE03CCD28E205805C749FE4 /* object_changeset.cpp in Sources */, + 6FFE3D1B499EB10FBEF54B11B6914EEA /* object_notifier.cpp in Sources */, + 7AC2030996D338C027D2A864AC00806F /* object_schema.cpp in Sources */, + 3655E896EC942A91908C3E6C2FF44830 /* object_store.cpp in Sources */, + 262B533DDE9925F5ADFEC7EFD95697FA /* placeholder.cpp in Sources */, + 916174DBE8D667BEE3774A286F22AF48 /* push_client.cpp in Sources */, + D440B41F87F5C037A0BA851C26231AFD /* Realm-dummy.m in Sources */, + 7995E0CD758104708892EC53E508A900 /* realm_coordinator.cpp in Sources */, + E261648E916D34916F2F63D857C9A77B /* regular_expression.cpp in Sources */, + 58C84DC22DCFA32BC2C40603F2515323 /* remote_mongo_client.cpp in Sources */, + 8D19635341502D13EB61E1C8F54ECB62 /* remote_mongo_collection.cpp in Sources */, + F820ACC051D239EF5BDE2C0FFF724196 /* remote_mongo_database.cpp in Sources */, + 8B95E16BD1E45AD2AD5FADA674641F58 /* results.cpp in Sources */, + 3B16B1FA9F291577F7A38D26AA4072E3 /* results_notifier.cpp in Sources */, + 1E88822153E6359EF32E90F306FB9A3B /* RLMAccessor.mm in Sources */, + D0DD7B89F7D44FC9C89C6011FFC678FA /* RLMAnalytics.mm in Sources */, + 18647A26267C25CCA0A69980F0361B1C /* RLMAPIKeyAuth.mm in Sources */, + 07DC2E90E5A497D6D74DAC6DEFA59184 /* RLMApp.mm in Sources */, + 19E834C227A83A88B934BAC1D912DACF /* RLMArray.mm in Sources */, + 0F5C8237D37574BDF4B202D4C54FD84A /* RLMBSON.mm in Sources */, + 6907E511281A1585862FA580BA1AA27A /* RLMClassInfo.mm in Sources */, + F01DFDF2060AB810B670CCB76AAEA85F /* RLMCollection.mm in Sources */, + F63BBD21E5DDFAB3973E0905D2301869 /* RLMConstants.m in Sources */, + 8BB7DB661CCE73DCD3AD00A9B0281C70 /* RLMCredentials.mm in Sources */, + F1B409D1BE71BBB170395E9121F0C67A /* RLMDecimal128.mm in Sources */, + 8E9DCE0300CB6B885CB0B0848660CDB4 /* RLMEmailPasswordAuth.mm in Sources */, + 23198C37125F7D48363439FDED535895 /* RLMEmbeddedObject.mm in Sources */, + 5B2D4557AB2074A39773DB270E6C3DDB /* RLMFindOneAndModifyOptions.mm in Sources */, + 44B6F5708A1CE9EE9BEB29866102A469 /* RLMFindOptions.mm in Sources */, + A848EF9FFBA3FDA9CC5119C087592FEA /* RLMListBase.mm in Sources */, + 729CF267488A10754F1E249B4E5DE1AE /* RLMManagedArray.mm in Sources */, + D61D564476EF739873DD9EBDE8416963 /* RLMMigration.mm in Sources */, + 576E58F745809FE5EA79AF979F7CB959 /* RLMMongoClient.mm in Sources */, + 178044E8590E008952687280FAC7A3B7 /* RLMMongoCollection.mm in Sources */, + 49A989318D26BD0E6FD80A91B8F1486C /* RLMNetworkTransport.mm in Sources */, + 30EB41114FFEBF43058708FDD2A1FDED /* RLMObject.mm in Sources */, + E515A33E15D267644599D92FFF01C153 /* RLMObjectBase.mm in Sources */, + 857D651808499F8B24D5EDE50D147551 /* RLMObjectId.mm in Sources */, + 2FCE7C367D4CD8660C8A29D02B3FA7A7 /* RLMObjectSchema.mm in Sources */, + 601BF4A1BE00CCD3E7DF72E06D546534 /* RLMObjectStore.mm in Sources */, + 6D419CC34E321A9F0BC9A16E44593339 /* RLMObservation.mm in Sources */, + 8CD9C9A4B73AA40DA804E9D351A356D4 /* RLMOptionalBase.mm in Sources */, + D0B4E40C0F861DBC1FE63272EC95444A /* RLMPredicateUtil.mm in Sources */, + 642E161B02B38B6D4C18373D2C37D573 /* RLMProperty.mm in Sources */, + B435FA7C9BD453EBB6B51256E5B64F11 /* RLMProviderClient.mm in Sources */, + CD3D3D27D37B7B9B0001FD398284717F /* RLMPushClient.mm in Sources */, + AB1F6B3296C144585DDCBCCABB6D9343 /* RLMQueryUtil.mm in Sources */, + F3F7760BFC76C0A414395ED3DF1E6C90 /* RLMRealm+Sync.mm in Sources */, + E3DF652CDC2438967B655D3ED5BE83CE /* RLMRealm.mm in Sources */, + CFEA3F101DE538F84287DC4A0850310D /* RLMRealmConfiguration+Sync.mm in Sources */, + 1751F4D5E808044F5256F9D215C05B55 /* RLMRealmConfiguration.mm in Sources */, + A3F211F51254914790080A6E804A9D60 /* RLMRealmUtil.mm in Sources */, + 841E48251F31B1D543566E3A13865ACD /* RLMResults.mm in Sources */, + 52B827057310BA50188CD872748D8EDE /* RLMSchema.mm in Sources */, + 1606DD80E17C3C3F5EF57010FF2F2283 /* RLMSwiftSupport.m in Sources */, + F5AF9CF0B558FCD45C0DBFED149299EB /* RLMSyncConfiguration.mm in Sources */, + 64A68FDD7E4FF7FE7BDED7EE918A8B25 /* RLMSyncManager.mm in Sources */, + 9DC377BA787CE5DD877D77390EB6AA4E /* RLMSyncSession.mm in Sources */, + E1AF1FE47E95F9A724ACA36136445D60 /* RLMSyncUtil.mm in Sources */, + 9FCF8D3AA301D89BC32C6023A0A5C21B /* RLMThreadSafeReference.mm in Sources */, + 7284925E9037C99E8F2EF8B9E3C5097C /* RLMUpdateChecker.mm in Sources */, + 933D4526196380D5F0A886A9717E7DE3 /* RLMUpdateResult.mm in Sources */, + EACA770276C17263B13712AE21C51C62 /* RLMUser.mm in Sources */, + FC7C7F9AB5C91F3E3B8E0A7AA9B4D223 /* RLMUserAPIKey.mm in Sources */, + 78A9DFDD190D31400114C1E6981B8728 /* RLMUtil.mm in Sources */, + BB4A976D04B8FC213E343AB9762058ED /* scheduler.cpp in Sources */, + 5D99E2CB87F0128C877A251BE5FEB7FC /* schema.cpp in Sources */, + 0603EE49571AF2F3E368BBED1EC7EA03 /* shared_realm.cpp in Sources */, + 680A5E8F4B218F13EF981C79A59DF96D /* sync_file.cpp in Sources */, + F47689A031D0C57D3F9C93EB43854C7D /* sync_manager.cpp in Sources */, + 8F10537A5EE0F53AA7F12A197A35561D /* sync_metadata.cpp in Sources */, + CBF5210B66B6E2BB31EB10649B3C688D /* sync_session.cpp in Sources */, + B7D97D56253496C380B8814779679641 /* sync_user.cpp in Sources */, + 2E92A4050BE7F15D17D28B27CD7CDE8A /* system_configuration.cpp in Sources */, + F427DF803EE73A3582492EB0161E0D8B /* thread_safe_reference.cpp in Sources */, + 266D487710C4475F9E508F2BECE80CD2 /* transact_log_handler.cpp in Sources */, + E23C04D2B3D8A4F5C4DBB96B5A07C9CC /* uuid.cpp in Sources */, + B7BE18598E8D81B5BC8CFD2542CDE8AC /* weak_realm_notifier.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 387BE4231BBE89D567FD30920819A396 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B17EE6534DB2F9BE4C7F022EFC577F6E /* AddRef.swift in Sources */, + 48D9CD209B48FA979CE03D682AE1EFDB /* Amb.swift in Sources */, + 425BB7C9815A5326C554A139D99522B0 /* AnonymousDisposable.swift in Sources */, + BD981502B63CA6245CDA8ED2975F73C5 /* AnonymousObserver.swift in Sources */, + 4955084D6408D4EB955FB42512C45E7E /* AnyObserver.swift in Sources */, + F72A6848430F0D0900D4917EB5E08F60 /* AsMaybe.swift in Sources */, + 9B0C27309D7AA03EC0B4B74C637F728E /* AsSingle.swift in Sources */, + 8379CE8ADB710D5E66BA7034FD91C106 /* AsyncLock.swift in Sources */, + 7EC4129725587E781EF3F79E63AB40EC /* AsyncSubject.swift in Sources */, + 91D00124917562F52641A33E63D781BE /* AtomicInt.swift in Sources */, + 05AB3D293B53F3DD1CF4079C346CC4DC /* Bag+Rx.swift in Sources */, + E00E7BF9489CA487E2C1FB8A178D0CE5 /* Bag.swift in Sources */, + 04291E11FB888F5E49E3DE64AA4FABEA /* BehaviorSubject.swift in Sources */, + 0C8541A37D210B0733A638DA526922A9 /* BinaryDisposable.swift in Sources */, + 280BF82393448B0CD8049ED6F681169D /* BooleanDisposable.swift in Sources */, + 1923AA0E1C547281C5310C62475BB01D /* Buffer.swift in Sources */, + 5D8E7BE5D7BDAB74C246233E8C1B778D /* Cancelable.swift in Sources */, + 92722A376625A1F7149AA703E0408894 /* Catch.swift in Sources */, + 558E5FFD90EBBB90A9BD5F6DBB55B225 /* CombineLatest+arity.swift in Sources */, + B569012D3FF00C015F0C5ADDB20B04F4 /* CombineLatest+Collection.swift in Sources */, + D3473A57080E70B88DA22CCCE335DCE2 /* CombineLatest.swift in Sources */, + 3BA050EA7B1B3936903B9CF1C69F9A58 /* CompactMap.swift in Sources */, + F1D0CF365F1C0EBBB9BE8D3B246AEA82 /* Completable+AndThen.swift in Sources */, + 9D30F00BD5CDA6D4DAC0715BF9A657AE /* Completable.swift in Sources */, + F9DEBDD0C6E5A2B7C90988C387E30CE3 /* CompositeDisposable.swift in Sources */, + B4F5580D3DFD4A2376B8897262380FA6 /* Concat.swift in Sources */, + 3A147160AC0E2C5D9235AB146A408B05 /* ConcurrentDispatchQueueScheduler.swift in Sources */, + A60C4E1E2F7572919C180B47A0F29287 /* ConcurrentMainScheduler.swift in Sources */, + 5AC65D32099C396B5D4EF9125BB7649D /* ConnectableObservableType.swift in Sources */, + 78ADB328BD29F62221BF79CEB2A89C81 /* Create.swift in Sources */, + FD1FE0BE94202EE309BB5D85BDB3932D /* CurrentThreadScheduler.swift in Sources */, + 35C06A684501F663EE30584A1C521A63 /* Date+Dispatch.swift in Sources */, + 12D1D8022F0ADA477ACEEAFCAC837CC7 /* Debounce.swift in Sources */, + 9791DC9559CFAF714A92BACF5B13FEF4 /* Debug.swift in Sources */, + 299DC3F31727763F334045CDF53A4188 /* DefaultIfEmpty.swift in Sources */, + 04BF7123DC74735A133F921FA96DD396 /* Deferred.swift in Sources */, + 4CBE7E174AF7FEE6949C6B5C18CA86F9 /* Delay.swift in Sources */, + 0E385F3601A33770B0F4FC24D17CC469 /* DelaySubscription.swift in Sources */, + 2F496C7787E50D612CE4F988FE7AAE5E /* Dematerialize.swift in Sources */, + 2D544742288315C957F9C5AF2EB78663 /* Deprecated.swift in Sources */, + 13500A001014B83E39A6F69782E84BE3 /* DispatchQueue+Extensions.swift in Sources */, + 38AA5C81B840EB73613085FA590D387A /* DispatchQueueConfiguration.swift in Sources */, + 3BC7E8B18CC01924EA304D1E351289CA /* Disposable.swift in Sources */, + EDAF0F759F933084FC54F9CFF660E5CB /* Disposables.swift in Sources */, + 01483F7977CD82C2E9DD58015E2A0176 /* DisposeBag.swift in Sources */, + 9F2C5F100F306A6B3AC4F959485D60C6 /* DisposeBase.swift in Sources */, + 50747D518C1C4C1FB8738CBDF820D2E4 /* DistinctUntilChanged.swift in Sources */, + 0AA03F782CE96EA724D4508E7312DDBB /* Do.swift in Sources */, + 883D5FBBA006E6B1614CD8B08853A8D2 /* ElementAt.swift in Sources */, + 0CE4DB3675E51900B206B8EF3A222AF6 /* Empty.swift in Sources */, + 022550CAA9C8BDAAAFA7AE5051910CF7 /* Enumerated.swift in Sources */, + 81892F5B2F07DC6BC0835CEF849DF4D4 /* Error.swift in Sources */, + F0BAF3ADF3EFB71158582B96DE71369B /* Errors.swift in Sources */, + 69E8F762D62563EF01CE5B68227D6515 /* Event.swift in Sources */, + E82171EB33337F99847E03EEAB85B001 /* Filter.swift in Sources */, + 029771921593A90D3A2120AAF9B8480E /* First.swift in Sources */, + FC136B129F9CD401CA9639D078B07967 /* Generate.swift in Sources */, + 3B6D2A9BD94A099667066E9733925D55 /* GroupBy.swift in Sources */, + A6B6A8ED7B80DC2A06E62E2E84907C78 /* GroupedObservable.swift in Sources */, + 00C4123FD9546F715751A4FCCD0DC2DF /* HistoricalScheduler.swift in Sources */, + 08C80374C02F106D2071840C9FD56F52 /* HistoricalSchedulerTimeConverter.swift in Sources */, + 73F87077A3D9144B369905812C38AC55 /* ImmediateSchedulerType.swift in Sources */, + 79E9EE217D63D5047BEFF84619151822 /* InfiniteSequence.swift in Sources */, + CD7EE17531481812A65BDE3B634BE875 /* InvocableScheduledItem.swift in Sources */, + 3E5888DBBB86DD9A7DB40B66D5D3F6C4 /* InvocableType.swift in Sources */, + 76C493AB7CC762FD68D29C8A099824B5 /* Just.swift in Sources */, + 0016AA0031565901037DDB550FF54651 /* Lock.swift in Sources */, + 18947EB8E832B0DE78FDFFA72FC91E82 /* LockOwnerType.swift in Sources */, + EAA258B8E03F55639960CA88385E4714 /* MainScheduler.swift in Sources */, + 51BDB454EA5B0F00C57B88F0B0926043 /* Map.swift in Sources */, + E66AE676C6BE74CC63FFE2FEEB560BAE /* Materialize.swift in Sources */, + E88BAAFE9AB16EBDB9F5CEA497F966A9 /* Maybe.swift in Sources */, + A79FB31B60D9705E762A82DD6AB4AB9B /* Merge.swift in Sources */, + D7E1E91CC797E5D4A1B6F0359FAD7297 /* Multicast.swift in Sources */, + B28296A50EB5B5B7742072F953004A7B /* Never.swift in Sources */, + ED3E0C98F7B39EF67FA8EDC302E94528 /* NopDisposable.swift in Sources */, + 849425BFC2B04B4F257995418BF94E56 /* Observable.swift in Sources */, + 0108B6FF9CADAB6BC4B784020F3EECFB /* ObservableConvertibleType.swift in Sources */, + 00C19614038FA2FB5DE63D615E4AF4B9 /* ObservableType+Extensions.swift in Sources */, + B6D36B8C8627159F88D54CA56BD9F892 /* ObservableType+PrimitiveSequence.swift in Sources */, + EF8F15A02A01B3F72D709C006C92C5AF /* ObservableType.swift in Sources */, + 889CB56B5E9CF3A71E4A91509F741D73 /* ObserveOn.swift in Sources */, + 249F7A7872239AF311B195CC27BC3051 /* ObserverBase.swift in Sources */, + 9331460E161ADBC85F891527849EC282 /* ObserverType.swift in Sources */, + 70D827AB6A89FD2D5D05325E9A8D2036 /* OperationQueueScheduler.swift in Sources */, + 4A7BE4972B1BB13FEE90F5D6561C8A68 /* Optional.swift in Sources */, + 0AA0F6F5C08A1CF24E8F821530A80B35 /* Platform.Darwin.swift in Sources */, + 4E2397162787DDCC0EB80D8B41B4015F /* Platform.Linux.swift in Sources */, + 042C3858E9EC93DECE415071DE0FB0EC /* PrimitiveSequence+Zip+arity.swift in Sources */, + 31E4B1E07CDE81B5A2A2B108976159D0 /* PrimitiveSequence.swift in Sources */, + A746788821047E64C8BD4E9D87C9B625 /* PriorityQueue.swift in Sources */, + 9DF8C6A435E81BF8787790DFECC08411 /* Producer.swift in Sources */, + 83B7E3B66F98454A70D50243B06C642F /* PublishSubject.swift in Sources */, + EE6252936D0BC4DF4016D58AEDDCE2BA /* Queue.swift in Sources */, + 073D5880E07C42312556418DF3AE7DCB /* Range.swift in Sources */, + 2EF232DF8C8C17CF8E9EF17A38284F07 /* Reactive.swift in Sources */, + 881C70481B46015D67ADA02E19FEF6E1 /* RecursiveLock.swift in Sources */, + 4C7CA14C1636AFACC3B4DC7F57A8CB4F /* RecursiveScheduler.swift in Sources */, + F612FD4FD9711510D62CDA9D9173AB72 /* Reduce.swift in Sources */, + 2592EAA1FF58939571C426109D21E5A5 /* RefCountDisposable.swift in Sources */, + 478ECC8504F31C605CF07FBC245A7CFF /* Repeat.swift in Sources */, + 7EF7523471466693BAC8D062665C5739 /* ReplaySubject.swift in Sources */, + 07D48815D96656AFEDF8BF96FAEC5072 /* RetryWhen.swift in Sources */, + DBB377F541B3603F9BA9606A1DB64DD0 /* Rx.swift in Sources */, + D4C7B6A1541F75250C3983CE364604A9 /* RxMutableBox.swift in Sources */, + 9E4DBAD6AF431F668F94E956E92C908A /* RxSwift-dummy.m in Sources */, + EF379606D0834B984BBE54F532B2E2AC /* Sample.swift in Sources */, + B8E6E280D60598D2495DF9B150792294 /* Scan.swift in Sources */, + 060971B9618A74DBF249CFC67C837936 /* ScheduledDisposable.swift in Sources */, + 33390E01D7EB4E3564907513AD16D565 /* ScheduledItem.swift in Sources */, + BAA015FE03F9938E2BDAF8750F8A0E60 /* ScheduledItemType.swift in Sources */, + F9E078483BA3FB0B5E8FDDD1F2C9B87E /* SchedulerServices+Emulation.swift in Sources */, + A4103D4B6E809B607DAD34B0723B4733 /* SchedulerType.swift in Sources */, + 5C724AD09CAAE87E18B82180F589C91C /* Sequence.swift in Sources */, + F177DDB062A8B87A9B598A36B5E9B27F /* SerialDispatchQueueScheduler.swift in Sources */, + 79DCC8A5ED66BF9DAA3ABF7253E79A44 /* SerialDisposable.swift in Sources */, + 3B7DC5D2B66F25F12674A8DEF1F39D56 /* ShareReplayScope.swift in Sources */, + CFD83F343EE1D966D873AA35362A2459 /* Single.swift in Sources */, + 36E7A944CC80CA15996E3B3BCDA9A334 /* SingleAssignmentDisposable.swift in Sources */, + 9D00BC8AB11B42F866B0C935D4F0782A /* SingleAsync.swift in Sources */, + EC25AC8D0A5DCEC1CED82C041B9DD003 /* Sink.swift in Sources */, + C7390ACBF2CEE2475250D982924AD5EF /* Skip.swift in Sources */, + C096DCFF1DF830B2FBDE80D30EA3BA51 /* SkipUntil.swift in Sources */, + 7F9ED1AB9D2DBAF3372A76755CBFCA36 /* SkipWhile.swift in Sources */, + FC674115A5CC3B1735233CDF98DBE616 /* StartWith.swift in Sources */, + 51C4A45A24282CA38D96E659DBB731EC /* SubjectType.swift in Sources */, + 7DD47F7CB7EF38A8097DDA5EE0DE5260 /* SubscribeOn.swift in Sources */, + 29609EB2017138C87F03CAD2376A8DF6 /* SubscriptionDisposable.swift in Sources */, + 4E72EBF6BB344291A468CC1F94F2C618 /* SwiftSupport.swift in Sources */, + 8BC5AA1E6AD1AB6DC4B9D729B4FA51E0 /* Switch.swift in Sources */, + 0525A9617675846B3F73BE5FB01EC5BB /* SwitchIfEmpty.swift in Sources */, + D1AD996716AF2C4C0A0FFDEB20CB76D6 /* SynchronizedDisposeType.swift in Sources */, + AF6D1FFF733DF2F1D2AF703D850832E6 /* SynchronizedOnType.swift in Sources */, + 7AD20C0DC5EC36C37F5557432449B972 /* SynchronizedUnsubscribeType.swift in Sources */, + 5B4067B84E6CB07830DE450A584651ED /* TailRecursiveSink.swift in Sources */, + 0D33FDF6B374AD0343214C16D30DDCDD /* Take.swift in Sources */, + F3B9DB19F608BFC873563494E3314EC9 /* TakeLast.swift in Sources */, + B89076FEF8EC003AC980CF918B9D20C6 /* TakeUntil.swift in Sources */, + 3E3E4FA86DBC2FF9B83337344365DED6 /* TakeWhile.swift in Sources */, + 46B81D9973FAC783A65A54B616A846C5 /* Throttle.swift in Sources */, + 2D476996F278959C1EBDEC64F4E904D8 /* Timeout.swift in Sources */, + 1CDC24596F1E0A53B36850A1B64B3F34 /* Timer.swift in Sources */, + DBA19C2B1420E4D0A8852A0434F364F4 /* ToArray.swift in Sources */, + F2343D5AA1F53A22738D26788BFAEE74 /* Using.swift in Sources */, + 9D7C342E2385A7BD0961AD94EF2DB544 /* VirtualTimeConverterType.swift in Sources */, + 66903C58DF7B49405B034C65DEDF7ABD /* VirtualTimeScheduler.swift in Sources */, + C9173647F028584F2E41255AAD3494AA /* Window.swift in Sources */, + C23BA015C29D1BD3F7E22641CD999AAB /* WithLatestFrom.swift in Sources */, + 2D58DDCB6077DE2D2A5FF49C89C88FF0 /* Zip+arity.swift in Sources */, + C0FA5CDF1CE99093FF0694BDF834069C /* Zip+Collection.swift in Sources */, + DFF0EA52B9AC62085891FC48C2ABACE0 /* Zip.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 47F45A0D0E307BE39C884A5D1FCFC3E6 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 589BC47EBB7DBE6F853F1800E67E431D /* RxAlamofire-dummy.m in Sources */, + A37330602381FBF8EBA947F042E5D3FD /* RxAlamofire.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 6E19EF506F273CB4E029E1D134AC72BC /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 94F295D2FA27DD8400B899BFAE5AB365 /* Pods-Darner-dan-uh-dummy.m in Sources */, + A89453604B902774519EC42E6316C985 /* BehaviorRelay.swift in Sources */, + 578CA2B081756A519BC26FC24375866D /* Observable+Bind.swift in Sources */, + EACFEE3517A5D770813C785F4FB2EAAE /* PublishRelay.swift in Sources */, + 1E4EEDD5D7E13356500F9A828204E08D /* RxRelay-dummy.m in Sources */, + F2CF55CAEDDD01EF9B402D0E3E0121DF /* Utils.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; - A10DCE0124B85221CDF4297FAB8692B5 /* Sources */ = { + 987BA66B56817ACD9B7A89C6165E7DC0 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - E760665C0AB19104AAE980C29CAA2F76 /* AddRef.swift in Sources */, - AA95D0BECE2FDCB55E0A59A0C52272FF /* Amb.swift in Sources */, - 8DA4CF1E2F19EF6E9B7F00F3A59510A9 /* AnonymousDisposable.swift in Sources */, - 3A04E00DA0A3F78C8F5C9983AFB98874 /* AnonymousObserver.swift in Sources */, - DEE005A7C80140E09224D958FECE2F5D /* AnyObserver.swift in Sources */, - FDEA0FDF7F44B7194D7B2C7A99B8F2E5 /* AsMaybe.swift in Sources */, - FC5FC3AD0EDCC97604F56C68B0D5029A /* AsSingle.swift in Sources */, - DB2A5396B53CD8A93F0043C66018F9C8 /* AsyncLock.swift in Sources */, - E87B7B8EAE2A3B1203CCE091B8994D7A /* AsyncSubject.swift in Sources */, - 86F42A02F82E7BF498DD7E39387FC90A /* AtomicInt.swift in Sources */, - A3947A2A74E8A0C652E26D61F30358BD /* Bag+Rx.swift in Sources */, - 179A924CC44BF28726F6D33001A5F5D8 /* Bag.swift in Sources */, - 2C3CFDD65F1BA7AB67BAC592017179EF /* BehaviorSubject.swift in Sources */, - 16B1D83EEC7F48EA8F95F891519AE6D9 /* BinaryDisposable.swift in Sources */, - 32544C48C4D27B134A181649A10641D1 /* BooleanDisposable.swift in Sources */, - 63171E68FC84120462E1CB6447862C71 /* Buffer.swift in Sources */, - 972752F5D0CB130EB55EB4BCDA161A71 /* Cancelable.swift in Sources */, - CAF399B9B0C071AB9DA54EFAB35FA05D /* Catch.swift in Sources */, - 4FBB4DBC2D984EF3D557AEDDCE238777 /* CombineLatest+arity.swift in Sources */, - 354917F5BA206895F2F9FCF8FEBF161E /* CombineLatest+Collection.swift in Sources */, - B721D47828DBCCEC8579800F3E1686AE /* CombineLatest.swift in Sources */, - F45A4698016A78D7C3C0E1A8CC28CD2B /* CompactMap.swift in Sources */, - 7E0202A48FF79AAE5A19524E46E45DDC /* Completable+AndThen.swift in Sources */, - CE52DEEB5A518D4E80AAD0B32C44493C /* Completable.swift in Sources */, - E99871F1698413492981F4D5B83ACA55 /* CompositeDisposable.swift in Sources */, - 2AB97EB5B0C17CB8AB8F9B5DF4662B49 /* Concat.swift in Sources */, - E6E046A2DA04D941708C043BE6EDBE26 /* ConcurrentDispatchQueueScheduler.swift in Sources */, - 3147DCDF7BD5EF6A09CCEA02DA51C1E1 /* ConcurrentMainScheduler.swift in Sources */, - E586EDD4E5F5DDC0B2010E28ED8A9540 /* ConnectableObservableType.swift in Sources */, - 2B9DE05CC8ACBEB8B8B6FEFDFAA9FABD /* Create.swift in Sources */, - 03A4EF6D6ACF6027EE70E29F57D05C93 /* CurrentThreadScheduler.swift in Sources */, - F5643E260EB37A5825F38AC065EF3CE6 /* Date+Dispatch.swift in Sources */, - 6B2C4592C8E7AB637DCE61146471D15B /* Debounce.swift in Sources */, - AE9CD52D79B9E0598327F6ACA67ABAAB /* Debug.swift in Sources */, - D405FD3A5013F19096331DE1545F50CC /* DefaultIfEmpty.swift in Sources */, - CF8EE3746589F5FF68951DBDE74D8E46 /* Deferred.swift in Sources */, - B47CAD0C912E476435BD8CEEC991DE24 /* Delay.swift in Sources */, - 9BE1AF91C4974E1FBC4A679C4B913CA3 /* DelaySubscription.swift in Sources */, - 319CD48B3F0943B0194D7EBE836C3B2A /* Dematerialize.swift in Sources */, - 089D379A99B15CCB464114CCDC8A48A8 /* Deprecated.swift in Sources */, - 16BE28E8C4861D7097B857C480542D16 /* DispatchQueue+Extensions.swift in Sources */, - C5A36BD3A03ACBCEE7AA512E75543F8F /* DispatchQueueConfiguration.swift in Sources */, - 5204D71C84ED0C9D697D1E4AC98E1A8C /* Disposable.swift in Sources */, - 0BB5D87B0D3F6911A672D1D064B7EADB /* Disposables.swift in Sources */, - 33032AD86EECA3E0CCD0C6600B46B387 /* DisposeBag.swift in Sources */, - 7FC14CECCDDE62D4D7A2D79D8957B7CB /* DisposeBase.swift in Sources */, - E271A581E3E779A7E78C930D9FCC1BB3 /* DistinctUntilChanged.swift in Sources */, - 4E3E4CA7B9F25F6BA15964BB1C9BB3E6 /* Do.swift in Sources */, - 6BD8F6FA000B8377364F162C31A4B39A /* ElementAt.swift in Sources */, - CB7A8E096418E09BFC913E24D0AFB9E6 /* Empty.swift in Sources */, - 33085BE19BC4950FD825D377A0384853 /* Enumerated.swift in Sources */, - 9C195E01501DDF1FDAC8088D7B220A39 /* Error.swift in Sources */, - 1A0290651373E42FF136C54678A70388 /* Errors.swift in Sources */, - DF7BB16D5068614BEC61A6AE56676BCE /* Event.swift in Sources */, - BEB34BE206AA9228BAE5F057274C096D /* Filter.swift in Sources */, - 5A3E64F9BF446D6C7EB89D63C9AC8949 /* First.swift in Sources */, - 28B256513A58DB398A2E4BD2CE8EE2A5 /* Generate.swift in Sources */, - 07346B19736ECE7D9BA113A615C601D6 /* GroupBy.swift in Sources */, - C90141C33122A1AB176932C44BB8CE20 /* GroupedObservable.swift in Sources */, - F3FB4FF17D04C088A943E25CA2CE4C7D /* HistoricalScheduler.swift in Sources */, - A93533D0C501E2BF125596DB8C36694D /* HistoricalSchedulerTimeConverter.swift in Sources */, - 8E34035DE1B50E48C75EBC3D9EF04F33 /* ImmediateSchedulerType.swift in Sources */, - D40B9D5116DE9A970BE2AAC71D950B8A /* InfiniteSequence.swift in Sources */, - A52C7C7156120DBD02B56E8000856270 /* InvocableScheduledItem.swift in Sources */, - F36EF88B9429864E9ACC6CADC35ACFFF /* InvocableType.swift in Sources */, - 1A7F311C56CE2CEC64BFEA35C2DA89BE /* Just.swift in Sources */, - 2F9649BA714818478F47344BE7E08151 /* Lock.swift in Sources */, - 5B65B608F22EB08CAE74F9D57A935665 /* LockOwnerType.swift in Sources */, - 46AA3C4ACC3EF6ECAAA5F5196C9066BF /* MainScheduler.swift in Sources */, - 5D99DF3D1F09C9650797EF260152C57B /* Map.swift in Sources */, - FE38BA94F6CC36847692BD46088FD1E0 /* Materialize.swift in Sources */, - 93B06FCEA76AF6E623A9E5138ED58F0E /* Maybe.swift in Sources */, - 17AE39C327A90155996F848C3E08D8BA /* Merge.swift in Sources */, - 41919C08D2C90A4C12791CFC39D51822 /* Multicast.swift in Sources */, - 929F5D52DEAA8E60C42A17646768CD76 /* Never.swift in Sources */, - 564C61571AFF901B24065864742CD15C /* NopDisposable.swift in Sources */, - 62D16ED4F8A216D49CB3BE043A40C057 /* Observable.swift in Sources */, - 781E862E3936B81C76DE56A2B73D39DB /* ObservableConvertibleType.swift in Sources */, - 99CFA1A10B374DEB190C746C8FE56328 /* ObservableType+Extensions.swift in Sources */, - E2485824224974D4F01A4D528FBF54F8 /* ObservableType+PrimitiveSequence.swift in Sources */, - FD71C12495B3C977B34C695E29BE6487 /* ObservableType.swift in Sources */, - 918AD74EAED7D96246EB3B40FC9A0BFB /* ObserveOn.swift in Sources */, - E94C8A4AC49CBF79C160CDF1456F3268 /* ObserverBase.swift in Sources */, - DBC8CDB0774E509631269FFBAA2DAFD9 /* ObserverType.swift in Sources */, - F18D13A96958391F1302D458E5EDF2FA /* OperationQueueScheduler.swift in Sources */, - 3BB89BD0995B26D47EDA758A3F566746 /* Optional.swift in Sources */, - 33669FD8E09B5B4890F9C8679FDF4C8F /* Platform.Darwin.swift in Sources */, - 11DB4B048DFAA48121111E915D511F12 /* Platform.Linux.swift in Sources */, - 5ECA61563A0B1B4AF3DD8DB33CC5ECC6 /* PrimitiveSequence+Zip+arity.swift in Sources */, - C71B657F060B00AA92C2FEEC8DEDFDD0 /* PrimitiveSequence.swift in Sources */, - 3204DA02231F4CCBAA8C0B6EF0627B0A /* PriorityQueue.swift in Sources */, - A69020C6D8D54C6B9967150C4D12C2F0 /* Producer.swift in Sources */, - 5212A728A6EBC318867A0DB2604E2CE2 /* PublishSubject.swift in Sources */, - 02D1115606C8781D7F76BCE3033EEB9D /* Queue.swift in Sources */, - E8CA9D201CCD569771BBA7230B4CE86D /* Range.swift in Sources */, - C6FD0005BA0122FC924F9A47B3A8F940 /* Reactive.swift in Sources */, - B31EB36681E88930D309731509146D8F /* RecursiveLock.swift in Sources */, - 56637F5983C7E3981550490AFD946487 /* RecursiveScheduler.swift in Sources */, - 1921A4C797E065C3175C89C03085BC29 /* Reduce.swift in Sources */, - 44032D72CBEE71CD817F3DB89CD39322 /* RefCountDisposable.swift in Sources */, - 5A37C1F7A988064F018E4657DCB9FAF4 /* Repeat.swift in Sources */, - DE951C89A0E4204747920D821A8CA125 /* ReplaySubject.swift in Sources */, - 81D3402DE15865EF965E92F16753CC6D /* RetryWhen.swift in Sources */, - 8FFA1171418DCF41A10A00E3DDF91F4D /* Rx.swift in Sources */, - D2F8250DFD8BF901BBCA0E921AA0A7DF /* RxMutableBox.swift in Sources */, - D1B3D37592824BF1800AF3C0D8577928 /* RxSwift-dummy.m in Sources */, - 57AFC435A3F7C0F0BEB59D98A5BCE035 /* Sample.swift in Sources */, - F65B6B6DC462EA29784F3829E27F3786 /* Scan.swift in Sources */, - 4DE13CD610E6B445AA4104D6B3DCA668 /* ScheduledDisposable.swift in Sources */, - 9DB91E3234D98F8F474CA1B60A4009EE /* ScheduledItem.swift in Sources */, - A2FA5D4CF29A68D435767AF9C7144879 /* ScheduledItemType.swift in Sources */, - F03680E55059E367B51764AF73D78877 /* SchedulerServices+Emulation.swift in Sources */, - 538FA8C7CAE943F6CA9EDF5040FD1050 /* SchedulerType.swift in Sources */, - 33CAC57AD2FA7C6141056F36E955ECA7 /* Sequence.swift in Sources */, - 1AFA7FE153D916110AAE766EE1920588 /* SerialDispatchQueueScheduler.swift in Sources */, - 29D33B120FF9E542C526ECC4F8C18B32 /* SerialDisposable.swift in Sources */, - 99A91523EDA858260DE382471FCD2660 /* ShareReplayScope.swift in Sources */, - DC2BF73B8DE32079B2A5D3EEB325693C /* Single.swift in Sources */, - 680EFD397F3D67F1E6FBD665174A2E4C /* SingleAssignmentDisposable.swift in Sources */, - 37D85D67348816DADADB998A0343A510 /* SingleAsync.swift in Sources */, - 1171EDC4E196453CF248BBB703A105FC /* Sink.swift in Sources */, - 0BF392DCED5271A700BB662938E60583 /* Skip.swift in Sources */, - 1381BECD9CEAC751B1D9C4D25D13A25B /* SkipUntil.swift in Sources */, - 68EA7E9593CB7E82CFFA7FF9ABB8D2E4 /* SkipWhile.swift in Sources */, - 139CA98072F5DBA2277D37E5CF6B56D2 /* StartWith.swift in Sources */, - C4F1F53A9B315A233D2DE4E41BE36840 /* SubjectType.swift in Sources */, - 3E120058DF7459A49DD4E35FBE67D133 /* SubscribeOn.swift in Sources */, - 75ADC8C732AA9E7F4B01FD30C12E601E /* SubscriptionDisposable.swift in Sources */, - 5B76B6236E5E08CFAD97BEE71AD3E597 /* SwiftSupport.swift in Sources */, - FD13BDBEB267F9CB352C4898F0A9ADAF /* Switch.swift in Sources */, - C6C99FDE5205C027D87F915E19FF5298 /* SwitchIfEmpty.swift in Sources */, - 83A9D64190846F4F9018E9CF717B0048 /* SynchronizedDisposeType.swift in Sources */, - 21B0B6449882CCDCCD83C054AC5E2792 /* SynchronizedOnType.swift in Sources */, - 09FC4987B40193613404BC3AC42C84CC /* SynchronizedUnsubscribeType.swift in Sources */, - 7D6BE9FF8C03259DC209739719007DA5 /* TailRecursiveSink.swift in Sources */, - ED96AC28B148B137544A4B56181F2A8D /* Take.swift in Sources */, - 6E4891B53E07159C063567FA272AEEE0 /* TakeLast.swift in Sources */, - DAB7CDCB3C855AA0E80989B69201E957 /* TakeUntil.swift in Sources */, - 63CCB311DA2A1B434FB68157555BDE88 /* TakeWhile.swift in Sources */, - 164528FB725289ABED8C8DAC554C5FE5 /* Throttle.swift in Sources */, - CC084A6E3141CBE88D1B65E7FE890CEC /* Timeout.swift in Sources */, - 381D280F4516CFFC0BB451CE0C21A21F /* Timer.swift in Sources */, - 8EDBBA201C0BDB79134CE1EA5DA331A0 /* ToArray.swift in Sources */, - 9264DEB116B5AE0104CBF6D5963808D4 /* Using.swift in Sources */, - ED62834CA901D873E8499CCC8E004F99 /* VirtualTimeConverterType.swift in Sources */, - C1F50C3F1C11D610B8B15650CCD4CBDA /* VirtualTimeScheduler.swift in Sources */, - 0D09D765CA4AA853CC79DB9677D60DD3 /* Window.swift in Sources */, - AB6C5AFFE7748088FC9101D2A569B275 /* WithLatestFrom.swift in Sources */, - 53B97F15B060F2EAF36166B73575057B /* Zip+arity.swift in Sources */, - 0EEF619C2531D6CCFD15EA37C965F3A0 /* Zip+Collection.swift in Sources */, - 820FCC7B141683EE4A1709B30BE2DB31 /* Zip.swift in Sources */, + 6C1EAB2CC7E9E6E109B45355419D8960 /* Aliases.swift in Sources */, + 55D00154D47F4F10F15AF209AD0DF687 /* App.swift in Sources */, + 552F8ED0C209B54D73234389B1932AF6 /* BSON.swift in Sources */, + 5549FE5C6E943FCBC92F17C64766A6F2 /* Combine.swift in Sources */, + 0954FFE9B7C7DE29B6333DB198731A2F /* Decimal128.swift in Sources */, + 53BB3BDA11BACEF71112399E01E8FBFD /* EmbeddedObject.swift in Sources */, + BA34DCC8F9F4D3FE007D7D4B83646F2B /* Error.swift in Sources */, + C4CDBA56D41744888750D08124E04B9E /* LinkingObjects.swift in Sources */, + C097D309A6C5250C1932A9F8AA9EC5AA /* List.swift in Sources */, + 4007D6404DFD7B75ABC694A2C5169D54 /* Migration.swift in Sources */, + A13343AD34EAF3769BB9B1BD249687CB /* MongoClient.swift in Sources */, + 9AB126DB8D28FE4AB79405C7381E741F /* Object.swift in Sources */, + 5E3CDC31679301E98CA6E49DFA37CC63 /* ObjectId.swift in Sources */, + 7A4301A07887232A5D3C87FD2FE85CBA /* ObjectiveCSupport+BSON.swift in Sources */, + B607A65D5E7BE4266BF64B5DA40016CC /* ObjectiveCSupport+Sync.swift in Sources */, + 93864538C6745E5AEF7FDB0743305ADF /* ObjectiveCSupport.swift in Sources */, + 4FF9983736B6CADBBF88AA045F521356 /* ObjectSchema.swift in Sources */, + B2B69A6518DA17ACF150F815F7C2332C /* Optional.swift in Sources */, + 724492108AD175B06CD238654A682F3F /* Property.swift in Sources */, + 7E978945DB721518C002B6B1C4153EC1 /* Realm.swift in Sources */, + C36DA24C3370C592CB56A246D60D4FD9 /* RealmCollection.swift in Sources */, + 1510FD50EA8543B9CEA250B66CFF6D01 /* RealmConfiguration.swift in Sources */, + 8CC41E6981CFDE74C31F6BCA8365363C /* RealmSwift-dummy.m in Sources */, + B797F6D52FDB1E40D50FD6EBEA92BCEA /* Results.swift in Sources */, + 6E157DD0AEA68E24821522D8996E1050 /* Schema.swift in Sources */, + A9D470B9CF9F652DD29828BD75A5CFB2 /* SortDescriptor.swift in Sources */, + BC68C6F8F90A12E99320DDB0B48544CD /* SwiftVersion.swift in Sources */, + EB29A867ADAF5659E0C48E5C4D8A450A /* Sync.swift in Sources */, + 7372C0C23D5BA126DD35CB42A6B7975B /* ThreadSafeReference.swift in Sources */, + 6F6BF6CBBAFEEB5A51F6AB50D96D751F /* Util.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1841,71 +3096,172 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - E7F0ABE901E7FEB69EF99230B6061091 /* Sources */ = { + DBA57EC1D88CA688EE56BFB33208383C /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 6E78218B1AF9B5CE8E63F3B03F4ED902 /* BehaviorRelay.swift in Sources */, - 16BB39EAD21D4FF5A0D3E70AC1B18859 /* Observable+Bind.swift in Sources */, - 741276A465432A0E1E5D3A6DEC2C98C0 /* PublishRelay.swift in Sources */, - 89EB2B6FDB58411C933B9913B315BA05 /* RxRelay-dummy.m in Sources */, - 21B090D339DBFB4F7FD1BE9E80BE5E85 /* Utils.swift in Sources */, + 5B88D22C3A0626D6BA8351DEEDB36B02 /* Pods-Darner-dan-uh-dummy.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - 0F5182513A3C7082E91EC7F7C9649135 /* PBXTargetDependency */ = { + 138C19B508083C0E4A285F0B219EDD6D /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = RxRelay; + target = 4622BFEF3DC16E8BD15EEFC30D4D0084 /* RxRelay */; + targetProxy = 10E08D2D9480E949307AAED1C22C172D /* PBXContainerItemProxy */; + }; + 29C6EECD957E8525858FF7C600787888 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = RealmSwift; + target = 782725687624F8665247B84AB581BEB1 /* RealmSwift */; + targetProxy = D656BA3D22E65ED3E91BD14EA3C0CE93 /* PBXContainerItemProxy */; + }; + 3F1DD9B01E60086675D3BD1DC9A3743E /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = RxSwift; target = EA9EA43B3B503823EE36C60D9C8A865F /* RxSwift */; - targetProxy = D1377C6C3472BDAF4F1B0D7E86628961 /* PBXContainerItemProxy */; + targetProxy = 1860554BFE11E0F943E72F51F6001D91 /* PBXContainerItemProxy */; }; - 2354AA506346B4B353C6948422111A93 /* PBXTargetDependency */ = { + 4B7953DADFBFC8B12FAAF48C9D4E96C8 /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = RxSwift; target = EA9EA43B3B503823EE36C60D9C8A865F /* RxSwift */; - targetProxy = 0F29B0C278670D8504AE57CE51EDBEF2 /* PBXContainerItemProxy */; + targetProxy = 55E20394D134B6C22391AACE5AF71D79 /* PBXContainerItemProxy */; + }; + 4CEE07902C2AD32A295BA78A490E25C8 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Alamofire; + target = EAAA1AD3A8A1B59AB91319EE40752C6D /* Alamofire */; + targetProxy = 5EC2F6106AC9F6038CAF0BBA5729514B /* PBXContainerItemProxy */; }; - 2BA25FD1E5B051CD6B1632932DA2E49E /* PBXTargetDependency */ = { + 743D217C3A4E6C81C00E6247984A7A73 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Alamofire; + target = EAAA1AD3A8A1B59AB91319EE40752C6D /* Alamofire */; + targetProxy = 7D9D933408532C30D0AD861AA38D722A /* PBXContainerItemProxy */; + }; + 82B99BE3147B5798EA7325B546ED768B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Realm; + target = 68494F30B4A13F8E5E88BCCAEC25B0A4 /* Realm */; + targetProxy = F95C4147E772E613A5678E1753EC880D /* PBXContainerItemProxy */; + }; + 832652F97D9464A776DA6DB47A9DDA1F /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Realm; + target = 68494F30B4A13F8E5E88BCCAEC25B0A4 /* Realm */; + targetProxy = AB59AD30498E5E7F449A847BB4852D68 /* PBXContainerItemProxy */; + }; + A1364262261DAC0871EB98B6F07B0C1F /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = RxCocoa; target = 7AD0C6DCDC9CEC8A3C7C10C7FEE07BE6 /* RxCocoa */; - targetProxy = 5F944B86754F6074923728E863E11840 /* PBXContainerItemProxy */; + targetProxy = 37927C6512BF1AF789EE56F26221F00D /* PBXContainerItemProxy */; + }; + BF86C82170854AA5A7AFDD5D1B809D4D /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = RxRelay; + target = 4622BFEF3DC16E8BD15EEFC30D4D0084 /* RxRelay */; + targetProxy = E66902C7B3AE87F045AE703402362FBB /* PBXContainerItemProxy */; }; - 6818CF147DC7F544793A124E2876DE1F /* PBXTargetDependency */ = { + CD2C562089B256FDD5ADD654B9AC1142 /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = RxSwift; target = EA9EA43B3B503823EE36C60D9C8A865F /* RxSwift */; - targetProxy = E620670CEAC0FC8F38E8C50FAD755209 /* PBXContainerItemProxy */; + targetProxy = 07CCD94A97AF52489B095244FDBCCF6F /* PBXContainerItemProxy */; }; - 72FDBEDFD6D6E32E2CBCCDAA8F51F899 /* PBXTargetDependency */ = { + D18F8A2579759361D9046C3593BDD0B3 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - name = RxRelay; - target = 4622BFEF3DC16E8BD15EEFC30D4D0084 /* RxRelay */; - targetProxy = 2ACF9674D82BFF1D31495413FF50DD23 /* PBXContainerItemProxy */; + name = RxAlamofire; + target = 1A538A5499B1706F0983D6826042657B /* RxAlamofire */; + targetProxy = E37A364E9D6514056B0B960F4A08AA28 /* PBXContainerItemProxy */; }; - A0AC1167A7EDC58ED6C5738142E4B56F /* PBXTargetDependency */ = { + D5CA75F4974434FD13E3B0CB3AC3EC56 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - name = RxRelay; - target = 4622BFEF3DC16E8BD15EEFC30D4D0084 /* RxRelay */; - targetProxy = BA7FBAFE7939C99EF033DB4127174511 /* PBXContainerItemProxy */; + name = RxSwift; + target = EA9EA43B3B503823EE36C60D9C8A865F /* RxSwift */; + targetProxy = 6B62F56D7627ECEE34134CBFF73B04A5 /* PBXContainerItemProxy */; }; - F21487C14FDB0883D8A5B8F61D922F87 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - name = Alamofire; - target = EAAA1AD3A8A1B59AB91319EE40752C6D /* Alamofire */; - targetProxy = 9C8C0873E0DB0190AD72C7AB067FC73A /* PBXContainerItemProxy */; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 315A0654AD4BAAF6DDDAFDF2583632C0 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = DF1B0D9D0F144EA76A970202FBA81679 /* RxCocoa.release.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/RxCocoa/RxCocoa-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/RxCocoa/RxCocoa-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/RxCocoa/RxCocoa.modulemap"; + PRODUCT_MODULE_NAME = RxCocoa; + PRODUCT_NAME = RxCocoa; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 3A1AA0F21EA19F9B0A5E7D50E6AF8424 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = FA85CDF926CEB090AC0FA2E804C63579 /* RealmSwift.release.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/RealmSwift/RealmSwift-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/RealmSwift/RealmSwift-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/RealmSwift/RealmSwift.modulemap"; + PRODUCT_MODULE_NAME = RealmSwift; + PRODUCT_NAME = RealmSwift; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; }; -/* End PBXTargetDependency section */ - -/* Begin XCBuildConfiguration section */ - 0DCCFA5DB0CE09B42A0B2288D8B2B251 /* Debug */ = { + 3A8C33639B8B99435E922FE61CD84550 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = E1757F396E51EFEFA58511C903B926C7 /* RxRelay.debug.xcconfig */; + baseConfigurationReference = 2EA875143B8C27199FCF997B7DB5F566 /* RxRelay.release.xcconfig */; buildSettings = { - CODE_SIGN_IDENTITY = ""; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; @@ -1931,16 +3287,16 @@ SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; - name = Debug; + name = Release; }; - 0F4E5A2A93FF6401011FB1CB34EDAF2E /* Debug */ = { + 49F88EE901656647FA9448BC3DD55E2A /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 1DC46D98E3D4A6854B4D3ACD807CDFE2 /* RxSwift.debug.xcconfig */; + baseConfigurationReference = E617414E007DAF8549B6F6E1177385B7 /* RxSwift.debug.xcconfig */; buildSettings = { - CODE_SIGN_IDENTITY = ""; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; @@ -1971,11 +3327,12 @@ }; name = Debug; }; - 11DB2A5008120A2BBED5C686B7E2C05D /* Release */ = { + 559E919602F2E4938AF8E95F3A5B6318 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = D2DBFDFBE48A0BFE84CDF28D07A087E4 /* RxCocoa.release.xcconfig */; + baseConfigurationReference = C1DCC7F7F58397F1C7D7D137C608195F /* Pods-Darner-dan-uh.debug.xcconfig */; buildSettings = { - CODE_SIGN_IDENTITY = ""; + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + CLANG_ENABLE_OBJC_WEAK = NO; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; @@ -1984,8 +3341,79 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - GCC_PREFIX_HEADER = "Target Support Files/RxCocoa/RxCocoa-prefix.pch"; - INFOPLIST_FILE = "Target Support Files/RxCocoa/RxCocoa-Info.plist"; + INFOPLIST_FILE = "Target Support Files/Pods-Darner-dan-uh/Pods-Darner-dan-uh-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 13.6; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-Darner-dan-uh/Pods-Darner-dan-uh.modulemap"; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 7101DF73002884A4420BCE424118A070 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 5E7AC000EA49E075669EE248F2B7E05D /* RxAlamofire.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/RxAlamofire/RxAlamofire-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/RxAlamofire/RxAlamofire-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/RxAlamofire/RxAlamofire.modulemap"; + PRODUCT_MODULE_NAME = RxAlamofire; + PRODUCT_NAME = RxAlamofire; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.1; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 772BB9FC5B888A68080DC3CC6A9E4D3E /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 1BBAA07630A36165CB5BFE215FF727E2 /* RxSwift.release.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/RxSwift/RxSwift-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/RxSwift/RxSwift-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = ( @@ -1993,9 +3421,9 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MODULEMAP_FILE = "Target Support Files/RxCocoa/RxCocoa.modulemap"; - PRODUCT_MODULE_NAME = RxCocoa; - PRODUCT_NAME = RxCocoa; + MODULEMAP_FILE = "Target Support Files/RxSwift/RxSwift.modulemap"; + PRODUCT_MODULE_NAME = RxSwift; + PRODUCT_NAME = RxSwift; SDKROOT = iphoneos; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; @@ -2007,10 +3435,80 @@ }; name = Release; }; - 13967C5C8F4B10B3EE4D6C208A0A7BEB /* Debug */ = { + 781FFFFDD8FDD3CB7191318133BC46DB /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = AC6A4C73F2B6D7B0FE5FC3A55E9945AF /* RealmSwift.debug.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/RealmSwift/RealmSwift-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/RealmSwift/RealmSwift-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/RealmSwift/RealmSwift.modulemap"; + PRODUCT_MODULE_NAME = RealmSwift; + PRODUCT_NAME = RealmSwift; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 7E81E76DAAE2CE8F82E7232E12AD4A12 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3A40B0E7398EBDFA5BB36A1A3D484D15 /* Alamofire.debug.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/Alamofire/Alamofire-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/Alamofire/Alamofire-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/Alamofire/Alamofire.modulemap"; + PRODUCT_MODULE_NAME = Alamofire; + PRODUCT_NAME = Alamofire; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.2; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 95607A856795A398FFB76177B56DE3A8 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -2033,6 +3531,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -2071,13 +3570,10 @@ }; name = Debug; }; - 3B631A44C741505677C03006EAD8405F /* Debug */ = { + 9C9F39EE7D5E3DEF337E895581E6A2FC /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = C1DCC7F7F58397F1C7D7D137C608195F /* Pods-Darner-dan-uh.debug.xcconfig */; + baseConfigurationReference = D94963727939C0F7D500399F2C8178BD /* Realm.debug.xcconfig */; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; - CLANG_ENABLE_OBJC_WEAK = NO; - CODE_SIGN_IDENTITY = ""; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; @@ -2086,35 +3582,33 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = "Target Support Files/Pods-Darner-dan-uh/Pods-Darner-dan-uh-Info.plist"; + GCC_PREFIX_HEADER = "Target Support Files/Realm/Realm-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/Realm/Realm-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 13.6; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MACH_O_TYPE = staticlib; - MODULEMAP_FILE = "Target Support Files/Pods-Darner-dan-uh/Pods-Darner-dan-uh.modulemap"; - OTHER_LDFLAGS = ""; - OTHER_LIBTOOLFLAGS = ""; - PODS_ROOT = "$(SRCROOT)"; - PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + MODULEMAP_FILE = "Target Support Files/Realm/Realm.modulemap"; + PRODUCT_MODULE_NAME = Realm; + PRODUCT_NAME = Realm; SDKROOT = iphoneos; SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; name = Debug; }; - 48FD2B4E815CEB933B18D313E9E9EF64 /* Release */ = { + BCAC530778CAA37BE0A5504108660645 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 66D915A4C32A6B2AE8EA8CDD952CCF81 /* Alamofire.release.xcconfig */; + baseConfigurationReference = 4C01E6FADE447436D88928C88EC55978 /* Alamofire.release.xcconfig */; buildSettings = { CLANG_ENABLE_OBJC_WEAK = NO; - CODE_SIGN_IDENTITY = ""; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; @@ -2146,47 +3640,10 @@ }; name = Release; }; - 516D8256E55FBCCC4E57CFD2051D396C /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 82CF61945D38FCF90C8205EF6C6049E6 /* RxSwift.release.xcconfig */; - buildSettings = { - CODE_SIGN_IDENTITY = ""; - "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - GCC_PREFIX_HEADER = "Target Support Files/RxSwift/RxSwift-prefix.pch"; - INFOPLIST_FILE = "Target Support Files/RxSwift/RxSwift-Info.plist"; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MODULEMAP_FILE = "Target Support Files/RxSwift/RxSwift.modulemap"; - PRODUCT_MODULE_NAME = RxSwift; - PRODUCT_NAME = RxSwift; - SDKROOT = iphoneos; - SKIP_INSTALL = YES; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; - 7DFF30BE30C7C6620E674C2C1A444D51 /* Release */ = { + CFA6460787C823A15A5DD30F0313DE8B /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = ADB12FD54E0F26373ED16E17F0940E6A /* RxRelay.release.xcconfig */; + baseConfigurationReference = 7B5BFEC05FC481CB99545BF0DB1DB91F /* Realm.release.xcconfig */; buildSettings = { - CODE_SIGN_IDENTITY = ""; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; @@ -2195,18 +3652,18 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - GCC_PREFIX_HEADER = "Target Support Files/RxRelay/RxRelay-prefix.pch"; - INFOPLIST_FILE = "Target Support Files/RxRelay/RxRelay-Info.plist"; + GCC_PREFIX_HEADER = "Target Support Files/Realm/Realm-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/Realm/Realm-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MODULEMAP_FILE = "Target Support Files/RxRelay/RxRelay.modulemap"; - PRODUCT_MODULE_NAME = RxRelay; - PRODUCT_NAME = RxRelay; + MODULEMAP_FILE = "Target Support Files/Realm/Realm.modulemap"; + PRODUCT_MODULE_NAME = Realm; + PRODUCT_NAME = Realm; SDKROOT = iphoneos; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; @@ -2218,10 +3675,11 @@ }; name = Release; }; - 871B6E28ABA34DAE69824AB9D22D3B7D /* Release */ = { + D6EECBCE91072E1A06BA3BD2D8E3C244 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -2244,6 +3702,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -2278,13 +3737,12 @@ }; name = Release; }; - B7A3FEAD11503C4AE9F29E7422133D03 /* Release */ = { + DF6C5E787D70A122619567EAADE0BF1A /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = BB22D2AF0D6F32A250C45EC2E571E494 /* Pods-Darner-dan-uh.release.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; CLANG_ENABLE_OBJC_WEAK = NO; - CODE_SIGN_IDENTITY = ""; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; @@ -2317,12 +3775,45 @@ }; name = Release; }; - E73BFB7433831CF292FADF6B2CB7AC3B /* Debug */ = { + F2C062E20257EFFF639D7FDEDDD5269F /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = F5BDCEE005C5A46BC2C40BA42571EC23 /* RxRelay.debug.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/RxRelay/RxRelay-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/RxRelay/RxRelay-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/RxRelay/RxRelay.modulemap"; + PRODUCT_MODULE_NAME = RxRelay; + PRODUCT_NAME = RxRelay; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + FCC82103B38C9632151E8D82E76112CC /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 2E187C471E348C73FE75C9A27421B443 /* Alamofire.debug.xcconfig */; + baseConfigurationReference = 339AE1A23AF8CB3EC9886CBBF610FEA6 /* RxAlamofire.debug.xcconfig */; buildSettings = { CLANG_ENABLE_OBJC_WEAK = NO; - CODE_SIGN_IDENTITY = ""; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; @@ -2331,8 +3822,8 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - GCC_PREFIX_HEADER = "Target Support Files/Alamofire/Alamofire-prefix.pch"; - INFOPLIST_FILE = "Target Support Files/Alamofire/Alamofire-Info.plist"; + GCC_PREFIX_HEADER = "Target Support Files/RxAlamofire/RxAlamofire-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/RxAlamofire/RxAlamofire-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 10.0; LD_RUNPATH_SEARCH_PATHS = ( @@ -2340,24 +3831,23 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MODULEMAP_FILE = "Target Support Files/Alamofire/Alamofire.modulemap"; - PRODUCT_MODULE_NAME = Alamofire; - PRODUCT_NAME = Alamofire; + MODULEMAP_FILE = "Target Support Files/RxAlamofire/RxAlamofire.modulemap"; + PRODUCT_MODULE_NAME = RxAlamofire; + PRODUCT_NAME = RxAlamofire; SDKROOT = iphoneos; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; - SWIFT_VERSION = 5.2; + SWIFT_VERSION = 5.1; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; name = Debug; }; - EC4C580659E08318BD7F02F5159C2BC2 /* Debug */ = { + FD1ACB73CF57D061218FD6389B04BEB1 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = B50080BBC3721DEBF83123B05531A6FE /* RxCocoa.debug.xcconfig */; + baseConfigurationReference = D256F37F99E6AAC79FEEE9508D19F476 /* RxCocoa.debug.xcconfig */; buildSettings = { - CODE_SIGN_IDENTITY = ""; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; @@ -2391,11 +3881,38 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 16D5AB567A9830B83428934DBAACEED4 /* Build configuration list for PBXNativeTarget "Realm" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 9C9F39EE7D5E3DEF337E895581E6A2FC /* Debug */, + CFA6460787C823A15A5DD30F0313DE8B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 19D83A142A5FC0D4D92A907CE6941B75 /* Build configuration list for PBXNativeTarget "RxAlamofire" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FCC82103B38C9632151E8D82E76112CC /* Debug */, + 7101DF73002884A4420BCE424118A070 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 2D0C38C2045BD02E6E1A280EF6CF131C /* Build configuration list for PBXNativeTarget "RealmSwift" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 781FFFFDD8FDD3CB7191318133BC46DB /* Debug */, + 3A1AA0F21EA19F9B0A5E7D50E6AF8424 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */ = { isa = XCConfigurationList; buildConfigurations = ( - 13967C5C8F4B10B3EE4D6C208A0A7BEB /* Debug */, - 871B6E28ABA34DAE69824AB9D22D3B7D /* Release */, + 95607A856795A398FFB76177B56DE3A8 /* Debug */, + D6EECBCE91072E1A06BA3BD2D8E3C244 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; @@ -2403,44 +3920,44 @@ 78E219AC01CD5AFED663C9AB28280801 /* Build configuration list for PBXNativeTarget "Alamofire" */ = { isa = XCConfigurationList; buildConfigurations = ( - E73BFB7433831CF292FADF6B2CB7AC3B /* Debug */, - 48FD2B4E815CEB933B18D313E9E9EF64 /* Release */, + 7E81E76DAAE2CE8F82E7232E12AD4A12 /* Debug */, + BCAC530778CAA37BE0A5504108660645 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 9B2D8D68CCB5B267F38915E244F92A0C /* Build configuration list for PBXNativeTarget "RxSwift" */ = { + 9DC209E81355211B7B9357CBE2268AFF /* Build configuration list for PBXNativeTarget "RxSwift" */ = { isa = XCConfigurationList; buildConfigurations = ( - 0F4E5A2A93FF6401011FB1CB34EDAF2E /* Debug */, - 516D8256E55FBCCC4E57CFD2051D396C /* Release */, + 49F88EE901656647FA9448BC3DD55E2A /* Debug */, + 772BB9FC5B888A68080DC3CC6A9E4D3E /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - F36470E19CC9B4BDA4369A4776800DE7 /* Build configuration list for PBXNativeTarget "Pods-Darner-dan-uh" */ = { + 9E36B4B9D2DB067E7BD7966187B475EA /* Build configuration list for PBXNativeTarget "Pods-Darner-dan-uh" */ = { isa = XCConfigurationList; buildConfigurations = ( - 3B631A44C741505677C03006EAD8405F /* Debug */, - B7A3FEAD11503C4AE9F29E7422133D03 /* Release */, + 559E919602F2E4938AF8E95F3A5B6318 /* Debug */, + DF6C5E787D70A122619567EAADE0BF1A /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - F7028E084333DB57BEE3106A0E5C0DFB /* Build configuration list for PBXNativeTarget "RxCocoa" */ = { + EF6456B7AF7EA9AF5F5E54E9EC597DA1 /* Build configuration list for PBXNativeTarget "RxRelay" */ = { isa = XCConfigurationList; buildConfigurations = ( - EC4C580659E08318BD7F02F5159C2BC2 /* Debug */, - 11DB2A5008120A2BBED5C686B7E2C05D /* Release */, + F2C062E20257EFFF639D7FDEDDD5269F /* Debug */, + 3A8C33639B8B99435E922FE61CD84550 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - F71283EE81D71731FDAEB843FC5D0009 /* Build configuration list for PBXNativeTarget "RxRelay" */ = { + F7028E084333DB57BEE3106A0E5C0DFB /* Build configuration list for PBXNativeTarget "RxCocoa" */ = { isa = XCConfigurationList; buildConfigurations = ( - 0DCCFA5DB0CE09B42A0B2288D8B2B251 /* Debug */, - 7DFF30BE30C7C6620E674C2C1A444D51 /* Release */, + FD1ACB73CF57D061218FD6389B04BEB1 /* Debug */, + 315A0654AD4BAAF6DDDAFDF2583632C0 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; diff --git a/Darner-dan-uh/Pods/Pods.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Darner-dan-uh/Pods/Pods.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..94b2795 --- /dev/null +++ b/Darner-dan-uh/Pods/Pods.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,4 @@ + + + diff --git a/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/ihyun_wook.xcuserdatad/xcschemes/Pods-Darner-dan-uh.xcscheme b/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/ihyun_wook.xcuserdatad/xcschemes/Pods-Darner-dan-uh.xcscheme index 2135365..d35631a 100644 --- a/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/ihyun_wook.xcuserdatad/xcschemes/Pods-Darner-dan-uh.xcscheme +++ b/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/ihyun_wook.xcuserdatad/xcschemes/Pods-Darner-dan-uh.xcscheme @@ -7,15 +7,15 @@ buildImplicitDependencies = "YES"> + buildForArchiving = "YES" + buildForAnalyzing = "YES"> @@ -23,14 +23,15 @@ - - + shouldUseLaunchSchemeArgsEnv = "YES"> + + - - + debugDocumentVersioning = "YES"> diff --git a/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/ihyun_wook.xcuserdatad/xcschemes/Realm.xcscheme b/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/ihyun_wook.xcuserdatad/xcschemes/Realm.xcscheme new file mode 100644 index 0000000..a7415c6 --- /dev/null +++ b/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/ihyun_wook.xcuserdatad/xcschemes/Realm.xcscheme @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/ihyun_wook.xcuserdatad/xcschemes/RealmSwift.xcscheme b/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/ihyun_wook.xcuserdatad/xcschemes/RealmSwift.xcscheme new file mode 100644 index 0000000..d7291ca --- /dev/null +++ b/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/ihyun_wook.xcuserdatad/xcschemes/RealmSwift.xcscheme @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/ihyun_wook.xcuserdatad/xcschemes/RxAlamofire.xcscheme b/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/ihyun_wook.xcuserdatad/xcschemes/RxAlamofire.xcscheme new file mode 100644 index 0000000..b107c45 --- /dev/null +++ b/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/ihyun_wook.xcuserdatad/xcschemes/RxAlamofire.xcscheme @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/ihyun_wook.xcuserdatad/xcschemes/xcschememanagement.plist b/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/ihyun_wook.xcuserdatad/xcschemes/xcschememanagement.plist index 93bb3f3..1e29baa 100644 --- a/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/ihyun_wook.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/ihyun_wook.xcuserdatad/xcschemes/xcschememanagement.plist @@ -8,26 +8,62 @@ isShown + orderHint + 0 + + Darner-dan-uh.xcscheme_^#shared#^_ + + orderHint + 8 Pods-Darner-dan-uh.xcscheme isShown + orderHint + 1 + + Realm.xcscheme + + isShown + + orderHint + 5 + + RealmSwift.xcscheme + + isShown + + orderHint + 6 + + RxAlamofire.xcscheme + + isShown + + orderHint + 7 RxCocoa.xcscheme isShown + orderHint + 2 RxRelay.xcscheme isShown + orderHint + 3 RxSwift.xcscheme isShown + orderHint + 4 SuppressBuildableAutocreation diff --git a/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/munjisu.xcuserdatad/xcschemes/Alamofire.xcscheme b/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/munjisu.xcuserdatad/xcschemes/Alamofire.xcscheme new file mode 100644 index 0000000..bc06c13 --- /dev/null +++ b/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/munjisu.xcuserdatad/xcschemes/Alamofire.xcscheme @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/munjisu.xcuserdatad/xcschemes/Pods-Darner-dan-uh.xcscheme b/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/munjisu.xcuserdatad/xcschemes/Pods-Darner-dan-uh.xcscheme new file mode 100644 index 0000000..d35631a --- /dev/null +++ b/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/munjisu.xcuserdatad/xcschemes/Pods-Darner-dan-uh.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/munjisu.xcuserdatad/xcschemes/Realm.xcscheme b/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/munjisu.xcuserdatad/xcschemes/Realm.xcscheme new file mode 100644 index 0000000..a7415c6 --- /dev/null +++ b/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/munjisu.xcuserdatad/xcschemes/Realm.xcscheme @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/munjisu.xcuserdatad/xcschemes/RealmSwift.xcscheme b/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/munjisu.xcuserdatad/xcschemes/RealmSwift.xcscheme new file mode 100644 index 0000000..d7291ca --- /dev/null +++ b/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/munjisu.xcuserdatad/xcschemes/RealmSwift.xcscheme @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/munjisu.xcuserdatad/xcschemes/RxAlamofire.xcscheme b/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/munjisu.xcuserdatad/xcschemes/RxAlamofire.xcscheme new file mode 100644 index 0000000..b107c45 --- /dev/null +++ b/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/munjisu.xcuserdatad/xcschemes/RxAlamofire.xcscheme @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/munjisu.xcuserdatad/xcschemes/RxAnimated.xcscheme b/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/munjisu.xcuserdatad/xcschemes/RxAnimated.xcscheme new file mode 100644 index 0000000..12ba91b --- /dev/null +++ b/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/munjisu.xcuserdatad/xcschemes/RxAnimated.xcscheme @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/munjisu.xcuserdatad/xcschemes/RxCocoa.xcscheme b/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/munjisu.xcuserdatad/xcschemes/RxCocoa.xcscheme new file mode 100644 index 0000000..78c8608 --- /dev/null +++ b/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/munjisu.xcuserdatad/xcschemes/RxCocoa.xcscheme @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/munjisu.xcuserdatad/xcschemes/RxRelay.xcscheme b/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/munjisu.xcuserdatad/xcschemes/RxRelay.xcscheme new file mode 100644 index 0000000..ea5245b --- /dev/null +++ b/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/munjisu.xcuserdatad/xcschemes/RxRelay.xcscheme @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/munjisu.xcuserdatad/xcschemes/RxSwift.xcscheme b/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/munjisu.xcuserdatad/xcschemes/RxSwift.xcscheme new file mode 100644 index 0000000..7b649f0 --- /dev/null +++ b/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/munjisu.xcuserdatad/xcschemes/RxSwift.xcscheme @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/munjisu.xcuserdatad/xcschemes/xcschememanagement.plist b/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/munjisu.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..6d37077 --- /dev/null +++ b/Darner-dan-uh/Pods/Pods.xcodeproj/xcuserdata/munjisu.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,34 @@ + + + + + SchemeUserState + + Alamofire.xcscheme_^#shared#^_ + + orderHint + 0 + + Pods-Darner-dan-uh.xcscheme_^#shared#^_ + + orderHint + 5 + + RxCocoa.xcscheme_^#shared#^_ + + orderHint + 2 + + RxRelay.xcscheme_^#shared#^_ + + orderHint + 4 + + RxSwift.xcscheme_^#shared#^_ + + orderHint + 3 + + + + diff --git a/Darner-dan-uh/Pods/Realm/LICENSE b/Darner-dan-uh/Pods/Realm/LICENSE new file mode 100644 index 0000000..57a0e0b --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/LICENSE @@ -0,0 +1,248 @@ +TABLE OF CONTENTS + +1. Apache License version 2.0 +2. Realm Components +3. Export Compliance + +1. ------------------------------------------------------------------------------- + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +2. ------------------------------------------------------------------------------- + +REALM COMPONENTS + +This software contains components with separate copyright and license terms. +Your use of these components is subject to the terms and conditions of the +following licenses. + +For the Realm Platform Extensions component + + Realm Platform Extensions License + + Copyright (c) 2011-2017 Realm Inc All rights reserved + + Redistribution and use in binary form, with or without modification, is + permitted provided that the following conditions are met: + + 1. You agree not to attempt to decompile, disassemble, reverse engineer or + otherwise discover the source code from which the binary code was derived. + You may, however, access and obtain a separate license for most of the + source code from which this Software was created, at + http://realm.io/pricing/. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +3. ------------------------------------------------------------------------------- + +EXPORT COMPLIANCE + +You understand that the Software may contain cryptographic functions that may be +subject to export restrictions, and you represent and warrant that you are not +(i) located in a jurisdiction that is subject to United States economic +sanctions (“Prohibited Jurisdiction”), including Cuba, Iran, North Korea, +Sudan, Syria or the Crimea region, (ii) a person listed on any U.S. government +blacklist (to include the List of Specially Designated Nationals and Blocked +Persons or the Consolidated Sanctions List administered by the U.S. Department +of the Treasury’s Office of Foreign Assets Control, or the Denied Persons List +or Entity List administered by the U.S. Department of Commerce) +(“Sanctioned Person”), or (iii) controlled or 50% or more owned by a Sanctioned +Person. + +You agree to comply with all export, re-export and import restrictions and +regulations of the U.S. Department of Commerce or other agency or authority of +the United States or other applicable countries. You also agree not to transfer, +or authorize the transfer of, directly or indirectly, of the Software to any +Prohibited Jurisdiction, or otherwise in violation of any such restrictions or +regulations. diff --git a/Darner-dan-uh/Pods/Realm/README.md b/Darner-dan-uh/Pods/Realm/README.md new file mode 100644 index 0000000..8b84d5d --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/README.md @@ -0,0 +1,73 @@ +![Realm](https://github.com/realm/realm-cocoa/raw/master/logo.png) + +Realm is a mobile database that runs directly inside phones, tablets or wearables. +This repository holds the source code for the iOS, macOS, tvOS & watchOS versions of Realm Swift & Realm Objective-C. + +## Features + +* **Mobile-first:** Realm is the first database built from the ground up to run directly inside phones, tablets and wearables. +* **Simple:** Data is directly [exposed as objects](https://realm.io/docs/objc/latest/#models) and [queryable by code](https://realm.io/docs/objc/latest/#queries), removing the need for ORM's riddled with performance & maintenance issues. Most of our users pick it up intuitively, getting simple apps up & running in minutes. +* **Modern:** Realm supports relationships, generics, vectorization and Swift. +* **Fast:** Realm is faster than even raw SQLite on common operations, while maintaining an extremely rich feature set. + +## Getting Started + +Please see the detailed instructions in our docs to add [Realm Objective-C](https://realm.io/docs/objc/latest/#installation) _or_ [Realm Swift](https://realm.io/docs/swift/latest/#installation) to your Xcode project. + +## Documentation + +### Realm Objective-C + +The documentation can be found at [realm.io/docs/objc/latest](https://realm.io/docs/objc/latest). +The API reference is located at [realm.io/docs/objc/latest/api/](https://realm.io/docs/objc/latest/api/). + +### Realm Swift + +The documentation can be found at [realm.io/docs/swift/latest](https://realm.io/docs/swift/latest). +The API reference is located at [realm.io/docs/swift/latest/api/](https://realm.io/docs/swift/latest/api/). + +## Getting Help + +- **Need help with your code?**: Look for previous questions with the[`realm` tag](https://stackoverflow.com/questions/tagged/realm?sort=newest) on Stack Overflow or [ask a new question](https://stackoverflow.com/questions/ask?tags=realm). For general discussion that might be considered too broad for Stack Overflow, use the [Community Forum](https://developer.mongodb.com/community/forums/tags/c/realm/9/realm-sdk). +- **Have a bug to report?** [Open a GitHub issue](https://github.com/realm/realm-cocoa/issues/new). If possible, include the version of Realm, a full log, the Realm file, and a project that shows the issue. +- **Have a feature request?** [Open a GitHub issue](https://github.com/realm/realm-cocoa/issues/new). Tell us what the feature should do and why you want the feature. + +## Building Realm + +In case you don't want to use the precompiled version, you can build Realm yourself from source. + +Prerequisites: + +* Building Realm requires Xcode 11.x or newer. +* If cloning from git, submodules are required: `git submodule update --init --recursive`. +* Building Realm documentation requires [jazzy](https://github.com/realm/jazzy) + +Once you have all the necessary prerequisites, building Realm.framework just takes a single command: `sh build.sh build`. You'll need an internet connection the first time you build Realm to download the core binary. + +Run `sh build.sh help` to see all the actions you can perform (build ios/osx, generate docs, test, etc.). + +## Contributing + +See [CONTRIBUTING.md](CONTRIBUTING.md) for more details! + +This project adheres to the [Contributor Covenant Code of Conduct](https://realm.io/conduct). +By participating, you are expected to uphold this code. Please report +unacceptable behavior to [info@realm.io](mailto:info@realm.io). + +## License + +Realm Objective-C & Realm Swift are published under the Apache 2.0 license. +Realm Core is also published under the Apache 2.0 license and is available +[here](https://github.com/realm/realm-core). + +**This product is not being made available to any person located in Cuba, Iran, +North Korea, Sudan, Syria or the Crimea region, or to any other person that is +not eligible to receive the product under U.S. law.** + +## Feedback + +**_If you use Realm and are happy with it, all we ask is that you please consider sending out a tweet mentioning [@realm](https://twitter.com/realm) to share your thoughts!_** + +**_And if you don't like it, please let us know what you would like improved, so we can fix it!_** + +![analytics](https://ga-beacon.appspot.com/UA-50247013-2/realm-cocoa/README?pixel) diff --git a/Darner-dan-uh/Pods/Realm/Realm/NSError+RLMSync.m b/Darner-dan-uh/Pods/Realm/Realm/NSError+RLMSync.m new file mode 100644 index 0000000..e8c2590 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/NSError+RLMSync.m @@ -0,0 +1,43 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2017 Realm Inc. +// +// 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 "NSError+RLMSync.h" + +#import "RLMSyncUtil.h" + +@implementation NSError (RLMSync) + +- (RLMSyncErrorActionToken *)rlmSync_errorActionToken { + if (self.domain != RLMSyncErrorDomain) { + return nil; + } + if (self.code == RLMSyncErrorClientResetError + || self.code == RLMSyncErrorPermissionDeniedError) { + return (RLMSyncErrorActionToken *)self.userInfo[kRLMSyncErrorActionTokenKey]; + } + return nil; +} + +- (NSString *)rlmSync_clientResetBackedUpRealmPath { + if (self.domain == RLMSyncErrorDomain && self.code == RLMSyncErrorClientResetError) { + return self.userInfo[kRLMSyncPathOfRealmBackupCopyKey]; + } + return nil; +} + +@end diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/binding_callback_thread_observer.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/binding_callback_thread_observer.cpp new file mode 100644 index 0000000..0c388d0 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/binding_callback_thread_observer.cpp @@ -0,0 +1,23 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2017 Realm Inc. +// +// 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 "binding_callback_thread_observer.hpp" + +namespace realm { +BindingCallbackThreadObserver* g_binding_callback_thread_observer = nullptr; +} diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/collection_notifications.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/collection_notifications.cpp new file mode 100644 index 0000000..03fad73 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/collection_notifications.cpp @@ -0,0 +1,61 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// 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 "collection_notifications.hpp" + +#include "impl/collection_notifier.hpp" + +using namespace realm; +using namespace realm::_impl; + +NotificationToken::NotificationToken(std::shared_ptr<_impl::CollectionNotifier> notifier, uint64_t token) +: m_notifier(std::move(notifier)), m_token(token) +{ +} + +NotificationToken::~NotificationToken() +{ + // m_notifier itself (and not just the pointed-to thing) needs to be accessed + // atomically to ensure that there are no data races when the token is + // destroyed after being modified on a different thread. + // This is needed despite the token not being thread-safe in general as + // users find it very surprising for obj-c objects to care about what + // thread they are deallocated on. + if (auto notifier = m_notifier.exchange({})) { + notifier->remove_callback(m_token); + } +} + +NotificationToken::NotificationToken(NotificationToken&&) = default; + +NotificationToken& NotificationToken::operator=(realm::NotificationToken&& rgt) +{ + if (this != &rgt) { + if (auto notifier = m_notifier.exchange({})) { + notifier->remove_callback(m_token); + } + m_notifier = std::move(rgt.m_notifier); + m_token = rgt.m_token; + } + return *this; +} + +void NotificationToken::suppress_next() +{ + m_notifier.load()->suppress_next_notification(m_token); +} diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/impl/apple/external_commit_helper.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/impl/apple/external_commit_helper.cpp new file mode 100644 index 0000000..1c4dab0 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/impl/apple/external_commit_helper.cpp @@ -0,0 +1,243 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// 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 "impl/external_commit_helper.hpp" +#include "impl/realm_coordinator.hpp" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace realm; +using namespace realm::_impl; + +namespace { +// Write a byte to a pipe to notify anyone waiting for data on the pipe +void notify_fd(int fd, int read_fd) +{ + while (true) { + char c = 0; + ssize_t ret = write(fd, &c, 1); + if (ret == 1) { + break; + } + + // If the pipe's buffer is full, we need to read some of the old data in + // it to make space. We don't just read in the code waiting for + // notifications so that we can notify multiple waiters with a single + // write. + assert(ret == -1 && errno == EAGAIN); + char buff[1024]; + read(read_fd, buff, sizeof buff); + } +} + +} // anonymous namespace + +void ExternalCommitHelper::FdHolder::close() +{ + if (m_fd != -1) { + ::close(m_fd); + } + m_fd = -1; +} + +// Inter-thread and inter-process notifications of changes are done using a +// named pipe in the filesystem next to the Realm file. Everyone who wants to be +// notified of commits waits for data to become available on the pipe, and anyone +// who commits a write transaction writes data to the pipe after releasing the +// write lock. Note that no one ever actually *reads* from the pipe: the data +// actually written is meaningless, and trying to read from a pipe from multiple +// processes at once is fraught with race conditions. + +// When a RLMRealm instance is created, we add a CFRunLoopSource to the current +// thread's runloop. On each cycle of the run loop, the run loop checks each of +// its sources for work to do, which in the case of CFRunLoopSource is just +// checking if CFRunLoopSourceSignal has been called since the last time it ran, +// and if so invokes the function pointer supplied when the source is created, +// which in our case just invokes `[realm handleExternalChange]`. + +// Listening for external changes is done using kqueue() on a background thread. +// kqueue() lets us efficiently wait until the amount of data which can be read +// from one or more file descriptors has changed, and tells us which of the file +// descriptors it was that changed. We use this to wait on both the shared named +// pipe, and a local anonymous pipe. When data is written to the named pipe, we +// signal the runloop source and wake up the target runloop, and when data is +// written to the anonymous pipe the background thread removes the runloop +// source from the runloop and and shuts down. +ExternalCommitHelper::ExternalCommitHelper(RealmCoordinator& parent) +: m_parent(parent) +{ + m_kq = kqueue(); + if (m_kq == -1) { + throw std::system_error(errno, std::system_category()); + } + +#if !TARGET_OS_TV + + + // Object Store needs to create a named pipe in order to coordinate notifications. + // This can be a problem on some file systems (e.g. FAT32) or due to security policies in SELinux. Most commonly + // it is a problem when saving Realms on external storage: https://stackoverflow.com/questions/2740321/how-to-create-named-pipe-mkfifo-in-android + // + // For this reason we attempt to create this file in a temporary location known to be safe to write these files. + // + // In order of priority we attempt to write the file in the following locations: + // 1) Next to the Realm file itself + // 2) A location defined by `Realm::Config::fifo_files_fallback_path` + // 3) A location defined by `DBOptions::set_sys_tmp_dir()` + // + // Core has a similar policy for its named pipes. + // + // Also see https://github.com/realm/realm-java/issues/3140 + // Note that hash collisions are okay here because they just result in doing extra work instead of resulting + // in correctness problems. + + std::string path; + std::string temp_dir = util::normalize_dir(parent.get_config().fifo_files_fallback_path); + std::string sys_temp_dir = util::normalize_dir(DBOptions::get_sys_tmp_dir()); + + path = parent.get_path() + ".note"; + bool fifo_created = realm::util::try_create_fifo(path); + if (!fifo_created && !temp_dir.empty()) { + path = util::format("%1realm_%2.note", temp_dir, std::hash()(parent.get_path())); + fifo_created = realm::util::try_create_fifo(path); + } + if (!fifo_created && !sys_temp_dir.empty()) { + path = util::format("%1realm_%2.note", sys_temp_dir, std::hash()(parent.get_path())); + realm::util::create_fifo(path); + } + + m_notify_fd = open(path.c_str(), O_RDWR); + if (m_notify_fd == -1) { + throw std::system_error(errno, std::system_category()); + } + + // Make writing to the pipe return -1 when the pipe's buffer is full + // rather than blocking until there's space available + int ret = fcntl(m_notify_fd, F_SETFL, O_NONBLOCK); + if (ret == -1) { + throw std::system_error(errno, std::system_category()); + } + +#else // !TARGET_OS_TV + + // tvOS does not support named pipes, so use an anonymous pipe instead + int notification_pipe[2]; + int ret = pipe(notification_pipe); + if (ret == -1) { + throw std::system_error(errno, std::system_category()); + } + + m_notify_fd = notification_pipe[0]; + m_notify_fd_write = notification_pipe[1]; + +#endif // TARGET_OS_TV + + // Create the anonymous pipe for shutdown notifications + int shutdown_pipe[2]; + ret = pipe(shutdown_pipe); + if (ret == -1) { + throw std::system_error(errno, std::system_category()); + } + + m_shutdown_read_fd = shutdown_pipe[0]; + m_shutdown_write_fd = shutdown_pipe[1]; + + m_thread = std::thread([=] { + try { + listen(); + } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + catch (std::exception const& e) { + fprintf(stderr, "uncaught exception in notifier thread: %s: %s\n", typeid(e).name(), e.what()); + asl_log(nullptr, nullptr, ASL_LEVEL_ERR, "uncaught exception in notifier thread: %s: %s", typeid(e).name(), e.what()); + throw; + } + catch (...) { + fprintf(stderr, "uncaught exception in notifier thread\n"); + asl_log(nullptr, nullptr, ASL_LEVEL_ERR, "uncaught exception in notifier thread"); + throw; + } +#pragma clang diagnostic pop + }); +} + +ExternalCommitHelper::~ExternalCommitHelper() +{ + notify_fd(m_shutdown_write_fd, m_shutdown_read_fd); + m_thread.join(); // Wait for the thread to exit +} + +void ExternalCommitHelper::listen() +{ + pthread_setname_np("Realm notification listener"); + + // Set up the kqueue + // EVFILT_READ indicates that we care about data being available to read + // on the given file descriptor. + // EV_CLEAR makes it wait for the amount of data available to be read to + // change rather than just returning when there is any data to read. + struct kevent ke[2]; + EV_SET(&ke[0], m_notify_fd, EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, 0); + EV_SET(&ke[1], m_shutdown_read_fd, EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, 0); + int ret = kevent(m_kq, ke, 2, nullptr, 0, nullptr); + assert(ret == 0); + + while (true) { + struct kevent event; + // Wait for data to become on either fd + // Return code is number of bytes available or -1 on error + ret = kevent(m_kq, nullptr, 0, &event, 1, nullptr); + if (ret == 0 || (ret < 0 && errno == EINTR)) { + // Spurious wakeup; just wait again + continue; + } + assert(ret > 0); + + // Check which file descriptor had activity: if it's the shutdown + // pipe, then someone called -stop; otherwise it's the named pipe + // and someone committed a write transaction + if (event.ident == (uint32_t)m_shutdown_read_fd) { + return; + } + assert(event.ident == (uint32_t)m_notify_fd); + + m_parent.on_change(); + } +} + +void ExternalCommitHelper::notify_others() +{ + if (m_notify_fd_write != -1) { + notify_fd(m_notify_fd_write, m_notify_fd); + } + else { + notify_fd(m_notify_fd, m_notify_fd); + } +} diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/impl/apple/keychain_helper.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/impl/apple/keychain_helper.cpp new file mode 100644 index 0000000..92b5b1e --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/impl/apple/keychain_helper.cpp @@ -0,0 +1,143 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// 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 "impl/apple/keychain_helper.hpp" + + +#include +#include + +#include + +#include + +using realm::util::CFPtr; +using realm::util::adoptCF; +using realm::util::retainCF; + +namespace realm { +namespace keychain { + +KeychainAccessException::KeychainAccessException(int32_t error_code) +: std::runtime_error(util::format("Keychain returned unexpected status code: %1", error_code)) { } + +namespace { + +constexpr size_t key_size = 64; + +#if !TARGET_IPHONE_SIMULATOR +CFPtr convert_string(const std::string& string) +{ + auto result = adoptCF(CFStringCreateWithBytes(nullptr, reinterpret_cast(string.data()), + string.size(), kCFStringEncodingASCII, false)); + if (!result) { + throw std::bad_alloc(); + } + return result; +} +#endif + +CFPtr build_search_dictionary(CFStringRef account, CFStringRef service, + __unused util::Optional group) +{ + auto d = adoptCF(CFDictionaryCreateMutable(nullptr, 0, &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks)); + if (!d) + throw std::bad_alloc(); + + CFDictionaryAddValue(d.get(), kSecClass, kSecClassGenericPassword); + CFDictionaryAddValue(d.get(), kSecReturnData, kCFBooleanTrue); + CFDictionaryAddValue(d.get(), kSecAttrAccount, account); + CFDictionaryAddValue(d.get(), kSecAttrService, service); +#if !TARGET_IPHONE_SIMULATOR + if (group) + CFDictionaryAddValue(d.get(), kSecAttrAccessGroup, convert_string(*group).get()); +#endif + return d; +} + +/// Get the encryption key for a given service, returning it only if it exists. +util::Optional> get_key(CFStringRef account, CFStringRef service) +{ + auto search_dictionary = build_search_dictionary(account, service, none); + CFDataRef retained_key_data; + if (OSStatus status = SecItemCopyMatching(search_dictionary.get(), (CFTypeRef *)&retained_key_data)) { + if (status != errSecItemNotFound) + throw KeychainAccessException(status); + + // Key was not found. + return none; + } + + // Key was previously stored. Extract it. + CFPtr key_data = adoptCF(retained_key_data); + if (key_size != CFDataGetLength(key_data.get())) + throw std::runtime_error("Password stored in keychain was not expected size."); + + auto key_bytes = reinterpret_cast(CFDataGetBytePtr(key_data.get())); + return std::vector(key_bytes, key_bytes + key_size); +} + +void set_key(const std::vector& key, CFStringRef account, CFStringRef service) +{ + auto search_dictionary = build_search_dictionary(account, service, none); + CFDictionaryAddValue(search_dictionary.get(), kSecAttrAccessible, kSecAttrAccessibleAfterFirstUnlock); + auto key_data = adoptCF(CFDataCreate(nullptr, reinterpret_cast(key.data()), key_size)); + if (!key_data) + throw std::bad_alloc(); + + CFDictionaryAddValue(search_dictionary.get(), kSecValueData, key_data.get()); + if (OSStatus status = SecItemAdd(search_dictionary.get(), nullptr)) + throw KeychainAccessException(status); +} + +} // anonymous namespace + +std::vector metadata_realm_encryption_key(bool check_legacy_service) +{ + CFStringRef account = CFSTR("metadata"); + CFStringRef legacy_service = CFSTR("io.realm.sync.keychain"); + + CFPtr service; + if (CFStringRef bundle_id = CFBundleGetIdentifier(CFBundleGetMainBundle())) + service = adoptCF(CFStringCreateWithFormat(NULL, NULL, CFSTR("%@ - Realm Sync Metadata Key"), bundle_id)); + else { + service = retainCF(legacy_service); + check_legacy_service = false; + } + + // Try retrieving the key. + if (auto existing_key = get_key(account, service.get())) { + return *existing_key; + } else if (check_legacy_service) { + // See if there's a key stored using the legacy shared keychain item. + if (auto existing_legacy_key = get_key(account, legacy_service)) { + // If so, copy it to the per-app keychain item before returning it. + set_key(*existing_legacy_key, account, service.get()); + return *existing_legacy_key; + } + } + // Make a completely new key. + std::vector key(key_size); + arc4random_buf(key.data(), key_size); + set_key(key, account, service.get()); + return key; +} + +} // keychain +} // realm diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/impl/collection_change_builder.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/impl/collection_change_builder.cpp new file mode 100644 index 0000000..5695b4b --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/impl/collection_change_builder.cpp @@ -0,0 +1,673 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// 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 "impl/collection_change_builder.hpp" + +#include + +#include + +using namespace realm; +using namespace realm::_impl; + +CollectionChangeBuilder::CollectionChangeBuilder(IndexSet deletions, + IndexSet insertions, + IndexSet modifications, + std::vector moves) +: CollectionChangeSet({std::move(deletions), std::move(insertions), std::move(modifications), {}, std::move(moves)}) +{ + for (auto&& move : this->moves) { + this->deletions.add(move.from); + this->insertions.add(move.to); + } +} + +void CollectionChangeBuilder::merge(CollectionChangeBuilder&& c) +{ + if (c.empty()) + return; + if (empty()) { + *this = std::move(c); + return; + } + + verify(); + c.verify(); + + // FIXME: this is comically wasteful + std::unordered_set col_keys; + if (m_track_columns) { + for (auto& col : columns) + col_keys.insert(col.first); + for (auto& col : c.columns) + col_keys.insert(col.first); + } + + auto for_each_col = [&](auto&& f) { + f(modifications, c.modifications); + if (m_track_columns) { + for (auto col : col_keys) + f(columns[col], c.columns[col]); + } + }; + + // First update any old moves + if (!c.moves.empty() || !c.deletions.empty() || !c.insertions.empty()) { + auto it = std::remove_if(begin(moves), end(moves), [&](auto& old) { + // Check if the moved row was moved again, and if so just update the destination + auto it = find_if(begin(c.moves), end(c.moves), [&](auto const& m) { + return old.to == m.from; + }); + if (it != c.moves.end()) { + for_each_col([&](auto& col, auto& other) { + if (col.contains(it->from)) + other.add(it->to); + }); + old.to = it->to; + *it = c.moves.back(); + c.moves.pop_back(); + return false; + } + + // Check if the destination was deleted + // Removing the insert for this move will happen later + if (c.deletions.contains(old.to)) + return true; + + // Update the destination to adjust for any new insertions and deletions + old.to = c.insertions.shift(c.deletions.unshift(old.to)); + return false; + }); + moves.erase(it, end(moves)); + } + + // Ignore new moves of rows which were previously inserted (the implicit + // delete from the move will remove the insert) + if (!insertions.empty() && !c.moves.empty()) { + c.moves.erase(std::remove_if(begin(c.moves), end(c.moves), + [&](auto const& m) { return insertions.contains(m.from); }), + end(c.moves)); + } + + // Ensure that any previously modified rows which were moved are still modified + if (!modifications.empty() && !c.moves.empty()) { + for (auto const& move : c.moves) { + for_each_col([&](auto& col, auto& other) { + if (col.contains(move.from)) + other.add(move.to); + }); + } + } + + // Update the source position of new moves to compensate for the changes made + // in the old changeset + if (!deletions.empty() || !insertions.empty()) { + for (auto& move : c.moves) + move.from = deletions.shift(insertions.unshift(move.from)); + } + + moves.insert(end(moves), begin(c.moves), end(c.moves)); + + // New deletion indices have been shifted by the insertions, so unshift them + // before adding + deletions.add_shifted_by(insertions, c.deletions); + + // Drop any inserted-then-deleted rows, then merge in new insertions + insertions.erase_at(c.deletions); + insertions.insert_at(c.insertions); + + clean_up_stale_moves(); + + for_each_col([&](auto& col, auto& other) { + col.erase_at(c.deletions); + col.shift_for_insert_at(c.insertions); + col.add(other); + }); + + c = {}; + verify(); +} + +void CollectionChangeBuilder::clean_up_stale_moves() +{ + // Look for moves which are now no-ops, and remove them plus the associated + // insert+delete. Note that this isn't just checking for from == to due to + // that rows can also be shifted by other inserts and deletes + moves.erase(std::remove_if(begin(moves), end(moves), [&](auto const& move) { + if (move.from - deletions.count(0, move.from) != move.to - insertions.count(0, move.to)) + return false; + deletions.remove(move.from); + insertions.remove(move.to); + return true; + }), end(moves)); +} + +void CollectionChangeBuilder::modify(size_t ndx, size_t col) +{ + modifications.add(ndx); + if (!m_track_columns || col == IndexSet::npos) + return; + columns[col].add(ndx); +} + +template +void CollectionChangeBuilder::for_each_col(Func&& f) +{ + f(modifications); + if (m_track_columns) { + for (auto& col : columns) + f(col.second); + } +} + +void CollectionChangeBuilder::insert(size_t index, size_t count, bool track_moves) +{ + REALM_ASSERT(count != 0); + + for_each_col([=](auto& col) { col.shift_for_insert_at(index, count); }); + if (!track_moves) + return; + + insertions.insert_at(index, count); + + for (auto& move : moves) { + if (move.to >= index) + move.to += count; + } +} + +void CollectionChangeBuilder::erase(size_t index) +{ + for_each_col([=](auto& col) { col.erase_at(index); }); + size_t unshifted = insertions.erase_or_unshift(index); + if (unshifted != IndexSet::npos) + deletions.add_shifted(unshifted); + + for (size_t i = 0; i < moves.size(); ++i) { + auto& move = moves[i]; + if (move.to == index) { + moves.erase(moves.begin() + i); + --i; + } + else if (move.to > index) + --move.to; + } +} + +void CollectionChangeBuilder::clear(size_t old_size) +{ + for (auto range : deletions) + old_size += range.second - range.first; + for (auto range : insertions) + old_size -= range.second - range.first; + + modifications.clear(); + insertions.clear(); + moves.clear(); + columns.clear(); + deletions.set(old_size); +} + +void CollectionChangeBuilder::move(size_t from, size_t to) +{ + REALM_ASSERT(from != to); + + bool updated_existing_move = false; + for (auto& move : moves) { + if (move.to != from) { + // Shift other moves if this row is moving from one side of them + // to the other + if (move.to >= to && move.to < from) + ++move.to; + else if (move.to <= to && move.to > from) + --move.to; + continue; + } + REALM_ASSERT(!updated_existing_move); + + // Collapse A -> B, B -> C into a single A -> C move + move.to = to; + updated_existing_move = true; + + insertions.erase_at(from); + insertions.insert_at(to); + } + + if (!updated_existing_move) { + auto shifted_from = insertions.erase_or_unshift(from); + insertions.insert_at(to); + + // Don't report deletions/moves for newly inserted rows + if (shifted_from != IndexSet::npos) { + shifted_from = deletions.add_shifted(shifted_from); + moves.push_back({shifted_from, to}); + } + } + + for_each_col([=](auto& col) { + bool modified = col.contains(from); + col.erase_at(from); + + if (modified) + col.insert_at(to); + else + col.shift_for_insert_at(to); + }); +} + +void CollectionChangeBuilder::verify() +{ +#ifdef REALM_DEBUG + for (auto&& move : moves) { + REALM_ASSERT(deletions.contains(move.from)); + REALM_ASSERT(insertions.contains(move.to)); + } +#endif +} + +namespace { +struct RowInfo { + int64_t key; + size_t prev_tv_index; + size_t tv_index; +}; + +#if 0 // FIXME: this is applicable to backlinks still +// Calculates the insertions/deletions required for a query on a table without +// a sort, where `removed` includes the rows which were modified to no longer +// match the query (but not outright deleted rows, which are filtered out long +// before any of this logic), and `move_candidates` tracks the rows which may +// be the result of a move. +// +// This function is not strictly required, as calculate_moves_sorted() will +// produce correct results even for the scenarios where this function is used. +// However, this function has asymptotically better worst-case performance and +// extremely cheap best-case performance, and is guaranteed to produce a minimal +// diff. +void calculate_moves_backlinks(std::vector& new_rows, IndexSet& removed, + IndexSet const& move_candidates, + CollectionChangeSet& changeset) +{ + // Here we track which row we expect to see, which in the absence of swap() + // is always the row immediately after the last row which was not moved. + size_t expected = 0; + for (auto& row : new_rows) { + if (row.shifted_tv_index == expected) { + ++expected; + continue; + } + + // We didn't find the row we were expecting to find, which means that + // either a row was moved forward to here, the row we were expecting was + // removed, or the row we were expecting moved back. + + // First check if this row even could have moved. If it can't, just + // treat it as a match and move on, and we'll handle the row we were + // expecting when we hit it later. + if (!move_candidates.contains(row.key)) { + expected = row.shifted_tv_index + 1; + continue; + } + + // Next calculate where we expect this row to be based on the insertions + // and removals (i.e. rows changed to not match the query), as it could + // be that the row actually ends up in this spot due to the rows before + // it being removed. + size_t calc_expected = row.tv_index - changeset.insertions.count(0, row.tv_index) + removed.count(0, row.prev_tv_index); + if (row.shifted_tv_index == calc_expected) { + expected = calc_expected + 1; + continue; + } + + // The row still isn't the expected one, so record it as a move + changeset.moves.push_back({row.prev_tv_index, row.tv_index}); + changeset.insertions.add(row.tv_index); + removed.add(row.prev_tv_index); + } +} +#endif + +class LongestCommonSubsequenceCalculator { +public: + // A pair of an object key and an index in the table view + struct Row { + int64_t key; + size_t tv_index; + }; + + struct Match { + // The index in `a` at which this match begins + size_t i; + // The index in `b` at which this match begins + size_t j; + // The length of this match + size_t size; + // The number of rows in this block which were modified + size_t modified; + }; + std::vector m_longest_matches; + + LongestCommonSubsequenceCalculator(std::vector& a, std::vector& b, + size_t start_index, + IndexSet const& modifications) + : m_modified(modifications) + , a(a), b(b) + { + find_longest_matches(start_index, a.size(), + start_index, b.size()); + m_longest_matches.push_back({a.size(), b.size(), 0}); + } + +private: + IndexSet const& m_modified; + + // The two arrays of rows being diffed + // a is sorted by tv_index, b is sorted by key + std::vector &a, &b; + + // Find the longest matching range in (a + begin1, a + end1) and (b + begin2, b + end2) + // "Matching" is defined as "has the same row index"; the TV index is just + // there to let us turn an index in a/b into an index which can be reported + // in the output changeset. + // + // This is done with the O(N) space variant of the dynamic programming + // algorithm for longest common subsequence, where N is the maximum number + // of the most common row index (which for everything but linkview-derived + // TVs will be 1). + Match find_longest_match(size_t begin1, size_t end1, size_t begin2, size_t end2) + { + struct Length { + size_t j, len; + }; + // The length of the matching block for each `j` for the previously checked row + std::vector prev; + // The length of the matching block for each `j` for the row currently being checked + std::vector cur; + + // Calculate the length of the matching block *ending* at b[j], which + // is 1 if b[j - 1] did not match, and b[j - 1] + 1 otherwise. + auto length = [&](size_t j) -> size_t { + for (auto const& pair : prev) { + if (pair.j + 1 == j) + return pair.len + 1; + } + return 1; + }; + + // Iterate over each `j` which has the same row index as a[i] and falls + // within the range begin2 <= j < end2 + auto for_each_b_match = [&](size_t i, auto&& f) { + auto ai = a[i].key; + // Find the TV indicies at which this row appears in the new results + // There should always be at least one (or it would have been + // filtered out earlier), but there can be multiple if there are dupes + auto it = lower_bound(begin(b), end(b), ai, + [](auto lft, auto rgt) { return lft.key < rgt; }); + REALM_ASSERT(it != end(b) && it->key == ai); + for (; it != end(b) && it->key == ai; ++it) { + size_t j = it->tv_index; + if (j < begin2) + continue; + if (j >= end2) + break; // b is sorted by tv_index so this can't transition from false to true + f(j); + } + }; + + Match best = {begin1, begin2, 0, 0}; + for (size_t i = begin1; i < end1; ++i) { + // prev = std::move(cur), but avoids discarding prev's heap allocation + cur.swap(prev); + cur.clear(); + + for_each_b_match(i, [&](size_t j) { + size_t size = length(j); + + cur.push_back({j, size}); + + // If the matching block ending at a[i] and b[j] is longer than + // the previous one, select it as the best + if (size > best.size) + best = {i - size + 1, j - size + 1, size, IndexSet::npos}; + // Given two equal-length matches, prefer the one with fewer modified rows + else if (size == best.size) { + if (best.modified == IndexSet::npos) + best.modified = m_modified.count(best.j - size + 1, best.j + 1); + auto count = m_modified.count(j - size + 1, j + 1); + if (count < best.modified) + best = {i - size + 1, j - size + 1, size, count}; + } + + // The best block should always fall within the range being searched + REALM_ASSERT(best.i >= begin1 && best.i + best.size <= end1); + REALM_ASSERT(best.j >= begin2 && best.j + best.size <= end2); + }); + } + return best; + } + + void find_longest_matches(size_t begin1, size_t end1, size_t begin2, size_t end2) + { + // FIXME: recursion could get too deep here + // recursion depth worst case is currently O(N) and each recursion uses 320 bytes of stack + // could reduce worst case to O(sqrt(N)) (and typical case to O(log N)) + // biasing equal selections towards the middle, but that's still + // insufficient for Android's 8 KB stacks + auto m = find_longest_match(begin1, end1, begin2, end2); + if (!m.size) + return; + if (m.i > begin1 && m.j > begin2) + find_longest_matches(begin1, m.i, begin2, m.j); + m_longest_matches.push_back(m); + if (m.i + m.size < end2 && m.j + m.size < end2) + find_longest_matches(m.i + m.size, end1, m.j + m.size, end2); + } +}; + +void calculate_moves_sorted(std::vector& rows, CollectionChangeSet& changeset) +{ + // The RowInfo array contains information about the old and new TV indices of + // each row, which we need to turn into two sequences of rows, which we'll + // then find matches in + std::vector a, b; + + a.reserve(rows.size()); + for (auto& row : rows) + a.push_back({row.key, row.prev_tv_index}); + std::sort(begin(a), end(a), [](auto lft, auto rgt) { + return std::tie(lft.tv_index, lft.key) < std::tie(rgt.tv_index, rgt.key); + }); + + // Before constructing `b`, first find the first index in `a` which will + // actually differ in `b`, and skip everything else if there aren't any + size_t first_difference = IndexSet::npos; + for (size_t i = 0; i < a.size(); ++i) { + if (a[i].key != rows[i].key) { + first_difference = i; + break; + } + } + if (first_difference == IndexSet::npos) + return; + + // Note that `b` is sorted by key, while `a` is sorted by tv_index + b.reserve(rows.size()); + for (size_t i = 0; i < rows.size(); ++i) + b.push_back({rows[i].key, i}); + std::sort(begin(b), end(b), [](auto lft, auto rgt) { + return std::tie(lft.key, lft.tv_index) < std::tie(rgt.key, rgt.tv_index); + }); + + // Calculate the LCS of the two sequences + auto matches = LongestCommonSubsequenceCalculator(a, b, first_difference, + changeset.modifications).m_longest_matches; + + // And then insert and delete rows as needed to align them + size_t i = first_difference, j = first_difference; + for (auto match : matches) { + for (; i < match.i; ++i) + changeset.deletions.add(a[i].tv_index); + for (; j < match.j; ++j) + changeset.insertions.add(rows[j].tv_index); + i += match.size; + j += match.size; + } +} + +template +void verify_changeset(std::vector const& prev_rows, + std::vector const& next_rows, + CollectionChangeBuilder const& changeset) +{ +#ifdef REALM_DEBUG + { // Verify that applying the calculated change to prev_rows actually produces next_rows + auto rows = prev_rows; + auto it = util::make_reverse_iterator(changeset.deletions.end()); + auto end = util::make_reverse_iterator(changeset.deletions.begin()); + for (; it != end; ++it) { + rows.erase(rows.begin() + it->first, rows.begin() + it->second); + } + + for (auto i : changeset.insertions.as_indexes()) { + rows.insert(rows.begin() + i, next_rows[i]); + } + + REALM_ASSERT(rows == next_rows); + } +#else + static_cast(prev_rows); + static_cast(next_rows); + static_cast(changeset); +#endif +} + +void calculate(CollectionChangeBuilder& ret, + std::vector old_rows, std::vector new_rows, + std::function key_did_change, bool in_table_order) +{ + // Now that our old and new sets of rows are sorted by key, we can + // iterate over them and either record old+new TV indices for rows present + // in both, or mark them as inserted/deleted if they appear only in one + size_t i = 0, j = 0; + while (i < old_rows.size() && j < new_rows.size()) { + auto old_index = old_rows[i]; + auto& new_index = new_rows[j]; + if (old_index.key == new_index.key) { + new_index.prev_tv_index = old_rows[i].tv_index; + ++i; + ++j; + } + else if (old_index.key < new_index.key) { + ret.deletions.add(old_index.tv_index); + ++i; + } + else { + ret.insertions.add(new_index.tv_index); + ++j; + } + } + + for (; i < old_rows.size(); ++i) + ret.deletions.add(old_rows[i].tv_index); + for (; j < new_rows.size(); ++j) + ret.insertions.add(new_rows[j].tv_index); + + // Filter out the new insertions since we don't need them for any of the + // further calculations + new_rows.erase(std::remove_if(begin(new_rows), end(new_rows), + [](auto& row) { return row.prev_tv_index == IndexSet::npos; }), + end(new_rows)); + std::sort(begin(new_rows), end(new_rows), + [](auto& lft, auto& rgt) { return lft.tv_index < rgt.tv_index; }); + + for (auto& row : new_rows) { + if (key_did_change(row.key)) { + ret.modifications.add(row.tv_index); + } + } + + if (!in_table_order) + calculate_moves_sorted(new_rows, ret); +} + +} // Anonymous namespace + +CollectionChangeBuilder CollectionChangeBuilder::calculate(std::vector const& prev_rows, + std::vector const& next_rows, + std::function key_did_change, + bool in_table_order) +{ + + auto build_row_info = [](auto& rows) { + std::vector info; + info.reserve(rows.size()); + for (size_t i = 0; i < rows.size(); ++i) + info.push_back({rows[i], IndexSet::npos, i}); + std::sort(begin(info), end(info), [](auto& lft, auto& rgt) { return lft.key < rgt.key; }); + return info; + }; + + CollectionChangeBuilder ret; + ::calculate(ret, build_row_info(prev_rows), build_row_info(next_rows), std::move(key_did_change), in_table_order); + ret.verify(); + verify_changeset(prev_rows, next_rows, ret); + return ret; +} + +CollectionChangeBuilder CollectionChangeBuilder::calculate(std::vector const& prev_rows, + std::vector const& next_rows, + std::function key_did_change) +{ + + auto build_row_info = [](auto& rows) { + std::vector info; + info.reserve(rows.size()); + for (size_t i = 0; i < rows.size(); ++i) + info.push_back({static_cast(rows[i]), IndexSet::npos, i}); + std::sort(begin(info), end(info), [](auto& lft, auto& rgt) { return lft.key < rgt.key; }); + return info; + }; + + CollectionChangeBuilder ret; + ::calculate(ret, build_row_info(prev_rows), build_row_info(next_rows), std::move(key_did_change), false); + ret.verify(); + verify_changeset(prev_rows, next_rows, ret); + return ret; +} + +CollectionChangeSet CollectionChangeBuilder::finalize() && +{ + // Calculate which indices in the old collection were modified + auto modifications_in_old = modifications; + modifications_in_old.erase_at(insertions); + modifications_in_old.shift_for_insert_at(deletions); + + // During changeset calculation we allow marking a row as both inserted and + // modified in case changeset merging results in it no longer being an insert, + // but we don't want inserts in the final modification set + modifications.remove(insertions); + + return { + std::move(deletions), + std::move(insertions), + std::move(modifications_in_old), + std::move(modifications), + std::move(moves), + std::move(columns) + }; +} diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/impl/collection_notifier.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/impl/collection_notifier.cpp new file mode 100644 index 0000000..4da4aaf --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/impl/collection_notifier.cpp @@ -0,0 +1,500 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// 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 "impl/collection_notifier.hpp" + +#include "impl/realm_coordinator.hpp" +#include "shared_realm.hpp" + +#include + +using namespace realm; +using namespace realm::_impl; + +bool CollectionNotifier::all_related_tables_covered(const TableVersions& versions) +{ + if (m_related_tables.size() > versions.size()) { + return false; + } + auto first = versions.begin(); + auto last = versions.end(); + for (auto& it : m_related_tables) { + TableKey tk{it.table_key}; + auto match = std::find_if(first, last, [tk](auto& elem) { + return elem.first == tk; + }); + if (match == last) { + // tk not found in versions + return false; + } + } + return true; +} + +std::function +CollectionNotifier::get_modification_checker(TransactionChangeInfo const& info, + ConstTableRef root_table) +{ + if (info.schema_changed) + set_table(root_table); + + // First check if any of the tables accessible from the root table were + // actually modified. This can be false if there were only insertions, or + // deletions which were not linked to by any row in the linking table + auto table_modified = [&](auto& tbl) { + auto it = info.tables.find(tbl.table_key.value); + return it != info.tables.end() && !it->second.modifications_empty(); + }; + if (!any_of(begin(m_related_tables), end(m_related_tables), table_modified)) { + return [](ObjectChangeSet::ObjectKeyType) { return false; }; + } + if (m_related_tables.size() == 1) { + auto& object_set = info.tables.find(m_related_tables[0].table_key.value)->second; + return [&](ObjectChangeSet::ObjectKeyType object_key) { return object_set.modifications_contains(object_key); }; + } + + return DeepChangeChecker(info, *root_table, m_related_tables); +} + +void DeepChangeChecker::find_related_tables(std::vector& out, Table const& table) +{ + auto table_key = table.get_key(); + if (any_of(begin(out), end(out), [=](auto& tbl) { return tbl.table_key == table_key; })) + return; + + // We need to add this table to `out` before recurring so that the check + // above works, but we can't store a pointer to the thing being populated + // because the recursive calls may resize `out`, so instead look it up by + // index every time + size_t out_index = out.size(); + out.push_back({table_key, {}}); + + for (auto col_key : table.get_column_keys()) { + auto type = table.get_column_type(col_key); + if (type == type_Link || type == type_LinkList) { + out[out_index].links.push_back({col_key.value, type == type_LinkList}); + find_related_tables(out, *table.get_link_target(col_key)); + } + } +} + +DeepChangeChecker::DeepChangeChecker(TransactionChangeInfo const& info, + Table const& root_table, + std::vector const& related_tables) +: m_info(info) +, m_root_table(root_table) +, m_root_table_key(root_table.get_key().value) +, m_root_object_changes([&] { + auto it = info.tables.find(m_root_table_key.value); + return it != info.tables.end() ? &it->second : nullptr; +}()) +, m_related_tables(related_tables) +{ +} + +bool DeepChangeChecker::check_outgoing_links(TableKey table_key, Table const& table, + int64_t obj_key, size_t depth) +{ + auto it = find_if(begin(m_related_tables), end(m_related_tables), + [&](auto&& tbl) { return tbl.table_key == table_key; }); + if (it == m_related_tables.end()) + return false; + if (it->links.empty()) + return false; + + // Check if we're already checking if the destination of the link is + // modified, and if not add it to the stack + auto already_checking = [&](int64_t col) { + auto end = m_current_path.begin() + depth; + auto match = std::find_if(m_current_path.begin(), end, [&](auto& p) { + return p.obj_key == obj_key && p.col_key == col; + }); + if (match != end) { + for (; match < end; ++match) match->depth_exceeded = true; + return true; + } + m_current_path[depth] = {obj_key, col, false}; + return false; + }; + + ConstObj obj = table.get_object(ObjKey(obj_key)); + auto linked_object_changed = [&](OutgoingLink const& link) { + if (already_checking(link.col_key)) + return false; + if (!link.is_list) { + if (obj.is_null(ColKey(link.col_key))) + return false; + auto dst = obj.get(ColKey(link.col_key)).value; + return check_row(*table.get_link_target(ColKey(link.col_key)), dst, depth + 1); + } + + auto& target = *table.get_link_target(ColKey(link.col_key)); + auto lvr = obj.get_linklist(ColKey(link.col_key)); + return std::any_of(lvr.begin(), lvr.end(), + [&, this](auto key) { return this->check_row(target, key.value, depth + 1); }); + }; + + return std::any_of(begin(it->links), end(it->links), linked_object_changed); +} + +bool DeepChangeChecker::check_row(Table const& table, ObjKeyType key, size_t depth) +{ + // Arbitrary upper limit on the maximum depth to search + if (depth >= m_current_path.size()) { + // Don't mark any of the intermediate rows checked along the path as + // not modified, as a search starting from them might hit a modification + for (size_t i = 0; i < m_current_path.size(); ++i) + m_current_path[i].depth_exceeded = true; + return false; + } + + TableKey table_key = table.get_key(); + if (depth > 0) { + auto it = m_info.tables.find(table_key.value); + if (it != m_info.tables.end() && it->second.modifications_contains(key)) + return true; + } + auto& not_modified = m_not_modified[table_key.value]; + auto it = not_modified.find(key); + if (it != not_modified.end()) + return false; + + bool ret = check_outgoing_links(table_key, table, key, depth); + if (!ret && (depth == 0 || !m_current_path[depth - 1].depth_exceeded)) + not_modified.insert(key); + return ret; +} + +bool DeepChangeChecker::operator()(ObjKeyType key) +{ + if (m_root_object_changes && m_root_object_changes->modifications_contains(key)) + return true; + return check_row(m_root_table, key, 0); +} + +CollectionNotifier::CollectionNotifier(std::shared_ptr realm) +: m_realm(std::move(realm)) +, m_sg_version(Realm::Internal::get_transaction(*m_realm).get_version_of_current_transaction()) +{ +} + +CollectionNotifier::~CollectionNotifier() +{ + // Need to do this explicitly to ensure m_realm is destroyed with the mutex + // held to avoid potential double-deletion + unregister(); +} + +void CollectionNotifier::release_data() noexcept +{ + m_sg = nullptr; +} + +uint64_t CollectionNotifier::add_callback(CollectionChangeCallback callback) +{ + m_realm->verify_thread(); + + util::CheckedLockGuard lock(m_callback_mutex); + auto token = m_next_token++; + m_callbacks.push_back({std::move(callback), {}, {}, token, false, false}); + if (m_callback_index == npos) { // Don't need to wake up if we're already sending notifications + Realm::Internal::get_coordinator(*m_realm).wake_up_notifier_worker(); + m_have_callbacks = true; + } + return token; +} + +void CollectionNotifier::remove_callback(uint64_t token) +{ + // the callback needs to be destroyed after releasing the lock as destroying + // it could cause user code to be called + Callback old; + { + util::CheckedLockGuard lock(m_callback_mutex); + auto it = find_callback(token); + if (it == end(m_callbacks)) { + return; + } + + size_t idx = distance(begin(m_callbacks), it); + if (m_callback_index != npos) { + if (m_callback_index >= idx) + --m_callback_index; + } + --m_callback_count; + + old = std::move(*it); + m_callbacks.erase(it); + + m_have_callbacks = !m_callbacks.empty(); + } +} + +void CollectionNotifier::suppress_next_notification(uint64_t token) +{ + { + std::lock_guard lock(m_realm_mutex); + REALM_ASSERT(m_realm); + m_realm->verify_thread(); + m_realm->verify_in_write(); + } + + util::CheckedLockGuard lock(m_callback_mutex); + auto it = find_callback(token); + if (it != end(m_callbacks)) { + it->skip_next = true; + } +} + +std::vector::iterator CollectionNotifier::find_callback(uint64_t token) +{ + REALM_ASSERT(m_error || m_callbacks.size() > 0); + + auto it = find_if(begin(m_callbacks), end(m_callbacks), + [=](const auto& c) { return c.token == token; }); + // We should only fail to find the callback if it was removed due to an error + REALM_ASSERT(m_error || it != end(m_callbacks)); + return it; +} + +void CollectionNotifier::unregister() noexcept +{ + std::lock_guard lock(m_realm_mutex); + m_realm = nullptr; +} + +bool CollectionNotifier::is_alive() const noexcept +{ + std::lock_guard lock(m_realm_mutex); + return m_realm != nullptr; +} + +std::unique_lock CollectionNotifier::lock_target() +{ + return std::unique_lock{m_realm_mutex}; +} + +void CollectionNotifier::set_table(ConstTableRef table) +{ + m_related_tables.clear(); + DeepChangeChecker::find_related_tables(m_related_tables, *table); +} + +void CollectionNotifier::add_required_change_info(TransactionChangeInfo& info) +{ + if (!do_add_required_change_info(info) || m_related_tables.empty()) { + return; + } + + info.tables.reserve(m_related_tables.size()); + for (auto& tbl : m_related_tables) + info.tables[tbl.table_key.value]; +} + +void CollectionNotifier::prepare_handover() +{ + REALM_ASSERT(m_sg); + m_sg_version = m_sg->get_version_of_current_transaction(); + do_prepare_handover(*m_sg); + add_changes(std::move(m_change)); + REALM_ASSERT(m_change.empty()); + m_has_run = true; + +#ifdef REALM_DEBUG + util::CheckedLockGuard lock(m_callback_mutex); + for (auto& callback : m_callbacks) + REALM_ASSERT(!callback.skip_next); +#endif +} + +void CollectionNotifier::before_advance() +{ + for_each_callback([&](auto& lock, auto& callback) { + if (callback.changes_to_deliver.empty()) { + return; + } + + auto changes = callback.changes_to_deliver; + // acquire a local reference to the callback so that removing the + // callback from within it can't result in a dangling pointer + auto cb = callback.fn; + lock.unlock_unchecked(); + cb.before(changes); + }); +} + +void CollectionNotifier::after_advance() +{ + for_each_callback([&](auto& lock, auto& callback) { + if (callback.initial_delivered && callback.changes_to_deliver.empty()) { + return; + } + callback.initial_delivered = true; + + auto changes = std::move(callback.changes_to_deliver); + // acquire a local reference to the callback so that removing the + // callback from within it can't result in a dangling pointer + auto cb = callback.fn; + lock.unlock_unchecked(); + cb.after(changes); + }); +} + +void CollectionNotifier::deliver_error(std::exception_ptr error) +{ + // Don't complain about double-unregistering callbacks + m_error = true; + + m_callback_count = m_callbacks.size(); + for_each_callback([this, &error](auto& lock, auto& callback) { + // acquire a local reference to the callback so that removing the + // callback from within it can't result in a dangling pointer + auto cb = std::move(callback.fn); + auto token = callback.token; + lock.unlock_unchecked(); + cb.error(error); + + // We never want to call the callback again after this, so just remove it + this->remove_callback(token); + }); +} + +bool CollectionNotifier::is_for_realm(Realm& realm) const noexcept +{ + std::lock_guard lock(m_realm_mutex); + return m_realm.get() == &realm; +} + +bool CollectionNotifier::package_for_delivery() +{ + if (!prepare_to_deliver()) + return false; + util::CheckedLockGuard lock(m_callback_mutex); + for (auto& callback : m_callbacks) + callback.changes_to_deliver = std::move(callback.accumulated_changes).finalize(); + m_callback_count = m_callbacks.size(); + return true; +} + +template +void CollectionNotifier::for_each_callback(Fn&& fn) +{ + util::CheckedUniqueLock callback_lock(m_callback_mutex); + REALM_ASSERT_DEBUG(m_callback_count <= m_callbacks.size()); + for (++m_callback_index; m_callback_index < m_callback_count; ++m_callback_index) { + fn(callback_lock, m_callbacks[m_callback_index]); + if (!callback_lock.owns_lock()) + callback_lock.lock_unchecked(); + } + + m_callback_index = npos; +} + +void CollectionNotifier::attach_to(std::shared_ptr sg) +{ + do_attach_to(*sg); + m_sg = std::move(sg); +} + +Transaction& CollectionNotifier::source_shared_group() +{ + return Realm::Internal::get_transaction(*m_realm); +} + +void CollectionNotifier::add_changes(CollectionChangeBuilder change) +{ + util::CheckedLockGuard lock(m_callback_mutex); + for (auto& callback : m_callbacks) { + if (callback.skip_next) { + REALM_ASSERT_DEBUG(callback.accumulated_changes.empty()); + callback.skip_next = false; + } + else { + if (&callback == &m_callbacks.back()) + callback.accumulated_changes.merge(std::move(change)); + else + callback.accumulated_changes.merge(CollectionChangeBuilder(change)); + } + } +} + +NotifierPackage::NotifierPackage(std::exception_ptr error, + std::vector> notifiers, + RealmCoordinator* coordinator) +: m_notifiers(std::move(notifiers)) +, m_coordinator(coordinator) +, m_error(std::move(error)) +{ +} + +// Clang TSE seems to not like returning a unique_lock from a function +void NotifierPackage::package_and_wait(util::Optional target_version) NO_THREAD_SAFETY_ANALYSIS +{ + if (!m_coordinator || m_error || !*this) + return; + + auto lock = m_coordinator->wait_for_notifiers([&] { + if (!target_version) + return true; + return std::all_of(begin(m_notifiers), end(m_notifiers), [&](auto const& n) { + return !n->have_callbacks() || (n->has_run() && n->version().version >= *target_version); + }); + }); + + // Package the notifiers for delivery and remove any which don't have anything to deliver + auto package = [&](auto& notifier) { + if (notifier->has_run() && notifier->package_for_delivery()) { + m_version = notifier->version(); + return false; + } + return true; + }; + m_notifiers.erase(std::remove_if(begin(m_notifiers), end(m_notifiers), package), end(m_notifiers)); + if (m_version && target_version && m_version->version < *target_version) { + m_notifiers.clear(); + m_version = util::none; + } + REALM_ASSERT(m_version || m_notifiers.empty()); + + m_coordinator = nullptr; +} + +void NotifierPackage::before_advance() +{ + if (m_error) + return; + for (auto& notifier : m_notifiers) + notifier->before_advance(); +} + +void NotifierPackage::after_advance() +{ + if (m_error) { + for (auto& notifier : m_notifiers) + notifier->deliver_error(m_error); + return; + } + for (auto& notifier : m_notifiers) + notifier->after_advance(); +} + +void NotifierPackage::add_notifier(std::shared_ptr notifier) +{ + m_notifiers.push_back(notifier); + m_coordinator->register_notifier(notifier); +} diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/impl/list_notifier.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/impl/list_notifier.cpp new file mode 100644 index 0000000..5123ff5 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/impl/list_notifier.cpp @@ -0,0 +1,104 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// 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 "impl/list_notifier.hpp" + +#include "list.hpp" + +#include +#include + +using namespace realm; +using namespace realm::_impl; + +ListNotifier::ListNotifier(std::shared_ptr realm, LstBase const& list, + PropertyType type) +: CollectionNotifier(std::move(realm)) +, m_type(type) +, m_table(list.get_table()->get_key()) +, m_col(list.get_col_key()) +, m_obj(list.get_key()) +, m_prev_size(list.size()) +{ + if (m_type == PropertyType::Object) { + set_table(static_cast(list).get_target_table()); + } +} + +void ListNotifier::release_data() noexcept +{ + m_list = {}; + CollectionNotifier::release_data(); +} + +void ListNotifier::do_attach_to(Transaction& sg) +{ + try { + auto obj = sg.get_table(m_table)->get_object(m_obj); + m_list = obj.get_listbase_ptr(m_col); + } + catch (const KeyNotFound&) { + } +} + +bool ListNotifier::do_add_required_change_info(TransactionChangeInfo& info) +{ + if (!m_list->is_attached()) + return false; // origin row was deleted after the notification was added + + info.lists.push_back({m_table, m_obj.value, m_col.value, &m_change}); + + m_info = &info; + return true; +} + +void ListNotifier::run() +{ + if (!m_list->is_attached()) { + // List was deleted, so report all of the rows being removed if this is + // the first run after that + if (m_prev_size) { + m_change.deletions.set(m_prev_size); + m_prev_size = 0; + } + else { + m_change = {}; + } + return; + } + + m_prev_size = m_list->size(); + + if (m_type == PropertyType::Object) { + auto& list = static_cast(*m_list); + auto object_did_change = get_modification_checker(*m_info, list.get_target_table()); + for (size_t i = 0; i < list.size(); ++i) { + if (m_change.modifications.contains(i)) + continue; + if (object_did_change(list.get(i).value)) + m_change.modifications.add(i); + } + + for (auto const& move : m_change.moves) { + if (m_change.modifications.contains(move.to)) + continue; + if (object_did_change(list.get(move.to).value)) + m_change.modifications.add(move.to); + } + } +} diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/impl/object_notifier.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/impl/object_notifier.cpp new file mode 100644 index 0000000..f266199 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/impl/object_notifier.cpp @@ -0,0 +1,64 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2017 Realm Inc. +// +// 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 "impl/object_notifier.hpp" + +#include "shared_realm.hpp" + +using namespace realm; +using namespace realm::_impl; + +ObjectNotifier::ObjectNotifier(std::shared_ptr realm, TableKey table, ObjKey obj) +: CollectionNotifier(std::move(realm)) +, m_table(table) +, m_obj(obj) +{ +} + +bool ObjectNotifier::do_add_required_change_info(TransactionChangeInfo& info) +{ + m_info = &info; + info.tables[m_table.value]; + return false; +} + +void ObjectNotifier::run() +{ + if (!m_table) + return; + + auto it = m_info->tables.find(m_table.value); + if (it == m_info->tables.end()) + return; + auto& change = it->second; + + if (change.deletions_contains(m_obj.value)) { + m_change.deletions.add(0); + m_table = {}; + m_obj = {}; + return; + } + + auto column_modifications = change.get_columns_modified(m_obj.value); + if (!column_modifications) + return; + m_change.modifications.add(0); + for (auto col : *column_modifications) { + m_change.columns[col].add(0); + } +} diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/impl/realm_coordinator.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/impl/realm_coordinator.cpp new file mode 100644 index 0000000..3706f91 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/impl/realm_coordinator.cpp @@ -0,0 +1,1183 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// 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 "impl/realm_coordinator.hpp" + +#include "impl/collection_notifier.hpp" +#include "impl/external_commit_helper.hpp" +#include "impl/transact_log_handler.hpp" +#include "impl/weak_realm_notifier.hpp" +#include "binding_context.hpp" +#include "object_schema.hpp" +#include "object_store.hpp" +#include "property.hpp" +#include "schema.hpp" +#include "thread_safe_reference.hpp" +#include "util/scheduler.hpp" + +#if REALM_ENABLE_SYNC +#include "sync/impl/sync_file.hpp" +#include "sync/async_open_task.hpp" +#include "sync/sync_config.hpp" +#include "sync/sync_manager.hpp" +#include "sync/sync_session.hpp" +#endif + +#include +#include +#include +#include + +#include +#include + +using namespace realm; +using namespace realm::_impl; + +static auto& s_coordinator_mutex = *new std::mutex; +static auto& s_coordinators_per_path = *new std::unordered_map>; + +std::shared_ptr RealmCoordinator::get_coordinator(StringData path) +{ + std::lock_guard lock(s_coordinator_mutex); + + auto& weak_coordinator = s_coordinators_per_path[path]; + if (auto coordinator = weak_coordinator.lock()) { + return coordinator; + } + + auto coordinator = std::make_shared(); + weak_coordinator = coordinator; + return coordinator; +} + +std::shared_ptr RealmCoordinator::get_coordinator(const Realm::Config& config) NO_THREAD_SAFETY_ANALYSIS +{ + auto coordinator = get_coordinator(config.path); + util::CheckedLockGuard lock(coordinator->m_realm_mutex); + coordinator->set_config(config); + return coordinator; +} + +std::shared_ptr RealmCoordinator::get_existing_coordinator(StringData path) +{ + std::lock_guard lock(s_coordinator_mutex); + + auto& weak_coordinator = s_coordinators_per_path[path]; + if (auto coordinator = weak_coordinator.lock()) { + return coordinator; + } + + return {}; +} + +void RealmCoordinator::create_sync_session(bool force_client_resync) +{ +#if REALM_ENABLE_SYNC + if (m_sync_session) + return; + + if (!m_config.encryption_key.empty() && !m_config.sync_config->realm_encryption_key) { + throw std::logic_error("A realm encryption key was specified in Realm::Config but not in SyncConfig"); + } else if (m_config.sync_config->realm_encryption_key && m_config.encryption_key.empty()) { + throw std::logic_error("A realm encryption key was specified in SyncConfig but not in Realm::Config"); + } else if (m_config.sync_config->realm_encryption_key && + !std::equal(m_config.sync_config->realm_encryption_key->begin(), m_config.sync_config->realm_encryption_key->end(), + m_config.encryption_key.begin(), m_config.encryption_key.end())) { + throw std::logic_error("The realm encryption key specified in SyncConfig does not match the one in Realm::Config"); + } + + m_sync_session = m_config.sync_config->user->sync_manager()->get_session(m_config.path, + *m_config.sync_config, + force_client_resync); + + std::weak_ptr weak_self = shared_from_this(); + SyncSession::Internal::set_sync_transact_callback(*m_sync_session, + [weak_self](VersionID old_version, VersionID new_version) { + if (auto self = weak_self.lock()) { + util::CheckedUniqueLock lock(self->m_transaction_callback_mutex); + if (auto transaction_callback = self->m_transaction_callback) { + lock.unlock(); + transaction_callback(old_version, new_version); + } + if (self->m_notifier) + self->m_notifier->notify_others(); + } + }); +#else + static_cast(force_client_resync); +#endif +} + +void RealmCoordinator::set_config(const Realm::Config& config) +{ + if (config.encryption_key.data() && config.encryption_key.size() != 64) + throw InvalidEncryptionKeyException(); + if (config.schema_mode == SchemaMode::Immutable && config.sync_config) + throw std::logic_error("Synchronized Realms cannot be opened in immutable mode"); + if (config.schema_mode == SchemaMode::Additive && config.migration_function) + throw std::logic_error("Realms opened in Additive-only schema mode do not use a migration function"); + if (config.schema_mode == SchemaMode::Immutable && config.migration_function) + throw std::logic_error("Realms opened in immutable mode do not use a migration function"); + if (config.schema_mode == SchemaMode::ReadOnlyAlternative && config.migration_function) + throw std::logic_error("Realms opened in read-only mode do not use a migration function"); + if (config.schema_mode == SchemaMode::Immutable && config.initialization_function) + throw std::logic_error("Realms opened in immutable mode do not use an initialization function"); + if (config.schema_mode == SchemaMode::ReadOnlyAlternative && config.initialization_function) + throw std::logic_error("Realms opened in read-only mode do not use an initialization function"); + if (config.schema && config.schema_version == ObjectStore::NotVersioned) + throw std::logic_error("A schema version must be specified when the schema is specified"); + if (!config.realm_data.is_null() && (!config.immutable() || !config.in_memory)) + throw std::logic_error("In-memory realms initialized from memory buffers can only be opened in read-only mode"); + if (!config.realm_data.is_null() && !config.path.empty()) + throw std::logic_error("Specifying both memory buffer and path is invalid"); + if (!config.realm_data.is_null() && !config.encryption_key.empty()) + throw std::logic_error("Memory buffers do not support encryption"); + // ResetFile also won't use the migration function, but specifying one is + // allowed to simplify temporarily switching modes during development + + bool no_existing_realm = std::all_of(begin(m_weak_realm_notifiers), end(m_weak_realm_notifiers), + [](auto& notifier) { return notifier.expired(); }); + if (no_existing_realm) { + m_config = config; + m_config.scheduler = nullptr; + } + else { + if (m_config.immutable() != config.immutable()) { + throw MismatchedConfigException("Realm at path '%1' already opened with different read permissions.", config.path); + } + if (m_config.in_memory != config.in_memory) { + throw MismatchedConfigException("Realm at path '%1' already opened with different inMemory settings.", config.path); + } + if (m_config.encryption_key != config.encryption_key) { + throw MismatchedConfigException("Realm at path '%1' already opened with a different encryption key.", config.path); + } + if (m_config.schema_mode != config.schema_mode) { + throw MismatchedConfigException("Realm at path '%1' already opened with a different schema mode.", config.path); + } + util::CheckedLockGuard lock(m_schema_cache_mutex); + if (config.schema && m_schema_version != ObjectStore::NotVersioned && m_schema_version != config.schema_version) { + throw MismatchedConfigException("Realm at path '%1' already opened with different schema version.", config.path); + } + +#if REALM_ENABLE_SYNC + if (bool(m_config.sync_config) != bool(config.sync_config)) { + throw MismatchedConfigException("Realm at path '%1' already opened with different sync configurations.", config.path); + } + + if (config.sync_config) { + if (m_config.sync_config->user != config.sync_config->user) { + throw MismatchedConfigException("Realm at path '%1' already opened with different sync user.", config.path); + } + if (m_config.sync_config->partition_value != config.sync_config->partition_value) { + throw MismatchedConfigException("Realm at path '%1' already opened with different partition value.", config.path); + } + if (m_config.sync_config->transformer != config.sync_config->transformer) { + throw MismatchedConfigException("Realm at path '%1' already opened with different transformer.", config.path); + } + if (m_config.sync_config->realm_encryption_key != config.sync_config->realm_encryption_key) { + throw MismatchedConfigException("Realm at path '%1' already opened with sync session encryption key.", config.path); + } + } +#endif + // Mixing cached and uncached Realms is allowed + m_config.cache = config.cache; + + // Realm::update_schema() handles complaining about schema mismatches + } +} + +std::shared_ptr RealmCoordinator::get_cached_realm(Realm::Config const& config, std::shared_ptr scheduler) +{ + if (!config.cache) + return nullptr; + util::CheckedUniqueLock lock(m_realm_mutex); + return do_get_cached_realm(config, scheduler); +} + +std::shared_ptr RealmCoordinator::do_get_cached_realm(Realm::Config const& config, std::shared_ptr scheduler) +{ + if (!config.cache) + return nullptr; + + if (!scheduler) { + scheduler = config.scheduler; + } + + if (!scheduler) + return nullptr; + + for (auto& cached_realm : m_weak_realm_notifiers) { + if (!cached_realm.is_cached_for_scheduler(scheduler)) + continue; + // can be null if we jumped in between ref count hitting zero and + // unregister_realm() getting the lock + if (auto realm = cached_realm.realm()) { + // If the file is uninitialized and was opened without a schema, + // do the normal schema init + if (realm->schema_version() == ObjectStore::NotVersioned) + break; + + // Otherwise if we have a realm schema it needs to be an exact + // match (even having the same properties but in different + // orders isn't good enough) + if (config.schema && realm->schema() != *config.schema) + throw MismatchedConfigException("Realm at path '%1' already opened on current thread with different schema.", config.path); + + return realm; + } + } + return nullptr; +} + +std::shared_ptr RealmCoordinator::get_realm(Realm::Config config, util::Optional version) +{ + if (!config.scheduler) + config.scheduler = version ? util::Scheduler::get_frozen(version.value()) : util::Scheduler::make_default(); + // realm must be declared before lock so that the mutex is released before + // we release the strong reference to realm, as Realm's destructor may want + // to acquire the same lock + std::shared_ptr realm; + util::CheckedUniqueLock lock(m_realm_mutex); + set_config(config); + if ((realm = do_get_cached_realm(config))) { + if (version) { + REALM_ASSERT(realm->read_transaction_version() == version.value()); + } + return realm; + } + do_get_realm(std::move(config), realm, version, lock); + return realm; +} + +std::shared_ptr RealmCoordinator::get_realm(std::shared_ptr scheduler) +{ + std::shared_ptr realm; + util::CheckedUniqueLock lock(m_realm_mutex); + auto config = m_config; + config.scheduler = scheduler ? scheduler : util::Scheduler::make_default(); + if ((realm = do_get_cached_realm(config))) { + return realm; + } + do_get_realm(std::move(config), realm, none, lock); + return realm; +} + +ThreadSafeReference RealmCoordinator::get_unbound_realm() +{ + std::shared_ptr realm; + util::CheckedUniqueLock lock(m_realm_mutex); + do_get_realm(m_config, realm, none, lock); + return ThreadSafeReference(realm); +} + +void RealmCoordinator::do_get_realm(Realm::Config config, std::shared_ptr& realm, + util::Optional version, + util::CheckedUniqueLock& realm_lock) +{ + open_db(); + + auto schema = std::move(config.schema); + auto migration_function = std::move(config.migration_function); + auto initialization_function = std::move(config.initialization_function); + auto audit_factory = std::move(config.audit_factory); + config.schema = {}; + + realm = Realm::make_shared_realm(std::move(config), version, shared_from_this()); + if (!m_notifier && !m_config.immutable() && m_config.automatic_change_notifications) { + try { + m_notifier = std::make_unique(*this); + } + catch (std::system_error const& ex) { + throw RealmFileException(RealmFileException::Kind::AccessError, + get_path(), ex.code().message(), ""); + } + } + m_weak_realm_notifiers.emplace_back(realm, config.cache); + + if (realm->config().sync_config) + create_sync_session(false); + + if (!m_audit_context && audit_factory) + m_audit_context = audit_factory(); + + realm_lock.unlock_unchecked(); + if (schema) { + realm->update_schema(std::move(*schema), config.schema_version, std::move(migration_function), + std::move(initialization_function)); + } +} + +void RealmCoordinator::bind_to_context(Realm& realm) +{ + util::CheckedLockGuard lock(m_realm_mutex); + for (auto& cached_realm : m_weak_realm_notifiers) { + if (!cached_realm.is_for_realm(&realm)) + continue; + cached_realm.bind_to_scheduler(); + return; + } + REALM_TERMINATE("Invalid Realm passed to bind_to_context()"); +} + +#if REALM_ENABLE_SYNC +std::shared_ptr RealmCoordinator::get_synchronized_realm(Realm::Config config) +{ + if (!config.sync_config) + throw std::logic_error("This method is only available for fully synchronized Realms."); + + util::CheckedLockGuard lock(m_realm_mutex); + set_config(config); + // FIXME: Re-enable once the server reintroduces support for State Realms. + // bool exists = File::exists(m_config.path); + create_sync_session(false /* exists */); + return std::make_shared(shared_from_this(), m_sync_session); +} + +void RealmCoordinator::create_session(const Realm::Config& config) +{ + REALM_ASSERT(config.sync_config); + util::CheckedLockGuard lock(m_realm_mutex); + set_config(config); + // FIXME: Re-enable once the server reintroduces support for State Realms. + // bool exists = File::exists(m_config.path); + create_sync_session(false /* exists */); +} + +#endif + +namespace realm { +namespace _impl { +REALM_NOINLINE void translate_file_exception(StringData path, bool immutable) +{ + try { + throw; + } + catch (util::File::PermissionDenied const& ex) { + throw RealmFileException(RealmFileException::Kind::PermissionDenied, ex.get_path(), + util::format("Unable to open a realm at path '%1'. Please use a path where your app has %2 permissions.", + ex.get_path(), immutable ? "read" : "read-write"), + ex.what()); + } + catch (util::File::Exists const& ex) { + throw RealmFileException(RealmFileException::Kind::Exists, ex.get_path(), + util::format("File at path '%1' already exists.", ex.get_path()), + ex.what()); + } + catch (util::File::NotFound const& ex) { + throw RealmFileException(RealmFileException::Kind::NotFound, ex.get_path(), + util::format("Directory at path '%1' does not exist.", ex.get_path()), ex.what()); + } + catch (FileFormatUpgradeRequired const& ex) { + throw RealmFileException(RealmFileException::Kind::FormatUpgradeRequired, path, + "The Realm file format must be allowed to be upgraded " + "in order to proceed.", + ex.what()); + } + catch (util::File::AccessError const& ex) { + // Errors for `open()` include the path, but other errors don't. We + // don't want two copies of the path in the error, so strip it out if it + // appears, and then include it in our prefix. + std::string underlying = ex.what(); + RealmFileException::Kind error_kind = RealmFileException::Kind::AccessError; + // FIXME: Replace this with a proper specific exception type once Core adds support for it. + if (underlying == "Bad or incompatible history type") + error_kind = RealmFileException::Kind::BadHistoryError; + auto pos = underlying.find(ex.get_path()); + if (pos != std::string::npos && pos > 0) { + // One extra char at each end for the quotes + underlying.replace(pos - 1, ex.get_path().size() + 2, ""); + } + throw RealmFileException(error_kind, ex.get_path(), + util::format("Unable to open a realm at path '%1': %2.", ex.get_path(), underlying), ex.what()); + } + catch (IncompatibleLockFile const& ex) { + throw RealmFileException(RealmFileException::Kind::IncompatibleLockFile, path, + "Realm file is currently open in another process " + "which cannot share access with this process. " + "All processes sharing a single file must be the same architecture.", + ex.what()); + } + catch (UnsupportedFileFormatVersion const& ex) { + throw RealmFileException(RealmFileException::Kind::FormatUpgradeRequired, path, + util::format("Opening Realm files of format version %1 is not supported by this version of Realm", ex.source_version), + ex.what()); + } +} +} // namespace _impl +} // namespace realm + +void RealmCoordinator::open_db() +{ + if (m_db || m_read_only_group) + return; + + bool server_synchronization_mode = m_config.sync_config || m_config.force_sync_history; + try { + if (m_config.immutable()) { + if (m_config.realm_data.is_null()) { + m_read_only_group = std::make_shared(m_config.path, + m_config.encryption_key.data(), + Group::mode_ReadOnly); + } + else { + // Create in-memory read-only realm from existing buffer (without taking ownership of the buffer) + m_read_only_group = std::make_unique(m_config.realm_data, false); + } + return; + } + + if (server_synchronization_mode) { +#if REALM_ENABLE_SYNC + m_history = sync::make_client_replication(m_config.path); +#else + REALM_TERMINATE("Realm was not built with sync enabled"); +#endif + } + else { + m_history = make_in_realm_history(m_config.path); + } + + DBOptions options; + options.durability = m_config.in_memory + ? DBOptions::Durability::MemOnly + : DBOptions::Durability::Full; + + if (!m_config.fifo_files_fallback_path.empty()) { + options.temp_dir = util::normalize_dir(m_config.fifo_files_fallback_path); + } + options.encryption_key = m_config.encryption_key.data(); + options.allow_file_format_upgrade = !m_config.disable_format_upgrade + && m_config.schema_mode != SchemaMode::ResetFile; + m_db = DB::create(*m_history, options); + } + catch (realm::FileFormatUpgradeRequired const&) { + if (m_config.schema_mode != SchemaMode::ResetFile) { + translate_file_exception(m_config.path, m_config.immutable()); + } + util::File::remove(m_config.path); + return open_db(); + } + catch (UnsupportedFileFormatVersion const&) { + if (m_config.schema_mode != SchemaMode::ResetFile) { + translate_file_exception(m_config.path, m_config.immutable()); + } + util::File::remove(m_config.path); + return open_db(); + } +#if REALM_ENABLE_SYNC + catch (IncompatibleHistories const& ex) { + translate_file_exception(m_config.path, m_config.immutable()); // Throws + } +#endif // REALM_ENABLE_SYNC + catch (...) { + translate_file_exception(m_config.path, m_config.immutable()); + } + + if (!m_config.should_compact_on_launch_function) + return; + + size_t free_space = 0; + size_t used_space = 0; + if (auto tr = m_db->start_write(true)) { + tr->commit(); + m_db->get_stats(free_space, used_space); + } + if (free_space > 0 && m_config.should_compact_on_launch_function(free_space + used_space, used_space)) + m_db->compact(); +} + +void RealmCoordinator::close() +{ + m_db->close(); + m_db = nullptr; +} + +std::shared_ptr RealmCoordinator::begin_read(VersionID version, bool frozen_transaction) +{ + open_db(); + if (m_read_only_group) + return m_read_only_group; + return (frozen_transaction) ? m_db->start_frozen(version) : m_db->start_read(version); +} + +uint64_t RealmCoordinator::get_schema_version() const noexcept +{ + util::CheckedLockGuard lock(m_schema_cache_mutex); + return m_schema_version; +} + +bool RealmCoordinator::get_cached_schema(Schema& schema, uint64_t& schema_version, + uint64_t& transaction) const noexcept +{ + util::CheckedLockGuard lock(m_schema_cache_mutex); + if (!m_cached_schema) + return false; + schema = *m_cached_schema; + schema_version = m_schema_version; + transaction = m_schema_transaction_version_max; + return true; +} + +void RealmCoordinator::cache_schema(Schema const& new_schema, uint64_t new_schema_version, + uint64_t transaction_version) +{ + util::CheckedLockGuard lock(m_schema_cache_mutex); + if (transaction_version < m_schema_transaction_version_max) + return; + if (new_schema.empty() || new_schema_version == ObjectStore::NotVersioned) + return; + + m_cached_schema = new_schema; + m_schema_version = new_schema_version; + m_schema_transaction_version_min = transaction_version; + m_schema_transaction_version_max = transaction_version; +} + +void RealmCoordinator::clear_schema_cache_and_set_schema_version(uint64_t new_schema_version) +{ + util::CheckedLockGuard lock(m_schema_cache_mutex); + m_cached_schema = util::none; + m_schema_version = new_schema_version; +} + +void RealmCoordinator::advance_schema_cache(uint64_t previous, uint64_t next) +{ + util::CheckedLockGuard lock(m_schema_cache_mutex); + if (!m_cached_schema) + return; + REALM_ASSERT(previous <= m_schema_transaction_version_max); + if (next < m_schema_transaction_version_min) + return; + m_schema_transaction_version_min = std::min(previous, m_schema_transaction_version_min); + m_schema_transaction_version_max = std::max(next, m_schema_transaction_version_max); +} + +RealmCoordinator::RealmCoordinator() +{ +} + +RealmCoordinator::~RealmCoordinator() +{ + { + std::lock_guard coordinator_lock(s_coordinator_mutex); + for (auto it = s_coordinators_per_path.begin(); it != s_coordinators_per_path.end(); ) { + if (it->second.expired()) { + it = s_coordinators_per_path.erase(it); + } + else { + ++it; + } + } + } + // Waits for the worker thread to join + m_notifier = nullptr; + + // Ensure the notifiers aren't holding on to Transactions after we destroy + // the History object the DB depends on + // No locking needed here because the worker thread is gone + for (auto& notifier : m_new_notifiers) + notifier->release_data(); + for (auto& notifier : m_notifiers) + notifier->release_data(); +} + +void RealmCoordinator::unregister_realm(Realm* realm) +{ + // Normally results notifiers are cleaned up by the background worker thread + // but if that's disabled we need to ensure that any notifiers from this + // Realm get cleaned up + if (!m_config.automatic_change_notifications) { + util::CheckedLockGuard lock(m_notifier_mutex); + clean_up_dead_notifiers(); + } + { + util::CheckedLockGuard lock(m_realm_mutex); + auto new_end = remove_if(begin(m_weak_realm_notifiers), end(m_weak_realm_notifiers), + [=](auto& notifier) { return notifier.expired() || notifier.is_for_realm(realm); }); + m_weak_realm_notifiers.erase(new_end, end(m_weak_realm_notifiers)); + } +} + +// Thread-safety analsys doesn't reasonably handle calling functions on different +// instances of this type +void RealmCoordinator::clear_cache() NO_THREAD_SAFETY_ANALYSIS +{ + std::vector> realms_to_close; + std::vector> coordinators; + { + std::lock_guard lock(s_coordinator_mutex); + + for (auto& weak_coordinator : s_coordinators_per_path) { + auto coordinator = weak_coordinator.second.lock(); + if (!coordinator) { + continue; + } + coordinators.push_back(coordinator); + + coordinator->m_notifier = nullptr; + + // Gather a list of all of the realms which will be removed + util::CheckedLockGuard lock(coordinator->m_realm_mutex); + for (auto& weak_realm_notifier : coordinator->m_weak_realm_notifiers) { + if (auto realm = weak_realm_notifier.realm()) { + realms_to_close.push_back(realm); + } + } + } + + s_coordinators_per_path.clear(); + } + coordinators.clear(); + + // Close all of the previously cached Realms. This can't be done while + // s_coordinator_mutex is held as it may try to re-lock it. + for (auto& realm : realms_to_close) + realm->close(); +} + +void RealmCoordinator::clear_all_caches() +{ + std::vector> to_clear; + { + std::lock_guard lock(s_coordinator_mutex); + for (auto iter : s_coordinators_per_path) { + to_clear.push_back(iter.second); + } + } + for (auto weak_coordinator : to_clear) { + if (auto coordinator = weak_coordinator.lock()) { + coordinator->clear_cache(); + } + } +} + +void RealmCoordinator::assert_no_open_realms() noexcept +{ +#ifdef REALM_DEBUG + std::lock_guard lock(s_coordinator_mutex); + REALM_ASSERT(s_coordinators_per_path.empty()); +#endif +} + +void RealmCoordinator::wake_up_notifier_worker() +{ + if (m_notifier) { + // FIXME: this wakes up the notification workers for all processes and + // not just us. This might be worth optimizing in the future. + m_notifier->notify_others(); + } +} + +void RealmCoordinator::commit_write(Realm& realm) +{ + REALM_ASSERT(!m_config.immutable()); + REALM_ASSERT(realm.is_in_transaction()); + + Transaction& tr = Realm::Internal::get_transaction(realm); + { + // Need to acquire this lock before committing or another process could + // perform a write and notify us before we get the chance to set the + // skip version + util::CheckedLockGuard l(m_notifier_mutex); + + tr.commit_and_continue_as_read(); + + // Don't need to check m_new_notifiers because those don't skip versions + bool have_notifiers = std::any_of(m_notifiers.begin(), m_notifiers.end(), + [&](auto&& notifier) { return notifier->is_for_realm(realm); }); + if (have_notifiers) { + m_notifier_skip_version = Realm::Internal::get_transaction(realm).get_version_of_current_transaction(); + } + } + +#if REALM_ENABLE_SYNC + // Realm could be closed in did_change. So send sync notification first before did_change. + if (m_sync_session) { + auto version = tr.get_version(); + SyncSession::Internal::nonsync_transact_notify(*m_sync_session, version); + } +#endif + if (realm.m_binding_context) { + realm.m_binding_context->did_change({}, {}); + } + + if (m_notifier) { + m_notifier->notify_others(); + } +} + +void RealmCoordinator::enable_wait_for_change() +{ + m_db->enable_wait_for_change(); +} + +bool RealmCoordinator::wait_for_change(std::shared_ptr tr) +{ + return m_db->wait_for_change(tr); +} + +void RealmCoordinator::wait_for_change_release() +{ + m_db->wait_for_change_release(); +} + +void RealmCoordinator::pin_version(VersionID versionid) +{ + if (m_async_error) + return; + if (!m_advancer_sg || versionid < m_advancer_sg->get_version_of_current_transaction()) + m_advancer_sg = m_db->start_read(versionid); +} + +// Thread-safety analsys doesn't reasonably handle calling functions on different +// instances of this type +void RealmCoordinator::register_notifier(std::shared_ptr notifier) NO_THREAD_SAFETY_ANALYSIS +{ + auto version = notifier->version(); + auto& self = Realm::Internal::get_coordinator(*notifier->get_realm()); + { + util::CheckedLockGuard lock(self.m_notifier_mutex); + self.pin_version(version); + self.m_new_notifiers.push_back(std::move(notifier)); + } +} + +void RealmCoordinator::clean_up_dead_notifiers() +{ + auto swap_remove = [&](auto& container) { + bool did_remove = false; + for (size_t i = 0; i < container.size(); ++i) { + if (container[i]->is_alive()) + continue; + + // Ensure the notifier is destroyed here even if there's lingering refs + // to the async notifier elsewhere + container[i]->release_data(); + + if (container.size() > i + 1) + container[i] = std::move(container.back()); + container.pop_back(); + --i; + did_remove = true; + } + return did_remove; + }; + + if (swap_remove(m_notifiers) && m_notifiers.empty()) { + m_notifier_sg = nullptr; + m_notifier_skip_version = {0, 0}; + } + if (swap_remove(m_new_notifiers) && m_new_notifiers.empty()) { + m_advancer_sg = nullptr; + } +} + +void RealmCoordinator::on_change() +{ + run_async_notifiers(); + + util::CheckedLockGuard lock(m_realm_mutex); + for (auto& realm : m_weak_realm_notifiers) { + realm.notify(); + } +} + +namespace { +class IncrementalChangeInfo { +public: + IncrementalChangeInfo(Transaction& sg, + std::vector>& notifiers) + : m_sg(sg) + { + if (notifiers.empty()) + return; + + auto cmp = [&](auto&& lft, auto&& rgt) { + return lft->version() < rgt->version(); + }; + + // Sort the notifiers by their source version so that we can pull them + // all forward to the latest version in a single pass over the transaction log + std::sort(notifiers.begin(), notifiers.end(), cmp); + + // Preallocate the required amount of space in the vector so that we can + // safely give out pointers to within the vector + size_t count = 1; + for (auto it = notifiers.begin(), next = it + 1; next != notifiers.end(); ++it, ++next) { + if (cmp(*it, *next)) + ++count; + } + m_info.reserve(count); + m_info.resize(1); + m_current = &m_info[0]; + } + + TransactionChangeInfo& current() const { return *m_current; } + + bool advance_incremental(VersionID version) + { + if (version != m_sg.get_version_of_current_transaction()) { + transaction::advance(m_sg, *m_current, version); + m_info.push_back({std::move(m_current->lists)}); + auto next = &m_info.back(); + for (auto& table : m_current->tables) + next->tables[table.first]; + m_current = next; + return true; + } + return false; + } + + void advance_to_final(VersionID version) + { + if (!m_current) { + transaction::advance(m_sg, nullptr, version); + return; + } + + transaction::advance(m_sg, *m_current, version); + + // We now need to combine the transaction change info objects so that all of + // the notifiers see the complete set of changes from their first version to + // the most recent one + for (size_t i = m_info.size() - 1; i > 0; --i) { + auto& cur = m_info[i]; + if (cur.tables.empty()) + continue; + auto& prev = m_info[i - 1]; + if (prev.tables.empty()) { + prev.tables = cur.tables; + continue; + } + for (auto& ct : cur.tables) { + auto& pt = prev.tables[ct.first]; + if (pt.empty()) + pt = ct.second; + else + pt.merge(ObjectChangeSet{ct.second}); + } + } + + // Copy the list change info if there are multiple LinkViews for the same LinkList + auto id = [](auto const& list) { return std::tie(list.table_key, list.col_key, list.row_key); }; + for (size_t i = 1; i < m_current->lists.size(); ++i) { + for (size_t j = i; j > 0; --j) { + if (id(m_current->lists[i]) == id(m_current->lists[j - 1])) { + m_current->lists[j - 1].changes->merge(CollectionChangeBuilder{*m_current->lists[i].changes}); + } + } + } + } + +private: + std::vector m_info; + TransactionChangeInfo* m_current = nullptr; + Transaction& m_sg; +}; +} // anonymous namespace + +void RealmCoordinator::run_async_notifiers() +{ + util::CheckedUniqueLock lock(m_notifier_mutex); + + clean_up_dead_notifiers(); + + if (m_notifiers.empty() && m_new_notifiers.empty()) { + m_notifier_cv.notify_all(); + return; + } + + if (!m_notifier_sg) { + m_notifier_sg = m_db->start_read(); + } + + if (m_async_error) { + std::move(m_new_notifiers.begin(), m_new_notifiers.end(), std::back_inserter(m_notifiers)); + m_new_notifiers.clear(); + m_notifier_cv.notify_all(); + return; + } + + VersionID version; + + // Advance all of the new notifiers to the most recent version, if any + auto new_notifiers = std::move(m_new_notifiers); + IncrementalChangeInfo new_notifier_change_info(*m_advancer_sg, new_notifiers); + auto advancer_sg = std::move(m_advancer_sg); + + if (!new_notifiers.empty()) { + REALM_ASSERT(advancer_sg); + REALM_ASSERT_3(advancer_sg->get_version_of_current_transaction().version, + <=, new_notifiers.front()->version().version); + + // The advancer SG can be at an older version than the oldest new notifier + // if a notifier was added and then removed before it ever got the chance + // to run, as we don't move the pin forward when removing dead notifiers + transaction::advance(*advancer_sg, nullptr, new_notifiers.front()->version()); + + // Advance each of the new notifiers to the latest version, attaching them + // to the SG at their handover version. This requires a unique + // TransactionChangeInfo for each source version, so that things don't + // see changes from before the version they were handed over from. + // Each Info has all of the changes between that source version and the + // next source version, and they'll be merged together later after + // releasing the lock + for (auto& notifier : new_notifiers) { + new_notifier_change_info.advance_incremental(notifier->version()); + notifier->attach_to(advancer_sg); + notifier->add_required_change_info(new_notifier_change_info.current()); + } + new_notifier_change_info.advance_to_final(VersionID{}); + + // We want to advance the non-new notifiers to the same version as the + // new notifiers to avoid having to merge changes from any new + // transaction that happen immediately after this into the new notifier + // changes + version = advancer_sg->get_version_of_current_transaction(); + } + else { + // If we have no new notifiers we want to just advance to the latest + // version, but we have to pick a "latest" version while holding the + // notifier lock to avoid advancing over a transaction which should be + // skipped + // FIXME: this is comically slow + version = m_db->start_read()->get_version_of_current_transaction(); + if (version == m_notifier_sg->get_version_of_current_transaction()) { + // We were spuriously woken up and there isn't actually anything to do + REALM_ASSERT(!m_notifier_skip_version.version); + m_notifier_cv.notify_all(); + return; + } + } + + auto skip_version = m_notifier_skip_version; + m_notifier_skip_version = {0, 0}; + + // Make a copy of the notifiers vector and then release the lock to avoid + // blocking other threads trying to register or unregister notifiers while we run them + decltype(m_notifiers) notifiers; + if (version != m_notifier_sg->get_version_of_current_transaction()) { + // We only want to rerun the existing notifiers if the version has changed. + // This is both a minor optimization and required for notification + // skipping to work. The skip logic assumes that the notifier can't be + // running when suppress_next() is called because it can only be called + // from within a write transaction, and starting the write transaction + // would have blocked until the notifier is done running. However, + // on_change() can be triggered by things other than writes, so we may + // be here even if the notifiers don't need to rerun. + notifiers = m_notifiers; + } + m_notifiers.insert(m_notifiers.end(), new_notifiers.begin(), new_notifiers.end()); + lock.unlock(); + + if (skip_version.version) { + REALM_ASSERT(!notifiers.empty()); + REALM_ASSERT(version >= skip_version); + IncrementalChangeInfo change_info(*m_notifier_sg, notifiers); + for (auto& notifier : notifiers) + notifier->add_required_change_info(change_info.current()); + change_info.advance_to_final(skip_version); + + for (auto& notifier : notifiers) + notifier->run(); + + util::CheckedLockGuard lock(m_notifier_mutex); + for (auto& notifier : notifiers) + notifier->prepare_handover(); + } + + // Advance the non-new notifiers to the same version as we advanced the new + // ones to (or the latest if there were no new ones) + IncrementalChangeInfo change_info(*m_notifier_sg, notifiers); + for (auto& notifier : notifiers) { + notifier->add_required_change_info(change_info.current()); + } + change_info.advance_to_final(version); + + // Attach the new notifiers to the main SG and move them to the main list + for (auto& notifier : new_notifiers) { + notifier->attach_to(m_notifier_sg); + notifier->run(); + } + + // Change info is now all ready, so the notifiers can now perform their + // background work + for (auto& notifier : notifiers) { + notifier->run(); + } + + // Reacquire the lock while updating the fields that are actually read on + // other threads + util::CheckedLockGuard lock2(m_notifier_mutex); + for (auto& notifier : new_notifiers) { + notifier->prepare_handover(); + } + for (auto& notifier : notifiers) { + notifier->prepare_handover(); + } + clean_up_dead_notifiers(); + m_notifier_cv.notify_all(); +} + +bool RealmCoordinator::can_advance(Realm& realm) +{ + bool changes = realm.last_seen_transaction_version() != m_db->get_version_of_latest_snapshot(); + return changes; +} + +void RealmCoordinator::advance_to_ready(Realm& realm) +{ + util::CheckedUniqueLock lock(m_notifier_mutex); + _impl::NotifierPackage notifiers(m_async_error, notifiers_for_realm(realm), this); + lock.unlock(); + notifiers.package_and_wait(util::none); + + // FIXME: we probably won't actually want a strong pointer here + auto sg = Realm::Internal::get_transaction_ref(realm); + if (notifiers) { + auto version = notifiers.version(); + if (version) { + auto current_version = sg->get_version_of_current_transaction(); + // Notifications are out of date, so just discard + // This should only happen if begin_read() was used to change the + // read version outside of our control + if (*version < current_version) + return; + // While there is a newer version, notifications are for the current + // version so just deliver them without advancing + if (*version == current_version) { + if (realm.m_binding_context) + realm.m_binding_context->will_send_notifications(); + notifiers.after_advance(); + if (realm.m_binding_context) + realm.m_binding_context->did_send_notifications(); + return; + } + } + } + + transaction::advance(sg, realm.m_binding_context.get(), notifiers); +} + +std::vector> RealmCoordinator::notifiers_for_realm(Realm& realm) +{ + std::vector> ret; + for (auto& notifier : m_new_notifiers) { + if (notifier->is_for_realm(realm)) + ret.push_back(notifier); + } + for (auto& notifier : m_notifiers) { + if (notifier->is_for_realm(realm)) + ret.push_back(notifier); + } + return ret; +} + +bool RealmCoordinator::advance_to_latest(Realm& realm) +{ + // FIXME: we probably won't actually want a strong pointer here + auto self = shared_from_this(); + auto sg = Realm::Internal::get_transaction_ref(realm); + util::CheckedUniqueLock lock(m_notifier_mutex); + _impl::NotifierPackage notifiers(m_async_error, notifiers_for_realm(realm), this); + lock.unlock(); + notifiers.package_and_wait(sg->get_version_of_latest_snapshot()); + + auto version = sg->get_version_of_current_transaction(); + transaction::advance(sg, realm.m_binding_context.get(), notifiers); + + // Realm could be closed in the callbacks. + if (realm.is_closed()) + return false; + + return version != sg->get_version_of_current_transaction(); +} + +void RealmCoordinator::promote_to_write(Realm& realm) +{ + REALM_ASSERT(!realm.is_in_transaction()); + + util::CheckedUniqueLock lock(m_notifier_mutex); + _impl::NotifierPackage notifiers(m_async_error, notifiers_for_realm(realm), this); + lock.unlock(); + + // FIXME: we probably won't actually want a strong pointer here + auto tr = Realm::Internal::get_transaction_ref(realm); + transaction::begin(tr, realm.m_binding_context.get(), notifiers); +} + +void RealmCoordinator::process_available_async(Realm& realm) +{ + REALM_ASSERT(!realm.is_in_transaction()); + + util::CheckedUniqueLock lock(m_notifier_mutex); + auto notifiers = notifiers_for_realm(realm); + if (notifiers.empty()) + return; + + if (auto error = m_async_error) { + lock.unlock(); + if (realm.m_binding_context) + realm.m_binding_context->will_send_notifications(); + for (auto& notifier : notifiers) + notifier->deliver_error(m_async_error); + if (realm.m_binding_context) + realm.m_binding_context->did_send_notifications(); + return; + } + + bool in_read = realm.is_in_read_transaction(); + auto& sg = Realm::Internal::get_transaction(realm); + auto version = sg.get_version_of_current_transaction(); + auto package = [&](auto& notifier) { + return !(notifier->has_run() && (!in_read || notifier->version() == version) && notifier->package_for_delivery()); + }; + notifiers.erase(std::remove_if(begin(notifiers), end(notifiers), package), end(notifiers)); + if (notifiers.empty()) + return; + lock.unlock(); + + // no before advance because the Realm is already at the given version, + // because we're either sending initial notifications or the write was + // done on this Realm instance + + if (realm.m_binding_context) { + realm.m_binding_context->will_send_notifications(); + if (realm.is_closed()) // i.e. the Realm was closed in the callback above + return; + } + + for (auto& notifier : notifiers) + notifier->after_advance(); + + if (realm.m_binding_context) + realm.m_binding_context->did_send_notifications(); +} + +void RealmCoordinator::set_transaction_callback(std::function fn) +{ + create_sync_session(false); + util::CheckedLockGuard lock(m_transaction_callback_mutex); + m_transaction_callback = std::move(fn); +} + +bool RealmCoordinator::compact() +{ + return m_db->compact(); +} diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/impl/results_notifier.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/impl/results_notifier.cpp new file mode 100644 index 0000000..8b7757e --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/impl/results_notifier.cpp @@ -0,0 +1,364 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// 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 "impl/results_notifier.hpp" + +#include "shared_realm.hpp" + +#include + +using namespace realm; +using namespace realm::_impl; + +// Some of the inter-thread synchronization for this class is handled externally +// by RealmCoordinator using the "notifier lock" which also guards registering +// and unregistering notifiers. This can make it somewhat difficult to tell what +// can safely be accessed where. +// +// The data flow is: +// - ResultsNotifier is created on target thread. +// - On background worker thread: +// * do_attach_to() called with notifier lock held +// - Writes to m_query +// * do_add_required_change_info() called with notifier lock held +// - Writes to m_info +// * run() called with no locks held +// - Reads m_query +// - Reads m_info +// - Reads m_need_to_run <-- FIXME: data race? +// - Writes m_run_tv +// * do_prepare_handover() called with notifier lock held +// - Reads m_run_tv +// - Writes m_handover_transaction +// - Writes m_handover_tv +// - On target thread: +// * prepare_to_deliver() called with notifier lock held +// - Reads m_handover_transaction +// - Reads m_handover_tv +// - Writes m_deliver_transaction +// - Writes m_deliver_handover +// * get_tableview() called with no locks held +// - Reads m_deliver_transaction +// - Reads m_deliver_handover +// - Reads m_results_were_used + +ResultsNotifier::ResultsNotifier(Results& target) +: ResultsNotifierBase(target.get_realm()) +, m_query(std::make_unique(target.get_query())) +, m_descriptor_ordering(target.get_descriptor_ordering()) +, m_target_is_in_table_order(target.is_in_table_order()) +{ + auto table = m_query->get_table(); + if (table) { + set_table(table); + } +} + +void ResultsNotifier::release_data() noexcept +{ + m_query = {}; + m_run_tv = {}; + m_handover_tv = {}; + m_handover_transaction = {}; + m_delivered_tv = {}; + m_delivered_transaction = {}; + CollectionNotifier::release_data(); +} + +bool ResultsNotifier::get_tableview(TableView& out) +{ + if (!m_delivered_tv) + return false; + auto& transaction = source_shared_group(); + if (transaction.get_transact_stage() != DB::transact_Reading) + return false; + if (m_delivered_transaction->get_version_of_current_transaction() != transaction.get_version_of_current_transaction()) + return false; + + out = std::move(*transaction.import_copy_of(*m_delivered_tv, PayloadPolicy::Move)); + m_delivered_tv.reset(); + return true; +} + +bool ResultsNotifier::do_add_required_change_info(TransactionChangeInfo& info) +{ + m_info = &info; + return m_query->get_table() && has_run() && have_callbacks(); +} + +bool ResultsNotifier::need_to_run() +{ + REALM_ASSERT(m_info); + + { + auto lock = lock_target(); + // Don't run the query if the results aren't actually going to be used + if (!get_realm() || (!have_callbacks() && !m_results_were_used)) + return false; + } + + // If we've run previously, check if we need to rerun + if (has_run() && m_query->sync_view_if_needed() == m_last_seen_version) { + // Does m_last_seen_version match m_related_tables + if (all_related_tables_covered(m_last_seen_version)) { + return false; + } + } + return true; +} + +void ResultsNotifier::calculate_changes() +{ + if (has_run() && have_callbacks()) { + std::vector next_rows; + next_rows.reserve(m_run_tv.size()); + for (size_t i = 0; i < m_run_tv.size(); ++i) + next_rows.push_back(m_run_tv.get_key(i).value); + + m_change = CollectionChangeBuilder::calculate(m_previous_rows, next_rows, + get_modification_checker(*m_info, m_query->get_table()), + m_target_is_in_table_order); + + m_previous_rows = std::move(next_rows); + } + else { + m_previous_rows.resize(m_run_tv.size()); + for (size_t i = 0; i < m_run_tv.size(); ++i) + m_previous_rows[i] = m_run_tv.get_key(i).value; + } +} + +void ResultsNotifier::run() +{ + // Table's been deleted, so report all rows as deleted + if (!m_query->get_table()) { + m_change = {}; + m_change.deletions.set(m_previous_rows.size()); + m_previous_rows.clear(); + return; + } + + if (!need_to_run()) + return; + + m_query->sync_view_if_needed(); + m_run_tv = m_query->find_all(); + m_run_tv.apply_descriptor_ordering(m_descriptor_ordering); + m_run_tv.sync_if_needed(); + m_last_seen_version = m_run_tv.ObjList::get_dependency_versions(); + + calculate_changes(); +} + +void ResultsNotifier::do_prepare_handover(Transaction& sg) +{ + m_handover_tv.reset(); + if (m_handover_transaction) + m_handover_transaction->advance_read(sg.get_version_of_current_transaction()); + + if (m_run_tv.is_attached()) { + REALM_ASSERT(m_run_tv.is_in_sync()); + if (!m_handover_transaction) + m_handover_transaction = sg.duplicate(); + m_handover_tv = m_run_tv.clone_for_handover(m_handover_transaction.get(), PayloadPolicy::Move); + m_run_tv = {}; + } +} + +bool ResultsNotifier::prepare_to_deliver() +{ + auto lock = lock_target(); + auto realm = get_realm(); + if (!realm) { + m_handover_tv.reset(); + m_delivered_tv.reset(); + return false; + } + if (!m_handover_tv) { + bool transaction_is_stale = m_delivered_transaction && + (!realm->is_in_read_transaction() || realm->read_transaction_version() > m_delivered_transaction->get_version_of_current_transaction()); + if (transaction_is_stale) { + m_delivered_tv.reset(); + m_delivered_transaction.reset(); + } + return true; + } + + m_results_were_used = !m_delivered_tv; + m_delivered_tv.reset(); + if (m_delivered_transaction) + m_delivered_transaction->advance_read(m_handover_transaction->get_version_of_current_transaction()); + else + m_delivered_transaction = m_handover_transaction->duplicate(); + m_delivered_tv = m_delivered_transaction->import_copy_of(*m_handover_tv, PayloadPolicy::Move); + m_handover_tv.reset(); + + return true; +} + +void ResultsNotifier::do_attach_to(Transaction& sg) +{ + if (m_query->get_table()) + m_query = sg.import_copy_of(*m_query, PayloadPolicy::Move); +} + +ListResultsNotifier::ListResultsNotifier(Results& target) +: ResultsNotifierBase(target.get_realm()) +, m_list(target.get_list()) +{ + auto& ordering = target.get_descriptor_ordering(); + for (size_t i = 0, sz = ordering.size(); i < sz; i++) { + auto descr = ordering[i]; + if (descr->get_type() == DescriptorType::Sort) + m_sort_order = static_cast(descr)->is_ascending(0); + if (descr->get_type() == DescriptorType::Distinct) + m_distinct = true; + } + +} + +void ListResultsNotifier::release_data() noexcept +{ + m_list = {}; + CollectionNotifier::release_data(); +} + +bool ListResultsNotifier::get_list_indices(ListIndices& out) +{ + if (!m_delivered_indices) + return false; + auto& transaction = source_shared_group(); + if (m_delivered_transaction_version != transaction.get_version_of_current_transaction()) + return false; + + out = std::move(m_delivered_indices); + m_delivered_indices = util::none; + return true; +} + +bool ListResultsNotifier::do_add_required_change_info(TransactionChangeInfo& info) +{ + if (!m_list->is_attached()) + return false; // origin row was deleted after the notification was added + + info.lists.push_back({m_list->get_table()->get_key(), m_list->get_key().value, + m_list->get_col_key().value, &m_change}); + + m_info = &info; + return true; +} + +bool ListResultsNotifier::need_to_run() +{ + REALM_ASSERT(m_info); + + { + auto lock = lock_target(); + // Don't run the query if the results aren't actually going to be used + if (!get_realm() || (!have_callbacks() && !m_results_were_used)) + return false; + } + + return !has_run() || m_list->has_changed(); +} + +void ListResultsNotifier::calculate_changes() +{ + // Unsorted lists can just forward the changeset directly from the + // transaction log parsing, but sorted lists need to perform diffing + if (has_run() && have_callbacks() && (m_sort_order || m_distinct)) { + // Update each of the row indices in m_previous_indices to the equivalent + // new index in the new list + if (!m_change.insertions.empty() || !m_change.deletions.empty()) { + for (auto& row : m_previous_indices) { + if (m_change.deletions.contains(row)) + row = npos; + else + row = m_change.insertions.shift(m_change.deletions.unshift(row)); + } + } + + m_change = CollectionChangeBuilder::calculate(m_previous_indices, *m_run_indices, + [=](int64_t key) { + return m_change.modifications_new.contains(static_cast(key)); + }); + } + + m_previous_indices = *m_run_indices; +} + +void ListResultsNotifier::run() +{ + if (!m_list->is_attached()) { + // List was deleted, so report all of the rows being removed + m_change = {}; + m_change.deletions.set(m_previous_indices.size()); + m_previous_indices.clear(); + return; + } + + if (!need_to_run()) + return; + + m_run_indices = std::vector(); + if (m_distinct) + m_list->distinct(*m_run_indices, m_sort_order); + else if (m_sort_order) + m_list->sort(*m_run_indices, *m_sort_order); + else { + m_run_indices->resize(m_list->size()); + std::iota(m_run_indices->begin(), m_run_indices->end(), 0); + } + + calculate_changes(); +} + +void ListResultsNotifier::do_prepare_handover(Transaction& sg) +{ + if (m_run_indices) { + m_handover_indices = std::move(m_run_indices); + m_run_indices = {}; + } + else { + m_handover_indices = {}; + } + m_handover_transaction_version = sg.get_version_of_current_transaction(); +} + +bool ListResultsNotifier::prepare_to_deliver() +{ + auto lock = lock_target(); + if (!get_realm()) { + return false; + } + if (!m_handover_indices) + return true; + + m_results_were_used = !m_delivered_indices; + m_delivered_indices = std::move(m_handover_indices); + m_delivered_transaction_version = m_handover_transaction_version; + m_handover_indices = {}; + + return true; +} + +void ListResultsNotifier::do_attach_to(Transaction& sg) +{ + if (m_list->is_attached()) + m_list = sg.import_copy_of(*m_list); +} diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/impl/transact_log_handler.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/impl/transact_log_handler.cpp new file mode 100644 index 0000000..918326f --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/impl/transact_log_handler.cpp @@ -0,0 +1,564 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// 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 "impl/transact_log_handler.hpp" + +#include "binding_context.hpp" +#include "impl/collection_notifier.hpp" +#include "index_set.hpp" +#include "shared_realm.hpp" + +#include + +#include +#include + +using namespace realm; + +namespace { + +class KVOAdapter : public _impl::TransactionChangeInfo { +public: + KVOAdapter(std::vector& observers, BindingContext* context); + + void before(Transaction& sg); + void after(Transaction& sg); + +private: + BindingContext* m_context; + std::vector& m_observers; + std::vector m_invalidated; + + struct ListInfo { + BindingContext::ObserverState* observer; + _impl::CollectionChangeBuilder builder; + ColKey col; + }; + std::vector m_lists; + VersionID m_version; +}; + +KVOAdapter::KVOAdapter(std::vector& observers, BindingContext* context) +: _impl::TransactionChangeInfo{} +, m_context(context) +, m_observers(observers) +{ + if (m_observers.empty()) + return; + + std::vector tables_needed; + for (auto& observer : observers) { + tables_needed.push_back(observer.table_key); + } + std::sort(begin(tables_needed), end(tables_needed)); + tables_needed.erase(std::unique(begin(tables_needed), end(tables_needed)), + end(tables_needed)); + + auto realm = context->realm.lock(); + auto& group = realm->read_group(); + for (auto& observer : observers) { + auto table = group.get_table(TableKey(observer.table_key)); + for (auto key : table->get_column_keys()) { + if (table->get_column_attr(key).test(col_attr_List)) + m_lists.push_back({&observer, {}, key}); + } + } + + tables.reserve(tables_needed.size()); + for (auto& tbl : tables_needed) + tables[tbl.value] = {}; + for (auto& list : m_lists) + lists.push_back({list.observer->table_key, + list.observer->obj_key, list.col.value, &list.builder}); +} + +void KVOAdapter::before(Transaction& sg) +{ + if (!m_context) + return; + + m_version = sg.get_version_of_current_transaction(); + if (tables.empty()) + return; + + for (auto& observer : m_observers) { + auto it = tables.find(observer.table_key.value); + if (it == tables.end()) + continue; + + auto const& table = it->second; + auto key = observer.obj_key; + if (table.deletions_contains(key)) { + m_invalidated.push_back(observer.info); + continue; + } + auto column_modifications = table.get_columns_modified(key); + if (column_modifications) { + for (auto col : *column_modifications) { + observer.changes[col].kind = BindingContext::ColumnInfo::Kind::Set; + } + } + } + + for (auto& list : m_lists) { + if (list.builder.empty()) { + // We may have pre-emptively marked the column as modified if the + // LinkList was selected but the actual changes made ended up being + // a no-op + list.observer->changes.erase(list.col.value); + continue; + } + // If the containing row was deleted then changes will be empty + if (list.observer->changes.empty()) { + REALM_ASSERT_DEBUG(tables[list.observer->table_key.value].deletions_contains(list.observer->obj_key)); + continue; + } + // otherwise the column should have been marked as modified + auto it = list.observer->changes.find(list.col.value); + REALM_ASSERT(it != list.observer->changes.end()); + auto& builder = list.builder; + auto& changes = it->second; + + builder.modifications.remove(builder.insertions); + + // KVO can't express moves (becaue NSArray doesn't have them), so + // transform them into a series of sets on each affected index when possible + if (!builder.moves.empty() && builder.insertions.count() == builder.moves.size() && builder.deletions.count() == builder.moves.size()) { + changes.kind = BindingContext::ColumnInfo::Kind::Set; + changes.indices = builder.modifications; + changes.indices.add(builder.deletions); + + // Iterate over each of the rows which may have been shifted by + // the moves and check if it actually has been, or if it's ended + // up in the same place as it started (either because the moves were + // actually a swap that doesn't effect the rows in between, or the + // combination of moves happen to leave some intermediate rows in + // the same place) + auto in_range = [](auto& it, auto end, size_t i) { + if (it != end && i >= it->second) + ++it; + return it != end && i >= it->first && i < it->second; + }; + + auto del_it = builder.deletions.begin(), del_end = builder.deletions.end(); + auto ins_it = builder.insertions.begin(), ins_end = builder.insertions.end(); + size_t start = std::min(ins_it->first, del_it->first); + size_t end = std::max(std::prev(ins_end)->second, std::prev(del_end)->second); + ptrdiff_t shift = 0; + for (size_t i = start; i < end; ++i) { + if (in_range(del_it, del_end, i)) + --shift; + else if (in_range(ins_it, ins_end, i + shift)) + ++shift; + if (shift != 0) + changes.indices.add(i); + } + } + // KVO can't express multiple types of changes at once + else if (builder.insertions.empty() + builder.modifications.empty() + builder.deletions.empty() < 2) { + changes.kind = BindingContext::ColumnInfo::Kind::SetAll; + } + else if (!builder.insertions.empty()) { + changes.kind = BindingContext::ColumnInfo::Kind::Insert; + changes.indices = builder.insertions; + } + else if (!builder.modifications.empty()) { + changes.kind = BindingContext::ColumnInfo::Kind::Set; + changes.indices = builder.modifications; + } + else { + REALM_ASSERT(!builder.deletions.empty()); + changes.kind = BindingContext::ColumnInfo::Kind::Remove; + changes.indices = builder.deletions; + } + } + m_context->will_change(m_observers, m_invalidated); +} + +void KVOAdapter::after(Transaction& sg) +{ + if (!m_context) + return; + m_context->did_change(m_observers, m_invalidated, + m_version != VersionID{} && + m_version != sg.get_version_of_current_transaction()); +} + +class TransactLogValidationMixin { + // The currently selected table + TableKey m_current_table; + + REALM_NORETURN + REALM_NOINLINE + void schema_error() + { + throw _impl::UnsupportedSchemaChange(); + } + +protected: + TableKey current_table() const noexcept { return m_current_table; } + +public: + + bool select_table(TableKey key) noexcept + { + m_current_table = key; + return true; + } + + // Removing or renaming things while a Realm is open is never supported + bool erase_group_level_table(TableKey) { schema_error(); } + bool rename_group_level_table(TableKey) { schema_error(); } + bool erase_column(ColKey) { schema_error(); } + bool rename_column(ColKey) { schema_error(); } + + // Additive changes and reorderings are supported + bool insert_group_level_table(TableKey) { return true; } + bool insert_column(ColKey) { return true; } + bool set_link_type(ColKey) { return true; } + + // Non-schema changes are all allowed + void parse_complete() { } + bool create_object(ObjKey) { return true; } + bool remove_object(ObjKey) { return true; } + bool clear_table(size_t=0) noexcept { return true; } + bool list_set(size_t) { return true; } + bool list_insert(size_t) { return true; } + bool list_erase(size_t) { return true; } + bool list_clear(size_t) { return true; } + bool list_move(size_t, size_t) { return true; } + bool list_swap(size_t, size_t) { return true; } +}; + + +// A transaction log handler that just validates that all operations made are +// ones supported by the object store +struct TransactLogValidator : public TransactLogValidationMixin { + bool modify_object(ColKey, ObjKey) { return true; } + bool select_list(ColKey, ObjKey) { return true; } +}; + +// Extends TransactLogValidator to track changes made to LinkViews +class TransactLogObserver : public TransactLogValidationMixin { + _impl::TransactionChangeInfo& m_info; + _impl::CollectionChangeBuilder* m_active_list = nullptr; + ObjectChangeSet* m_active_table = nullptr; + + _impl::CollectionChangeBuilder* find_list(ObjKey obj, ColKey col) + { + // When there are multiple source versions there could be multiple + // change objects for a single LinkView, in which case we need to use + // the last one + auto table = current_table(); + for (auto it = m_info.lists.rbegin(), end = m_info.lists.rend(); it != end; ++it) { + if (it->table_key == table && it->row_key == obj.value && it->col_key == col.value) + return it->changes; + } + return nullptr; + } + +public: + TransactLogObserver(_impl::TransactionChangeInfo& info) + : m_info(info) { } + + void parse_complete() + { + for (auto& list : m_info.lists) + list.changes->clean_up_stale_moves(); + for (auto it = m_info.tables.begin(); it != m_info.tables.end(); ) { + if (it->second.empty()) + it = m_info.tables.erase(it); + else + ++it; + } + } + + bool select_table(TableKey key) noexcept + { + TransactLogValidationMixin::select_table(key); + + TableKey table_key = current_table(); + if (m_info.track_all) + m_active_table = &m_info.tables[table_key.value]; + else { + auto it = m_info.tables.find(table_key.value); + if (it == m_info.tables.end()) + m_active_table = nullptr; + else + m_active_table = &it->second; + } + return true; + } + + bool select_list(ColKey col, ObjKey obj) + { + modify_object(col, obj); + m_active_list = find_list(obj, col); + return true; + } + + bool list_set(size_t index) + { + if (m_active_list) + m_active_list->modify(index); + return true; + } + + bool list_insert(size_t index) + { + if (m_active_list) + m_active_list->insert(index); + return true; + } + + bool list_erase(size_t index) + { + if (m_active_list) + m_active_list->erase(index); + return true; + } + + bool list_swap(size_t index1, size_t index2) + { + if (m_active_list) { + if (index1 > index2) + std::swap(index1, index2); + m_active_list->move(index1, index2); + if (index1 + 1 != index2) + m_active_list->move(index2 - 1, index1); + } + return true; + } + + bool list_clear(size_t old_size) + { + if (m_active_list) + m_active_list->clear(old_size); + return true; + } + + bool list_move(size_t from, size_t to) + { + if (m_active_list) + m_active_list->move(from, to); + return true; + } + + bool create_object(ObjKey key) + { + if (m_active_table) + m_active_table->insertions_add(key.value); + return true; + } + + bool remove_object(ObjKey key) + { + if (!m_active_table) + return true; + if (!m_active_table->insertions_remove(key.value)) + m_active_table->deletions_add(key.value); + m_active_table->modifications_remove(key.value); + + for (size_t i = 0; i < m_info.lists.size(); ++i) { + auto& list = m_info.lists[i]; + if (list.table_key != current_table()) + continue; + if (list.row_key == key.value) { + if (i + 1 < m_info.lists.size()) + m_info.lists[i] = std::move(m_info.lists.back()); + m_info.lists.pop_back(); + continue; + } + } + + return true; + } + + bool modify_object(ColKey col, ObjKey key) + { + if (m_active_table) + m_active_table->modifications_add(key.value, col.value); + return true; + } + + bool clear_table(size_t old_size) + { + auto cur_table = current_table(); + if (m_active_table) + m_active_table->clear(old_size); + auto it = remove_if(begin(m_info.lists), end(m_info.lists), + [&](auto const& lv) { return lv.table_key == cur_table; }); + m_info.lists.erase(it, end(m_info.lists)); + return true; + } + + bool insert_column(ColKey) + { + m_info.schema_changed = true; + return true; + } + + bool insert_group_level_table(TableKey) + { + m_info.schema_changed = true; + return true; + } +}; + +class KVOTransactLogObserver : public TransactLogObserver { + KVOAdapter m_adapter; + _impl::NotifierPackage& m_notifiers; + Transaction& m_sg; + +public: + KVOTransactLogObserver(std::vector& observers, + BindingContext* context, + _impl::NotifierPackage& notifiers, + Transaction& sg) + : TransactLogObserver(m_adapter) + , m_adapter(observers, context) + , m_notifiers(notifiers) + , m_sg(sg) + { + } + + ~KVOTransactLogObserver() + { + m_adapter.after(m_sg); + } + + void parse_complete() + { + TransactLogObserver::parse_complete(); + m_adapter.before(m_sg); + + m_notifiers.package_and_wait(m_sg.get_version_of_latest_snapshot()); + m_notifiers.before_advance(); + } +}; + +template +void advance_with_notifications(BindingContext* context, + const std::shared_ptr& sg, + Func&& func, _impl::NotifierPackage& notifiers) +{ + auto old_version = sg->get_version_of_current_transaction(); + std::vector observers; + if (context) { + observers = context->get_observed_rows(); + } + + // Advancing to the latest version with notifiers requires using the full + // transaction log observer so that we have a point where we know what + // version we're going to before we actually advance to that version + if (observers.empty() && (!notifiers || notifiers.version())) { + notifiers.before_advance(); + TransactLogValidator validator; + func(&validator); + auto new_version = sg->get_version_of_current_transaction(); + if (context && old_version != new_version) + context->did_change({}, {}); + // did_change() could close the Realm. Just return if it does. + if (sg->get_transact_stage() == DB::transact_Ready) + return; + if (context) + context->will_send_notifications(); + // will_send_notifications() could close the Realm. Just return if it does. + if (sg->get_transact_stage() == DB::transact_Ready) + return; + notifiers.after_advance(); + if (sg->get_transact_stage() == DB::transact_Ready) + return; + if (context) + context->did_send_notifications(); + return; + } + + if (context) + context->will_send_notifications(); + { + KVOTransactLogObserver observer(observers, context, notifiers, *sg); + func(&observer); + } + notifiers.package_and_wait(sg->get_version_of_current_transaction().version); // is a no-op if parse_complete() was called + notifiers.after_advance(); + if (context) + context->did_send_notifications(); +} + +} // anonymous namespace + +namespace realm { +namespace _impl { + +UnsupportedSchemaChange::UnsupportedSchemaChange() +: std::logic_error("Schema mismatch detected: another process has modified the Realm file's schema in an incompatible way") +{ +} + +namespace transaction { +void advance(Transaction& tr, BindingContext*, VersionID version) +{ + TransactLogValidator validator; + tr.advance_read(&validator, version); +} + +void advance(const std::shared_ptr& tr, BindingContext* context, NotifierPackage& notifiers) +{ + advance_with_notifications(context, tr, [&](auto&&... args) { + tr->advance_read(std::move(args)..., notifiers.version().value_or(VersionID{})); + }, notifiers); +} + +void begin(const std::shared_ptr& tr, BindingContext* context, NotifierPackage& notifiers) +{ + advance_with_notifications(context, tr, [&](auto&&... args) { + tr->promote_to_write(std::move(args)...); + }, notifiers); +} + +void cancel(Transaction& tr, BindingContext* context) +{ + std::vector observers; + if (context) { + observers = context->get_observed_rows(); + } + if (observers.empty()) { + tr.rollback_and_continue_as_read(); + return; + } + + _impl::NotifierPackage notifiers; + KVOTransactLogObserver o(observers, context, notifiers, tr); + tr.rollback_and_continue_as_read(&o); +} + +void advance(Transaction& tr, TransactionChangeInfo& info, VersionID version) +{ + if (!info.track_all && info.tables.empty() && info.lists.empty()) { + tr.advance_read(version); + } + else { + TransactLogObserver o(info); + tr.advance_read(&o, version); + } +} + +} // namespace transaction +} // namespace _impl +} // namespace realm diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/impl/weak_realm_notifier.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/impl/weak_realm_notifier.cpp new file mode 100644 index 0000000..f421f8d --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/impl/weak_realm_notifier.cpp @@ -0,0 +1,65 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// 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 "impl/weak_realm_notifier.hpp" + +#include "shared_realm.hpp" +#include "util/scheduler.hpp" + +using namespace realm; +using namespace realm::_impl; + + +WeakRealmNotifier::WeakRealmNotifier(const std::shared_ptr& realm, bool cache) +: m_realm(realm) +, m_realm_key(realm.get()) +, m_cache(cache) +{ + bind_to_scheduler(); +} + +WeakRealmNotifier::~WeakRealmNotifier() = default; + +void WeakRealmNotifier::notify() +{ + if (m_scheduler) + m_scheduler->notify(); +} + +void WeakRealmNotifier::bind_to_scheduler() +{ + REALM_ASSERT(!m_scheduler); + m_scheduler = realm()->scheduler(); + if (m_scheduler) { + m_scheduler->set_notify_callback([weak_realm = m_realm] { + if (auto realm = weak_realm.lock()) { + realm->notify(); + } + }); + } +} + +bool WeakRealmNotifier::is_cached_for_scheduler(std::shared_ptr scheduler) const +{ + return m_cache && (m_scheduler && scheduler) && (m_scheduler->is_same_as(scheduler.get())); +} + +bool WeakRealmNotifier::scheduler_is_on_thread() const +{ + return m_scheduler && m_scheduler->is_on_thread(); +} diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/index_set.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/index_set.cpp new file mode 100644 index 0000000..e1a3b10 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/index_set.cpp @@ -0,0 +1,707 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// 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 "index_set.hpp" + +#include + +#include + +using namespace realm; +using namespace realm::_impl; + +const size_t IndexSet::npos; + +template +void MutableChunkedRangeVectorIterator::set(size_t front, size_t back) +{ + this->m_outer->count -= this->m_inner->second - this->m_inner->first; + if (this->offset() == 0) { + this->m_outer->begin = front; + } + if (this->m_inner == &this->m_outer->data.back()) { + this->m_outer->end = back; + } + this->m_outer->count += back - front; + this->m_inner->first = front; + this->m_inner->second = back; +} + +template +void MutableChunkedRangeVectorIterator::adjust(ptrdiff_t front, ptrdiff_t back) +{ + if (this->offset() == 0) { + this->m_outer->begin += front; + } + if (this->m_inner == &this->m_outer->data.back()) { + this->m_outer->end += back; + } + this->m_outer->count += -front + back; + this->m_inner->first += front; + this->m_inner->second += back; +} + +template +void MutableChunkedRangeVectorIterator::shift(ptrdiff_t distance) +{ + if (this->offset() == 0) { + this->m_outer->begin += distance; + } + if (this->m_inner == &this->m_outer->data.back()) { + this->m_outer->end += distance; + } + this->m_inner->first += distance; + this->m_inner->second += distance; +} + +void ChunkedRangeVector::push_back(value_type value) +{ + if (!empty() && m_data.back().data.size() < max_size) { + auto& range = m_data.back(); + REALM_ASSERT(range.end <= value.first); + + range.data.push_back(value); + range.count += value.second - value.first; + range.end = value.second; + } + else { + m_data.push_back({{value}, value.first, value.second, value.second - value.first}); + } + verify(); +} + +ChunkedRangeVector::iterator ChunkedRangeVector::insert(iterator pos, value_type value) +{ + if (pos.m_outer == m_data.end()) { + push_back(std::move(value)); + return std::prev(end()); + } + + pos = ensure_space(pos); + auto& chunk = *pos.m_outer; + pos.m_inner = &*chunk.data.insert(pos.m_outer->data.begin() + pos.offset(), value); + chunk.count += value.second - value.first; + chunk.begin = std::min(chunk.begin, value.first); + chunk.end = std::max(chunk.end, value.second); + + verify(); + return pos; +} + +ChunkedRangeVector::iterator ChunkedRangeVector::ensure_space(iterator pos) +{ + if (pos.m_outer->data.size() + 1 <= max_size) + return pos; + + auto offset = pos.offset(); + + // Split the chunk in half to make space for the new insertion + auto new_pos = m_data.insert(pos.m_outer + 1, Chunk{}); + auto prev = new_pos - 1; + auto to_move = max_size / 2; + new_pos->data.reserve(to_move); + new_pos->data.assign(prev->data.end() - to_move, prev->data.end()); + prev->data.resize(prev->data.size() - to_move); + + size_t moved_count = 0; + for (auto range : new_pos->data) + moved_count += range.second - range.first; + + prev->end = prev->data.back().second; + prev->count -= moved_count; + new_pos->begin = new_pos->data.front().first; + new_pos->end = new_pos->data.back().second; + new_pos->count = moved_count; + + if (offset >= to_move) { + pos.m_outer = new_pos; + offset -= to_move; + } + else { + pos.m_outer = prev; + } + pos.m_end = m_data.end(); + pos.m_inner = &pos.m_outer->data[offset]; + verify(); + return pos; +} + +ChunkedRangeVector::iterator ChunkedRangeVector::erase(iterator pos) noexcept +{ + auto offset = pos.offset(); + auto& chunk = *pos.m_outer; + chunk.count -= pos->second - pos->first; + chunk.data.erase(chunk.data.begin() + offset); + + if (chunk.data.size() == 0) { + pos.m_outer = m_data.erase(pos.m_outer); + pos.m_end = m_data.end(); + pos.m_inner = pos.m_outer == m_data.end() ? nullptr : &pos.m_outer->data.front(); + verify(); + return pos; + } + + chunk.begin = chunk.data.front().first; + chunk.end = chunk.data.back().second; + if (offset < chunk.data.size()) + pos.m_inner = &chunk.data[offset]; + else { + ++pos.m_outer; + pos.m_inner = pos.m_outer == pos.m_end ? nullptr : &pos.m_outer->data.front(); + } + + verify(); + return pos; +} + +void ChunkedRangeVector::verify() const noexcept +{ +#ifdef REALM_DEBUG + size_t prev_end = -1; + for (auto range : *this) { + REALM_ASSERT(range.first < range.second); + REALM_ASSERT(prev_end == size_t(-1) || range.first > prev_end); + prev_end = range.second; + } + + for (auto& chunk : m_data) { + REALM_ASSERT(!chunk.data.empty()); + REALM_ASSERT(chunk.data.front().first == chunk.begin); + REALM_ASSERT(chunk.data.back().second == chunk.end); + REALM_ASSERT(chunk.count <= chunk.end - chunk.begin); + size_t count = 0; + for (auto range : chunk.data) + count += range.second - range.first; + REALM_ASSERT(count == chunk.count); + } +#endif +} + +namespace { +class ChunkedRangeVectorBuilder { +public: + using value_type = std::pair; + + ChunkedRangeVectorBuilder(ChunkedRangeVector const& expected); + void push_back(size_t index); + void push_back(std::pair range); + std::vector finalize(); +private: + std::vector m_data; + size_t m_outer_pos = 0; +}; + +ChunkedRangeVectorBuilder::ChunkedRangeVectorBuilder(ChunkedRangeVector const& expected) +{ + size_t size = 0; + for (auto const& chunk : expected.m_data) + size += chunk.data.size(); + m_data.resize(size / ChunkedRangeVector::max_size + 1); + for (size_t i = 0; i < m_data.size() - 1; ++i) + m_data[i].data.reserve(ChunkedRangeVector::max_size); +} + +void ChunkedRangeVectorBuilder::push_back(size_t index) +{ + push_back({index, index + 1}); +} + +void ChunkedRangeVectorBuilder::push_back(std::pair range) +{ + auto& chunk = m_data[m_outer_pos]; + if (chunk.data.empty()) { + chunk.data.push_back(range); + chunk.count = range.second - range.first; + chunk.begin = range.first; + } + else if (range.first == chunk.data.back().second) { + chunk.data.back().second = range.second; + chunk.count += range.second - range.first; + } + else if (chunk.data.size() < ChunkedRangeVector::max_size) { + chunk.data.push_back(range); + chunk.count += range.second - range.first; + } + else { + chunk.end = chunk.data.back().second; + ++m_outer_pos; + if (m_outer_pos >= m_data.size()) + m_data.push_back({{range}, range.first, 0, 1}); + else { + auto& chunk = m_data[m_outer_pos]; + chunk.data.push_back(range); + chunk.begin = range.first; + chunk.count = range.second - range.first; + } + } +} + +std::vector ChunkedRangeVectorBuilder::finalize() +{ + if (!m_data.empty()) { + m_data.resize(m_outer_pos + 1); + if (m_data.back().data.empty()) + m_data.pop_back(); + else + m_data.back().end = m_data.back().data.back().second; + } + return std::move(m_data); +} +} + +IndexSet::IndexSet(std::initializer_list values) +{ + for (size_t v : values) + add(v); +} + +bool IndexSet::contains(size_t index) const noexcept +{ + auto it = const_cast(this)->find(index); + return it != end() && it->first <= index; +} + +size_t IndexSet::count(size_t start_index, size_t end_index) const noexcept +{ + auto it = const_cast(this)->find(start_index); + const auto end = this->end(); + if (it == end || it->first >= end_index) { + return 0; + } + if (it->second >= end_index) + return std::min(it->second, end_index) - std::max(it->first, start_index); + + size_t ret = 0; + + if (start_index > it->first || it.offset() != 0) { + // Start index is in the middle of a chunk, so start by counting the + // rest of that chunk + ret = it->second - std::max(it->first, start_index); + for (++it; it != end && it->second < end_index && it.offset() != 0; ++it) { + ret += it->second - it->first; + } + if (it != end && it->first < end_index && it.offset() != 0) + ret += end_index - it->first; + if (it == end || it->second >= end_index) + return ret; + } + + // Now count all complete chunks that fall within the range + while (it != end && it.outer()->end <= end_index) { + REALM_ASSERT_DEBUG(it.offset() == 0); + ret += it.outer()->count; + it.next_chunk(); + } + + // Cound all complete ranges within the last chunk + while (it != end && it->second <= end_index) { + ret += it->second - it->first; + ++it; + } + + // And finally add in the partial last range + if (it != end && it->first < end_index) + ret += end_index - it->first; + return ret; +} + +IndexSet::iterator IndexSet::find(size_t index) noexcept +{ + return find(index, begin()); +} + +IndexSet::iterator IndexSet::find(size_t index, iterator begin) noexcept +{ + auto it = std::find_if(begin.outer(), m_data.end(), + [&](auto const& lft) { return lft.end > index; }); + if (it == m_data.end()) + return end(); + if (index < it->begin) + return iterator(it, m_data.end(), &it->data[0]); + auto inner_begin = it->data.begin(); + if (it == begin.outer()) + inner_begin += begin.offset(); + auto inner = std::lower_bound(inner_begin, it->data.end(), index, + [&](auto const& lft, auto) { return lft.second <= index; }); + REALM_ASSERT_DEBUG(inner != it->data.end()); + + return iterator(it, m_data.end(), &*inner); +} + +void IndexSet::add(size_t index) +{ + do_add(find(index), index); +} + +void IndexSet::add(IndexSet const& other) +{ + auto it = begin(); + for (size_t index : other.as_indexes()) { + it = do_add(find(index, it), index); + } +} + +size_t IndexSet::add_shifted(size_t index) +{ + iterator it = begin(), end = this->end(); + + // Shift for any complete chunks before the target + for (; it != end && it.outer()->end <= index; it.next_chunk()) + index += it.outer()->count; + + // And any ranges within the last partial chunk + for (; it != end && it->first <= index; ++it) + index += it->second - it->first; + + do_add(it, index); + return index; +} + +void IndexSet::add_shifted_by(IndexSet const& shifted_by, IndexSet const& values) +{ + if (values.empty()) + return; + +#ifdef REALM_DEBUG + size_t expected = std::distance(as_indexes().begin(), as_indexes().end()); + for (auto index : values.as_indexes()) { + if (!shifted_by.contains(index)) + ++expected; + } +#endif + + ChunkedRangeVectorBuilder builder(*this); + + auto old_it = cbegin(), old_end = cend(); + auto shift_it = shifted_by.cbegin(), shift_end = shifted_by.cend(); + + size_t skip_until = 0; + size_t old_shift = 0; + size_t new_shift = 0; + for (size_t index : values.as_indexes()) { + for (; shift_it != shift_end && shift_it->first <= index; ++shift_it) { + new_shift += shift_it->second - shift_it->first; + skip_until = shift_it->second; + } + if (index < skip_until) + continue; + + for (; old_it != old_end && old_it->first <= index - new_shift + old_shift; ++old_it) { + for (size_t i = old_it->first; i < old_it->second; ++i) + builder.push_back(i); + old_shift += old_it->second - old_it->first; + } + + REALM_ASSERT(index >= new_shift); + builder.push_back(index - new_shift + old_shift); + } + + copy(old_it, old_end, std::back_inserter(builder)); + m_data = builder.finalize(); + +#ifdef REALM_DEBUG + REALM_ASSERT((size_t)std::distance(as_indexes().begin(), as_indexes().end()) == expected); +#endif +} + +void IndexSet::set(size_t len) +{ + clear(); + if (len) { + push_back({0, len}); + } +} + +void IndexSet::insert_at(size_t index, size_t count) +{ + REALM_ASSERT(count > 0); + + auto pos = find(index); + auto end = this->end(); + bool in_existing = false; + if (pos != end) { + if (pos->first <= index) { + in_existing = true; + pos.adjust(0, count); + } + else { + pos.shift(count); + } + for (auto it = std::next(pos); it != end; ++it) + it.shift(count); + } + if (!in_existing) { + for (size_t i = 0; i < count; ++i) + pos = std::next(do_add(pos, index + i)); + } + + verify(); +} + +void IndexSet::insert_at(IndexSet const& positions) +{ + if (positions.empty()) + return; + if (empty()) { + *this = positions; + return; + } + + IndexIterator begin1 = cbegin(), begin2 = positions.cbegin(); + IndexIterator end1 = cend(), end2 = positions.cend(); + + ChunkedRangeVectorBuilder builder(*this); + size_t shift = 0; + while (begin1 != end1 && begin2 != end2) { + if (*begin1 + shift < *begin2) { + builder.push_back(*begin1++ + shift); + } + else { + ++shift; + builder.push_back(*begin2++); + } + } + for (; begin1 != end1; ++begin1) + builder.push_back(*begin1 + shift); + for (; begin2 != end2; ++begin2) + builder.push_back(*begin2); + + m_data = builder.finalize(); +} + +void IndexSet::shift_for_insert_at(size_t index, size_t count) +{ + REALM_ASSERT(count > 0); + + auto it = find(index); + if (it == end()) + return; + + for (auto pos = it, end = this->end(); pos != end; ++pos) + pos.shift(count); + + // If the range contained the insertion point, split the range and move + // the part of it before the insertion point back + if (it->first < index + count) { + auto old_second = it->second; + it.set(it->first - count, index); + insert(std::next(it), {index + count, old_second}); + } + verify(); +} + +void IndexSet::shift_for_insert_at(realm::IndexSet const& values) +{ + if (empty() || values.empty()) + return; + if (values.m_data.front().begin >= m_data.back().end) + return; + + IndexIterator begin1 = cbegin(), begin2 = values.cbegin(); + IndexIterator end1 = cend(), end2 = values.cend(); + + ChunkedRangeVectorBuilder builder(*this); + size_t shift = 0; + while (begin1 != end1 && begin2 != end2) { + if (*begin1 + shift < *begin2) { + builder.push_back(*begin1++ + shift); + } + else { + ++shift; + begin2++; + } + } + for (; begin1 != end1; ++begin1) + builder.push_back(*begin1 + shift); + + m_data = builder.finalize(); +} + +void IndexSet::erase_at(size_t index) +{ + auto it = find(index); + if (it != end()) + do_erase(it, index); +} + +void IndexSet::erase_at(IndexSet const& positions) +{ + if (empty() || positions.empty()) + return; + + ChunkedRangeVectorBuilder builder(*this); + + IndexIterator begin1 = cbegin(), begin2 = positions.cbegin(); + IndexIterator end1 = cend(), end2 = positions.cend(); + + size_t shift = 0; + while (begin1 != end1 && begin2 != end2) { + if (*begin1 < *begin2) { + builder.push_back(*begin1++ - shift); + } + else if (*begin1 == *begin2) { + ++shift; + ++begin1; + ++begin2; + } + else { + ++shift; + ++begin2; + } + } + for (; begin1 != end1; ++begin1) + builder.push_back(*begin1 - shift); + + m_data = builder.finalize(); +} + +size_t IndexSet::erase_or_unshift(size_t index) +{ + auto shifted = index; + iterator it = begin(), end = this->end(); + + // Shift for any complete chunks before the target + for (; it != end && it.outer()->end <= index; it.next_chunk()) + shifted -= it.outer()->count; + + // And any ranges within the last partial chunk + for (; it != end && it->second <= index; ++it) + shifted -= it->second - it->first; + + if (it == end) + return shifted; + + if (it->first <= index) + shifted = npos; + + do_erase(it, index); + + return shifted; +} + +void IndexSet::do_erase(iterator it, size_t index) +{ + if (it->first <= index) { + if (it->first + 1 == it->second) { + it = erase(it); + } + else { + it.adjust(0, -1); + ++it; + } + } + else if (it != begin() && std::prev(it)->second + 1 == it->first) { + std::prev(it).adjust(0, it->second - it->first); + it = erase(it); + } + + for (; it != end(); ++it) + it.shift(-1); +} + +IndexSet::iterator IndexSet::do_remove(iterator it, size_t begin, size_t end) +{ + for (it = find(begin, it); it != this->end() && it->first < end; it = find(begin, it)) { + // Trim off any part of the range to remove that's before the matching range + begin = std::max(it->first, begin); + + // If the matching range extends to both sides of the range to remove, + // split it on the range to remove + if (it->first < begin && it->second > end) { + auto old_second = it->second; + it.set(it->first, begin); + it = std::prev(insert(std::next(it), {end, old_second})); + } + // Range to delete now coverages (at least) one end of the matching range + else if (begin == it->first && end >= it->second) + it = erase(it); + else if (begin == it->first) + it.set(end, it->second); + else + it.set(it->first, begin); + } + return it; +} + +void IndexSet::remove(size_t index, size_t count) +{ + do_remove(find(index), index, index + count); +} + +void IndexSet::remove(realm::IndexSet const& values) +{ + auto it = begin(); + for (auto range : values) { + it = do_remove(it, range.first, range.second); + if (it == end()) + return; + } +} + +size_t IndexSet::shift(size_t index) const noexcept +{ + // FIXME: optimize + for (auto range : *this) { + if (range.first > index) + break; + index += range.second - range.first; + } + return index; +} + +size_t IndexSet::unshift(size_t index) const noexcept +{ + REALM_ASSERT_DEBUG(!contains(index)); + return index - count(0, index); +} + +void IndexSet::clear() noexcept +{ + m_data.clear(); +} + +IndexSet::iterator IndexSet::do_add(iterator it, size_t index) +{ + verify(); + bool more_before = it != begin(), valid = it != end(); + REALM_ASSERT(!more_before || index >= std::prev(it)->second); + if (valid && it->first <= index && it->second > index) { + // index is already in set + return it; + } + if (more_before && std::prev(it)->second == index) { + auto prev = std::prev(it); + // index is immediately after an existing range + prev.adjust(0, 1); + + if (valid && prev->second == it->first) { + // index joins two existing ranges + prev.adjust(0, it->second - it->first); + return std::prev(erase(it)); + } + return prev; + } + if (valid && it->first == index + 1) { + // index is immediately before an existing range + it.adjust(-1, 0); + return it; + } + + // index is not next to an existing range + return insert(it, {index, index + 1}); +} diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/list.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/list.cpp new file mode 100644 index 0000000..a757878 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/list.cpp @@ -0,0 +1,551 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// 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 "list.hpp" + +#include "impl/list_notifier.hpp" +#include "impl/realm_coordinator.hpp" +#include "object_schema.hpp" +#include "object_store.hpp" +#include "results.hpp" +#include "schema.hpp" +#include "shared_realm.hpp" + +namespace { +using namespace realm; + +template +struct ListType { + using type = Lst; +}; + +template<> +struct ListType { + using type = LnkLst; +}; + +} + +namespace realm { +using namespace _impl; + +List::List() noexcept = default; +List::~List() = default; + +List::List(const List&) = default; +List& List::operator=(const List&) = default; +List::List(List&&) = default; +List& List::operator=(List&&) = default; + +List::List(std::shared_ptr r, const Obj& parent_obj, ColKey col) +: m_realm(std::move(r)) +, m_type(ObjectSchema::from_core_type(col) & ~PropertyType::Array) +, m_list_base(parent_obj.get_listbase_ptr(col)) +, m_is_embedded(m_type == PropertyType::Object && as().get_target_table()->is_embedded()) +{ +} + +List::List(std::shared_ptr r, const LstBase& list) +: m_realm(std::move(r)) +, m_type(ObjectSchema::from_core_type(list.get_col_key()) & ~PropertyType::Array) +, m_list_base(list.clone()) +, m_is_embedded(m_type == PropertyType::Object && as().get_target_table()->is_embedded()) +{ +} + +static StringData object_name(Table const& table) +{ + return ObjectStore::object_type_for_table_name(table.get_name()); +} + +ObjectSchema const& List::get_object_schema() const +{ + verify_attached(); + + REALM_ASSERT(get_type() == PropertyType::Object); + auto object_schema = m_object_schema.load(); + if (!object_schema) { + auto object_type = object_name(*static_cast(*m_list_base).get_target_table()); + auto it = m_realm->schema().find(object_type); + REALM_ASSERT(it != m_realm->schema().end()); + m_object_schema = object_schema = &*it; + } + return *object_schema; +} + +Query List::get_query() const +{ + verify_attached(); + if (m_type == PropertyType::Object) + return static_cast(*m_list_base).get_target_table()->where(as()); + throw std::runtime_error("not implemented"); +} + +ObjKey List::get_parent_object_key() const +{ + verify_attached(); + return m_list_base->get_key(); +} + +ColKey List::get_parent_column_key() const +{ + verify_attached(); + return m_list_base->get_col_key(); +} + +TableKey List::get_parent_table_key() const +{ + verify_attached(); + return m_list_base->get_table()->get_key(); +} + +void List::verify_valid_row(size_t row_ndx, bool insertion) const +{ + size_t s = size(); + if (row_ndx > s || (!insertion && row_ndx == s)) { + throw OutOfBoundsIndexException{row_ndx, s + insertion}; + } +} + +void List::validate(const Obj& obj) const +{ + if (!obj.is_valid()) + throw std::invalid_argument("Object has been deleted or invalidated"); + auto target = static_cast(*m_list_base).get_target_table(); + if (obj.get_table() != target) + throw std::invalid_argument(util::format("Object of type (%1) does not match List type (%2)", + object_name(*obj.get_table()), + object_name(*target))); +} + +bool List::is_valid() const +{ + if (!m_realm) + return false; + m_realm->verify_thread(); + if (!m_realm->is_in_read_transaction()) + return false; + return m_list_base->is_attached(); +} + +void List::verify_attached() const +{ + if (!is_valid()) { + throw InvalidatedException(); + } +} + +void List::verify_in_transaction() const +{ + verify_attached(); + m_realm->verify_in_write(); +} + +size_t List::size() const +{ + verify_attached(); + return m_list_base->size(); +} + +template +T List::get(size_t row_ndx) const +{ + verify_valid_row(row_ndx); + return as().get(row_ndx); +} + +template<> +Obj List::get(size_t row_ndx) const +{ + verify_valid_row(row_ndx); + auto& list = as(); + return list.get_target_table()->get_object(list.get(row_ndx)); +} + +template +size_t List::find(T const& value) const +{ + verify_attached(); + return as().find_first(value); +} + +template<> +size_t List::find(Obj const& o) const +{ + verify_attached(); + if (!o.is_valid()) + return not_found; + validate(o); + + return as().ConstLstIf::find_first(o.get_key()); +} + +size_t List::find(Query&& q) const +{ + verify_attached(); + if (m_type == PropertyType::Object) { + ObjKey key = get_query().and_query(std::move(q)).find(); + return key ? as().ConstLstIf::find_first(key) : not_found; + } + throw std::runtime_error("not implemented"); +} + +template +void List::add(T value) +{ + verify_in_transaction(); + as().add(value); +} + +template<> +void List::add(Obj o) +{ + verify_in_transaction(); + if (m_is_embedded) + throw InvalidEmbeddedOperationException(); + validate(o); + as().add(o.get_key()); +} + +template +void List::insert(size_t row_ndx, T value) +{ + verify_in_transaction(); + verify_valid_row(row_ndx, true); + as().insert(row_ndx, value); +} + +template<> +void List::insert(size_t row_ndx, Obj o) +{ + verify_in_transaction(); + verify_valid_row(row_ndx, true); + validate(o); + if (m_is_embedded) + throw InvalidEmbeddedOperationException(); + as().insert(row_ndx, o.get_key()); +} + +void List::move(size_t source_ndx, size_t dest_ndx) +{ + verify_in_transaction(); + verify_valid_row(source_ndx); + verify_valid_row(dest_ndx); // Can't be one past end due to removing one earlier + if (source_ndx == dest_ndx) + return; + + m_list_base->move(source_ndx, dest_ndx); +} + +void List::remove(size_t row_ndx) +{ + verify_in_transaction(); + verify_valid_row(row_ndx); + m_list_base->remove(row_ndx, row_ndx + 1); +} + +void List::remove_all() +{ + verify_in_transaction(); + m_list_base->clear(); +} + +template +void List::set(size_t row_ndx, T value) +{ + verify_in_transaction(); + verify_valid_row(row_ndx); +// validate(row); + as().set(row_ndx, value); +} + +template<> +void List::set(size_t row_ndx, Obj o) +{ + verify_in_transaction(); + verify_valid_row(row_ndx); + validate(o); + if (m_is_embedded) + throw InvalidEmbeddedOperationException(); + as().set(row_ndx, o.get_key()); +} + +Obj List::add_embedded() +{ + verify_in_transaction(); + + if (!m_is_embedded) + throw InvalidEmbeddedOperationException(); + + return as().create_and_insert_linked_object(size()); +} + +Obj List::set_embedded(size_t list_ndx) +{ + verify_in_transaction(); + verify_valid_row(list_ndx); + + if (!m_is_embedded) + throw InvalidEmbeddedOperationException(); + + return as().create_and_set_linked_object(list_ndx); +} + +Obj List::insert_embedded(size_t list_ndx) +{ + verify_in_transaction(); + verify_valid_row(list_ndx, true); + + if (!m_is_embedded) + throw InvalidEmbeddedOperationException(); + + return as().create_and_insert_linked_object(list_ndx); +} + + +void List::swap(size_t ndx1, size_t ndx2) +{ + verify_in_transaction(); + verify_valid_row(ndx1); + verify_valid_row(ndx2); + m_list_base->swap(ndx1, ndx2); +} + +void List::delete_at(size_t row_ndx) +{ + verify_in_transaction(); + verify_valid_row(row_ndx); + if (m_type == PropertyType::Object) + as().remove_target_row(row_ndx); + else + m_list_base->remove(row_ndx, row_ndx + 1); +} + +void List::delete_all() +{ + verify_in_transaction(); + if (m_type == PropertyType::Object) + as().remove_all_target_rows(); + else + m_list_base->clear(); +} + +Results List::sort(SortDescriptor order) const +{ + verify_attached(); + if ((m_type == PropertyType::Object)) { + return Results(m_realm, std::dynamic_pointer_cast(m_list_base), util::none, std::move(order)); + } + else { + DescriptorOrdering o; + o.append_sort(order); + return Results(m_realm, m_list_base, std::move(o)); + } +} + +Results List::sort(std::vector> const& keypaths) const +{ + return as_results().sort(keypaths); +} + +Results List::filter(Query q) const +{ + verify_attached(); + return Results(m_realm, std::dynamic_pointer_cast(m_list_base), get_query().and_query(std::move(q))); +} + +Results List::as_results() const +{ + verify_attached(); + return m_type == PropertyType::Object + ? Results(m_realm, std::static_pointer_cast(m_list_base)) + : Results(m_realm, m_list_base); +} + +Results List::snapshot() const +{ + return as_results().snapshot(); +} + +// The simpler definition of void_t below does not work in gcc 4.9 due to a bug +// in that version of gcc (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64395) + +// template using VoidT = void; +namespace _impl { + template struct MakeVoid { using type = void; }; +} +template using VoidT = typename _impl::MakeVoid::type; + +template> +struct HasMinmaxType : std::false_type { }; +template +struct HasMinmaxType::minmax_type>> : std::true_type { }; + +template> +struct HasSumType : std::false_type { }; +template +struct HasSumType::sum_type>> : std::true_type { }; + +template +struct If; + +template<> +struct If { + template + static auto call(T self, Then&& fn, Else&&) { return fn(self); } +}; +template<> +struct If { + template + static auto call(T, Then&&, Else&& fn) { return fn(); } +}; + +util::Optional List::max(ColKey col) const +{ + if (get_type() == PropertyType::Object) + return as_results().max(col); + size_t out_ndx = not_found; + auto result = m_list_base->max(&out_ndx); + if (result.is_null()) { + throw realm::Results::UnsupportedColumnTypeException(m_list_base->get_col_key(), m_list_base->get_table(), "max"); + } + return out_ndx == not_found ? none : util::make_optional(result); +} + +util::Optional List::min(ColKey col) const +{ + if (get_type() == PropertyType::Object) + return as_results().min(col); + + size_t out_ndx = not_found; + auto result = m_list_base->min(&out_ndx); + if (result.is_null()) { + throw realm::Results::UnsupportedColumnTypeException(m_list_base->get_col_key(), m_list_base->get_table(), "min"); + } + return out_ndx == not_found ? none : util::make_optional(result); +} + +Mixed List::sum(ColKey col) const +{ + if (get_type() == PropertyType::Object) + return *as_results().sum(col); + + auto result = m_list_base->sum(); + if (result.is_null()) { + throw realm::Results::UnsupportedColumnTypeException(m_list_base->get_col_key(), m_list_base->get_table(), "sum"); + } + return result; +} + +util::Optional List::average(ColKey col) const +{ + if (get_type() == PropertyType::Object) + return as_results().average(col); + size_t count = 0; + auto result = m_list_base->avg(&count); + if (result.is_null()) { + throw realm::Results::UnsupportedColumnTypeException(m_list_base->get_col_key(), m_list_base->get_table(), "average"); + } + return count == 0 ? none : util::make_optional(result); +} + +bool List::operator==(List const& rgt) const noexcept +{ + return m_list_base->get_table() == rgt.m_list_base->get_table() + && m_list_base->get_key() == rgt.m_list_base->get_key() + && m_list_base->get_col_key() == rgt.m_list_base->get_col_key(); +} + +NotificationToken List::add_notification_callback(CollectionChangeCallback cb) & +{ + verify_attached(); + m_realm->verify_notifications_available(); + // Adding a new callback to a notifier which had all of its callbacks + // removed does not properly reinitialize the notifier. Work around this by + // recreating it instead. + // FIXME: The notifier lifecycle here is dumb (when all callbacks are removed + // from a notifier a zombie is left sitting around uselessly) and should be + // cleaned up. + if (m_notifier && !m_notifier->have_callbacks()) + m_notifier.reset(); + if (!m_notifier) { + m_notifier = std::make_shared(m_realm, *m_list_base, m_type); + RealmCoordinator::register_notifier(m_notifier); + } + return {m_notifier, m_notifier->add_callback(std::move(cb))}; +} + +List List::freeze(std::shared_ptr const& frozen_realm) const +{ + return List(frozen_realm, *frozen_realm->import_copy_of(*m_list_base)); +} + +bool List::is_frozen() const noexcept +{ + return m_realm->is_frozen(); +} + +List::OutOfBoundsIndexException::OutOfBoundsIndexException(size_t r, size_t c) +: std::out_of_range(util::format("Requested index %1 greater than max %2", r, c - 1)) +, requested(r), valid_count(c) {} + +#define REALM_PRIMITIVE_LIST_TYPE(T) \ + template T List::get(size_t) const; \ + template size_t List::find(T const&) const; \ + template void List::add(T); \ + template void List::insert(size_t, T); \ + template void List::set(size_t, T); + +REALM_PRIMITIVE_LIST_TYPE(bool) +REALM_PRIMITIVE_LIST_TYPE(int64_t) +REALM_PRIMITIVE_LIST_TYPE(float) +REALM_PRIMITIVE_LIST_TYPE(double) +REALM_PRIMITIVE_LIST_TYPE(StringData) +REALM_PRIMITIVE_LIST_TYPE(BinaryData) +REALM_PRIMITIVE_LIST_TYPE(Timestamp) +REALM_PRIMITIVE_LIST_TYPE(ObjKey) +REALM_PRIMITIVE_LIST_TYPE(ObjectId) +REALM_PRIMITIVE_LIST_TYPE(Decimal) +REALM_PRIMITIVE_LIST_TYPE(util::Optional) +REALM_PRIMITIVE_LIST_TYPE(util::Optional) +REALM_PRIMITIVE_LIST_TYPE(util::Optional) +REALM_PRIMITIVE_LIST_TYPE(util::Optional) +REALM_PRIMITIVE_LIST_TYPE(util::Optional) + +#undef REALM_PRIMITIVE_LIST_TYPE +} // namespace realm + +namespace { +size_t hash_combine() { return 0; } +template +size_t hash_combine(const T& v, Rest... rest) +{ + size_t h = hash_combine(rest...); + h ^= std::hash()(v) + 0x9e3779b9 + (h<<6) + (h>>2); + return h; +} +} + +namespace std { +size_t hash::operator()(List const& list) const +{ + auto& impl = *list.m_list_base; + return hash_combine(impl.get_key().value, impl.get_table()->get_key().value, + impl.get_col_key().value); +} +} diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/object.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/object.cpp new file mode 100644 index 0000000..080bb42 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/object.cpp @@ -0,0 +1,152 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2017 Realm Inc. +// +// 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 "object.hpp" + +#include "impl/object_notifier.hpp" +#include "impl/realm_coordinator.hpp" +#include "object_schema.hpp" +#include "object_store.hpp" + +#include + +using namespace realm; + +/* The nice syntax is not supported by MSVC */ +CreatePolicy CreatePolicy::Skip = {/*.create =*/ false, /*.copy =*/ false, /*.update =*/ false, /*.diff =*/ false}; +CreatePolicy CreatePolicy::ForceCreate = {/*.create =*/ true, /*.copy =*/ true, /*.update =*/ false, /*.diff =*/ false}; +CreatePolicy CreatePolicy::UpdateAll = {/*.create =*/ true, /*.copy =*/ true, /*.update =*/ true, /*.diff =*/ false}; +CreatePolicy CreatePolicy::UpdateModified = {/*.create =*/ true, /*.copy =*/ true, /*.update =*/ true, /*.diff =*/ true}; +CreatePolicy CreatePolicy::SetLink = {/*.create =*/ true, /*.copy =*/ false, /*.update =*/ false, /*.diff =*/ false}; + +Object Object::freeze(std::shared_ptr frozen_realm) const +{ + return Object(frozen_realm, frozen_realm->import_copy_of(m_obj)); +} + +bool Object::is_frozen() const noexcept +{ + return m_realm->is_frozen(); +} + +InvalidatedObjectException::InvalidatedObjectException(const std::string& object_type) +: std::logic_error("Accessing object of type " + object_type + " which has been invalidated or deleted") +, object_type(object_type) +{} + +InvalidPropertyException::InvalidPropertyException(const std::string& object_type, const std::string& property_name) +: std::logic_error(util::format("Property '%1.%2' does not exist", object_type, property_name)) +, object_type(object_type), property_name(property_name) +{} + +MissingPropertyValueException::MissingPropertyValueException(const std::string& object_type, const std::string& property_name) +: std::logic_error(util::format("Missing value for property '%1.%2'", object_type, property_name)) +, object_type(object_type), property_name(property_name) +{} + +MissingPrimaryKeyException::MissingPrimaryKeyException(const std::string& object_type) +: std::logic_error(util::format("'%1' does not have a primary key defined", object_type)) +, object_type(object_type) +{} + +ReadOnlyPropertyException::ReadOnlyPropertyException(const std::string& object_type, const std::string& property_name) +: std::logic_error(util::format("Cannot modify read-only property '%1.%2'", object_type, property_name)) +, object_type(object_type), property_name(property_name) {} + +ModifyPrimaryKeyException::ModifyPrimaryKeyException(const std::string& object_type, const std::string& property_name) +: std::logic_error(util::format("Cannot modify primary key after creation: '%1.%2'", object_type, property_name)) +, object_type(object_type), property_name(property_name) {} + +Object::Object(SharedRealm r, ObjectSchema const& s, Obj const& o) +: m_realm(std::move(r)), m_object_schema(&s), m_obj(o) { } + +Object::Object(SharedRealm r, Obj const& o) +: m_realm(std::move(r)) +, m_object_schema(&*m_realm->schema().find(ObjectStore::object_type_for_table_name(o.get_table()->get_name()))) +, m_obj(o) +{ + REALM_ASSERT(!m_obj.get_table() || (&m_realm->read_group() == _impl::TableFriend::get_parent_group(*m_obj.get_table()))); +} + +Object::Object(SharedRealm r, StringData object_type, ObjKey key) +: m_realm(std::move(r)) +, m_object_schema(&*m_realm->schema().find(object_type)) +, m_obj(ObjectStore::table_for_object_type(m_realm->read_group(), object_type)->get_object(key)) +{ + REALM_ASSERT(!m_obj.get_table() || (&m_realm->read_group() == _impl::TableFriend::get_parent_group(*m_obj.get_table()))); +} + +Object::Object(SharedRealm r, StringData object_type, size_t index) +: m_realm(std::move(r)) +, m_object_schema(&*m_realm->schema().find(object_type)) +, m_obj(ObjectStore::table_for_object_type(m_realm->read_group(), object_type)->get_object(index)) +{ + REALM_ASSERT(!m_obj.get_table() || (&m_realm->read_group() == _impl::TableFriend::get_parent_group(*m_obj.get_table()))); +} + +Object::Object() = default; +Object::~Object() = default; +Object::Object(Object const&) = default; +Object::Object(Object&&) = default; +Object& Object::operator=(Object const&) = default; +Object& Object::operator=(Object&&) = default; + +NotificationToken Object::add_notification_callback(CollectionChangeCallback callback) & +{ + verify_attached(); + m_realm->verify_notifications_available(); + if (!m_notifier) { + m_notifier = std::make_shared<_impl::ObjectNotifier>(m_realm, m_obj.get_table()->get_key(), m_obj.get_key()); + _impl::RealmCoordinator::register_notifier(m_notifier); + } + return {m_notifier, m_notifier->add_callback(std::move(callback))}; +} + +void Object::verify_attached() const +{ + m_realm->verify_thread(); + if (!m_obj.is_valid()) { + throw InvalidatedObjectException(m_object_schema->name); + } +} + +Property const& Object::property_for_name(StringData prop_name) const +{ + auto prop = m_object_schema->property_for_name(prop_name); + if (!prop) { + throw InvalidPropertyException(m_object_schema->name, prop_name); + } + return *prop; +} + +void Object::validate_property_for_setter(Property const& property) const +{ + verify_attached(); + m_realm->verify_in_write(); + + // Modifying primary keys is allowed in migrations to make it possible to + // add a new primary key to a type (or change the property type), but it + // is otherwise considered the immutable identity of the row + if (property.is_primary) { + if (!m_realm->is_in_migration()) + throw ModifyPrimaryKeyException(m_object_schema->name, property.name); + // Modifying the PK property while it's the PK will corrupt the table, + // so remove it and then restore it at the end of the migration (which will rebuild the table) + m_obj.get_table()->set_primary_key_column({}); + } +} diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/object_changeset.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/object_changeset.cpp new file mode 100644 index 0000000..e13eff0 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/object_changeset.cpp @@ -0,0 +1,149 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// 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 "object_changeset.hpp" + +using namespace realm; + +void ObjectChangeSet::insertions_add(ObjectKeyType obj) +{ + m_insertions.insert(obj); +} + +void ObjectChangeSet::modifications_add(ObjectKeyType obj, ColKeyType col) +{ + // don't report modifications on new objects + if (m_insertions.find(obj) == m_insertions.end()) { + m_modifications[obj].insert(col); + } +} + +void ObjectChangeSet::deletions_add(ObjectKeyType obj) +{ + m_modifications.erase(obj); + size_t num_inserts_removed = m_insertions.erase(obj); + if (num_inserts_removed == 0) { + m_deletions.insert(obj); + } +} + +void ObjectChangeSet::clear(size_t old_size) +{ + static_cast(old_size); // unused + m_clear_did_occur = true; + m_insertions.clear(); + m_modifications.clear(); + m_deletions.clear(); +} + +bool ObjectChangeSet::insertions_remove(ObjectKeyType obj) +{ + return m_insertions.erase(obj) > 0; +} + +bool ObjectChangeSet::modifications_remove(ObjectKeyType obj) +{ + return m_modifications.erase(obj) > 0; +} + +bool ObjectChangeSet::deletions_remove(ObjectKeyType obj) +{ + return m_deletions.erase(obj) > 0; +} + +bool ObjectChangeSet::deletions_contains(ObjectKeyType obj) const +{ + if (m_clear_did_occur) { + // FIXME: what are the expected notifications when an object is deleted + // and then another object is inserted with the same key? + return m_insertions.count(obj) == 0; + } + return m_deletions.count(obj) > 0; +} + +bool ObjectChangeSet::insertions_contains(ObjectKeyType obj) const +{ + return m_insertions.count(obj) > 0; +} + +bool ObjectChangeSet::modifications_contains(ObjectKeyType obj) const +{ + return m_modifications.count(obj) > 0; +} + +const ObjectChangeSet::ObjectSet* ObjectChangeSet::get_columns_modified(ObjectKeyType obj) const +{ + auto it = m_modifications.find(obj); + if (it == m_modifications.end()) { + return nullptr; + } + return &it->second; +} + +void ObjectChangeSet::merge(ObjectChangeSet&& other) +{ + if (other.empty()) + return; + if (empty()) { + *this = std::move(other); + return; + } + m_clear_did_occur = m_clear_did_occur || other.m_clear_did_occur; + + verify(); + other.verify(); + + // Drop any inserted-then-deleted rows, then merge in new insertions + for (auto it = other.m_deletions.begin(); it != other.m_deletions.end();) { + auto previously_inserted = m_insertions.find(*it); + auto previously_modified = m_modifications.find(*it); + if (previously_modified != m_modifications.end()) { + m_modifications.erase(previously_modified); + } + if (previously_inserted != m_insertions.end()) { + m_insertions.erase(previously_inserted); + it = m_deletions.erase(it); + } + else { + ++it; + } + } + if (!other.m_insertions.empty()) { + m_insertions.insert(other.m_insertions.begin(), other.m_insertions.end()); + } + if (!other.m_deletions.empty()) { + m_deletions.insert(other.m_deletions.begin(), other.m_deletions.end()); + } + for (auto it = other.m_modifications.begin(); it != other.m_modifications.end(); ++it) { + m_modifications[it->first].insert(it->second.begin(), it->second.end()); + } + + verify(); + + other = {}; +} + +void ObjectChangeSet::verify() +{ +#ifdef REALM_DEBUG + for (auto it = m_deletions.begin(); it != m_deletions.end(); ++it) { + REALM_ASSERT_EX(m_insertions.find(*it) == m_insertions.end(), *it); + } +#endif +} + diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/object_schema.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/object_schema.cpp new file mode 100644 index 0000000..27fa68f --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/object_schema.cpp @@ -0,0 +1,359 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// 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 "object_schema.hpp" + +#include "feature_checks.hpp" +#include "object_store.hpp" +#include "property.hpp" +#include "schema.hpp" + +#include +#include +#include + +using namespace realm; + +ObjectSchema::ObjectSchema() = default; +ObjectSchema::~ObjectSchema() = default; + +ObjectSchema::ObjectSchema(std::string name, std::initializer_list persisted_properties) +: ObjectSchema(std::move(name), persisted_properties, {}) +{ +} + +ObjectSchema::ObjectSchema(std::string name, IsEmbedded is_embedded, std::initializer_list persisted_properties) +: ObjectSchema(std::move(name), is_embedded, persisted_properties, {}) +{ +} + +ObjectSchema::ObjectSchema(std::string name, std::initializer_list persisted_properties, + std::initializer_list computed_properties) +: ObjectSchema(std::move(name), IsEmbedded{false}, persisted_properties, computed_properties) +{ +} + +ObjectSchema::ObjectSchema(std::string name, IsEmbedded is_embedded, std::initializer_list persisted_properties, + std::initializer_list computed_properties) +: name(std::move(name)) +, persisted_properties(persisted_properties) +, computed_properties(computed_properties) +, is_embedded(is_embedded) +{ + for (auto const& prop : persisted_properties) { + if (prop.is_primary) { + primary_key = prop.name; + break; + } + } +} + +PropertyType ObjectSchema::from_core_type(ColKey col) +{ + auto flags = PropertyType::Required; + auto attr = col.get_attrs(); + if (attr.test(col_attr_Nullable)) + flags |= PropertyType::Nullable; + if (attr.test(col_attr_List)) + flags |= PropertyType::Array; + switch (col.get_type()) { + case col_type_Int: return PropertyType::Int | flags; + case col_type_Float: return PropertyType::Float | flags; + case col_type_Double: return PropertyType::Double | flags; + case col_type_Bool: return PropertyType::Bool | flags; + case col_type_String: return PropertyType::String | flags; + case col_type_Binary: return PropertyType::Data | flags; + case col_type_Timestamp: return PropertyType::Date | flags; + case col_type_OldMixed: return PropertyType::Any | flags; + case col_type_ObjectId: return PropertyType::ObjectId | flags; + case col_type_Decimal: return PropertyType::Decimal | flags; + case col_type_Link: return PropertyType::Object | PropertyType::Nullable; + case col_type_LinkList: return PropertyType::Object | PropertyType::Array; + default: REALM_UNREACHABLE(); + } +} + +ObjectSchema::ObjectSchema(Group const& group, StringData name, TableKey key) +: name(name) +{ + ConstTableRef table; + if (key) { + table = group.get_table(key); + } + else { + table = ObjectStore::table_for_object_type(group, name); + } + table_key = table->get_key(); + is_embedded = table->is_embedded(); + + size_t count = table->get_column_count(); + ColKey pk_col = table->get_primary_key_column(); + persisted_properties.reserve(count); + + for (auto col_key : table->get_column_keys()) { + StringData column_name = table->get_column_name(col_key); + +#if REALM_ENABLE_SYNC + // The object ID column is an implementation detail, and is omitted from the schema. + // FIXME: this can go away once sync adopts stable ids? + if (column_name.begins_with("!")) + continue; +#endif + + Property property; + property.name = column_name; + property.type = ObjectSchema::from_core_type(col_key); + property.is_indexed = table->has_search_index(col_key) || pk_col == col_key; + property.column_key = col_key; + + if (property.type == PropertyType::Object) { + // set link type for objects and arrays + ConstTableRef linkTable = table->get_link_target(col_key); + property.object_type = ObjectStore::object_type_for_table_name(linkTable->get_name().data()); + } + persisted_properties.push_back(std::move(property)); + } + + if (pk_col) + primary_key = table->get_column_name(pk_col); + set_primary_key_property(); +} + +Property *ObjectSchema::property_for_name(StringData name) noexcept +{ + for (auto& prop : persisted_properties) { + if (StringData(prop.name) == name) { + return ∝ + } + } + for (auto& prop : computed_properties) { + if (StringData(prop.name) == name) { + return ∝ + } + } + return nullptr; +} + +Property *ObjectSchema::property_for_public_name(StringData public_name) noexcept +{ + // If no `public_name` is defined, the internal `name` is also considered the public name. + for (auto& prop : persisted_properties) { + if (prop.public_name == public_name || (prop.public_name.empty() && prop.name == public_name)) + return ∝ + } + + // Computed properties are not persisted, so creating a public name for such properties + // are a bit pointless since the internal name is already the "public name", but since + // this distinction isn't visible in the Property struct we allow it anyway. + for (auto& prop : computed_properties) { + if (StringData(prop.public_name.empty() ? prop.name : prop.public_name) == public_name) + return ∝ + } + return nullptr; +} + +const Property *ObjectSchema::property_for_public_name(StringData public_name) const noexcept +{ + return const_cast(this)->property_for_public_name(public_name); +} + +const Property *ObjectSchema::property_for_name(StringData name) const noexcept +{ + return const_cast(this)->property_for_name(name); +} + +bool ObjectSchema::property_is_computed(Property const& property) const noexcept +{ + auto end = computed_properties.end(); + return std::find(computed_properties.begin(), end, property) != end; +} + +void ObjectSchema::set_primary_key_property() noexcept +{ + if (primary_key.length()) { + if (auto primary_key_prop = primary_key_property()) { + primary_key_prop->is_primary = true; + } + } +} + +static void validate_property(Schema const& schema, + ObjectSchema const& parent_object_schema, + Property const& prop, + Property const** primary, + std::vector& exceptions) +{ + auto& object_name = parent_object_schema.name; + + if (prop.type == PropertyType::LinkingObjects && !is_array(prop.type)) { + exceptions.emplace_back("Linking Objects property '%1.%2' must be an array.", + object_name, prop.name); + } + + // check nullablity + if (is_nullable(prop.type) && !prop.type_is_nullable()) { + exceptions.emplace_back("Property '%1.%2' of type '%3' cannot be nullable.", + object_name, prop.name, string_for_property_type(prop.type)); + } + else if (prop.type == PropertyType::Object && !is_nullable(prop.type) && !is_array(prop.type)) { + exceptions.emplace_back("Property '%1.%2' of type 'object' must be nullable.", object_name, prop.name); + } + + // check primary keys + if (prop.is_primary) { + if (prop.type != PropertyType::Int && prop.type != PropertyType::String && prop.type != PropertyType::ObjectId) { + exceptions.emplace_back("Property '%1.%2' of type '%3' cannot be made the primary key.", + object_name, prop.name, string_for_property_type(prop.type)); + } + if (*primary) { + exceptions.emplace_back("Properties '%1' and '%2' are both marked as the primary key of '%3'.", + prop.name, (*primary)->name, object_name); + } + *primary = ∝ + } + + // check indexable + if (prop.is_indexed && !prop.type_is_indexable()) { + exceptions.emplace_back("Property '%1.%2' of type '%3' cannot be indexed.", + object_name, prop.name, string_for_property_type(prop.type)); + } + + // check that only link properties have object types + if (prop.type != PropertyType::LinkingObjects && !prop.link_origin_property_name.empty()) { + exceptions.emplace_back("Property '%1.%2' of type '%3' cannot have an origin property name.", + object_name, prop.name, string_for_property_type(prop.type)); + } + else if (prop.type == PropertyType::LinkingObjects && prop.link_origin_property_name.empty()) { + exceptions.emplace_back("Property '%1.%2' of type '%3' must have an origin property name.", + object_name, prop.name, string_for_property_type(prop.type)); + } + + if (prop.type != PropertyType::Object && prop.type != PropertyType::LinkingObjects) { + if (!prop.object_type.empty()) { + exceptions.emplace_back("Property '%1.%2' of type '%3' cannot have an object type.", + object_name, prop.name, prop.type_string()); + } + return; + } + + + // check that the object_type is valid for link properties + auto it = schema.find(prop.object_type); + if (it == schema.end()) { + exceptions.emplace_back("Property '%1.%2' of type '%3' has unknown object type '%4'", + object_name, prop.name, string_for_property_type(prop.type), prop.object_type); + return; + } + if (prop.type != PropertyType::LinkingObjects) + return; + + const Property *origin_property = it->property_for_name(prop.link_origin_property_name); + if (!origin_property) { + exceptions.emplace_back("Property '%1.%2' declared as origin of linking objects property '%3.%4' does not exist", + prop.object_type, prop.link_origin_property_name, + object_name, prop.name); + } + else if (origin_property->type != PropertyType::Object) { + exceptions.emplace_back("Property '%1.%2' declared as origin of linking objects property '%3.%4' is not a link", + prop.object_type, prop.link_origin_property_name, + object_name, prop.name); + } + else if (origin_property->object_type != object_name) { + exceptions.emplace_back("Property '%1.%2' declared as origin of linking objects property '%3.%4' links to type '%5'", + prop.object_type, prop.link_origin_property_name, + object_name, prop.name, origin_property->object_type); + } +} + +void ObjectSchema::validate(Schema const& schema, std::vector& exceptions) const +{ + std::vector public_property_names; + std::vector internal_property_names; + internal_property_names.reserve(persisted_properties.size() + computed_properties.size()); + auto gather_names = [&](auto const &properties) { + for (auto const &prop : properties) { + internal_property_names.push_back(prop.name); + if (!prop.public_name.empty()) + public_property_names.push_back(prop.public_name); + } + }; + gather_names(persisted_properties); + gather_names(computed_properties); + std::sort(public_property_names.begin(), public_property_names.end()); + std::sort(internal_property_names.begin(), internal_property_names.end()); + + // Check that property names and aliases are unique + auto for_each_duplicate = [](auto &&container, auto &&fn) { + auto end = container.end(); + for (auto it = std::adjacent_find(container.begin(), end); it != end; it = std::adjacent_find(it + 2, end)) + fn(*it); + }; + for_each_duplicate(public_property_names, [&](auto public_property_name) { + exceptions.emplace_back("Alias '%1' appears more than once in the schema for type '%2'.", + public_property_name, name); + }); + for_each_duplicate(internal_property_names, [&](auto internal_name) { + exceptions.emplace_back("Property '%1' appears more than once in the schema for type '%2'.", + internal_name, name); + }); + + // Check that no aliases conflict with property names + struct ErrorWriter { + ObjectSchema const& os; + std::vector& exceptions; + + ErrorWriter& operator=(StringData name) { + exceptions.emplace_back("Property '%1.%2' has an alias '%3' that conflicts with a property of the same name.", + os.name, os.property_for_public_name(name)->name, name); + return *this; + } + + ErrorWriter(ErrorWriter const&) = default; + ErrorWriter& operator=(ErrorWriter const&) { return *this; } + ErrorWriter& operator*() { return *this; } + ErrorWriter& operator++() { return *this; } + ErrorWriter& operator++(int) { return *this; } + } writer{*this, exceptions}; + std::set_intersection(public_property_names.begin(), public_property_names.end(), + internal_property_names.begin(), internal_property_names.end(), writer); + + // Validate all properties + const Property *primary = nullptr; + for (auto const& prop : persisted_properties) { + validate_property(schema, *this, prop, &primary, exceptions); + } + for (auto const& prop : computed_properties) { + validate_property(schema, *this, prop, &primary, exceptions); + } + + if (!primary_key.empty() && is_embedded) { + exceptions.emplace_back("Embedded object type '%1' cannot have a primary key.", name); + } + if (!primary_key.empty() && !primary && !primary_key_property()) { + exceptions.emplace_back("Specified primary key '%1.%2' does not exist.", name, primary_key); + } +} + +namespace realm { +bool operator==(ObjectSchema const& a, ObjectSchema const& b) noexcept +{ + return std::tie(a.name, a.is_embedded, a.primary_key, a.persisted_properties, a.computed_properties) + == std::tie(b.name, b.is_embedded, b.primary_key, b.persisted_properties, b.computed_properties); + +} +} diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/object_store.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/object_store.cpp new file mode 100644 index 0000000..6b43fd4 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/object_store.cpp @@ -0,0 +1,899 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// 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 "object_store.hpp" + +#include "feature_checks.hpp" +#include "object_schema.hpp" +#include "schema.hpp" +#include "shared_realm.hpp" + +#include +#include +#include +#include + +#if REALM_ENABLE_SYNC +#include +#include +#endif // REALM_ENABLE_SYNC + +#include + +using namespace realm; + +constexpr uint64_t ObjectStore::NotVersioned; + +namespace { +const char * const c_metadataTableName = "metadata"; +const char * const c_versionColumnName = "version"; + +const char c_object_table_prefix[] = "class_"; + +void create_metadata_tables(Group& group) { + // The 'metadata' table is simply ignored by Sync + TableRef metadata_table = group.get_or_add_table(c_metadataTableName); + + if (metadata_table->get_column_count() == 0) { + metadata_table->add_column(type_Int, c_versionColumnName); + metadata_table->create_object().set(c_versionColumnName, int64_t(ObjectStore::NotVersioned)); + } +} + +void set_schema_version(Group& group, uint64_t version) { + group.get_table(c_metadataTableName)->get_object(0).set(c_versionColumnName, version); +} + +template +auto table_for_object_schema(Group& group, ObjectSchema const& object_schema) +{ + return ObjectStore::table_for_object_type(group, object_schema.name); +} + +DataType to_core_type(PropertyType type) +{ + REALM_ASSERT(type != PropertyType::Object); // Link columns have to be handled differently + REALM_ASSERT(type != PropertyType::Any); // Mixed columns can't be created + switch (type & ~PropertyType::Flags) { + case PropertyType::Int: return type_Int; + case PropertyType::Bool: return type_Bool; + case PropertyType::Float: return type_Float; + case PropertyType::Double: return type_Double; + case PropertyType::String: return type_String; + case PropertyType::Date: return type_Timestamp; + case PropertyType::Data: return type_Binary; + case PropertyType::ObjectId: return type_ObjectId; + case PropertyType::Decimal: return type_Decimal; + default: REALM_COMPILER_HINT_UNREACHABLE(); + } +} + +ColKey add_column(Group& group, Table& table, Property const& property) +{ + // Cannot directly insert a LinkingObjects column (a computed property). + // LinkingObjects must be an artifact of an existing link column. + REALM_ASSERT(property.type != PropertyType::LinkingObjects); + + if (property.is_primary) { + // Primary key columns should have been created when the table was created + if (auto col = table.get_column_key(property.name)) { + return col; + } + } + if (property.type == PropertyType::Object) { + auto target_name = ObjectStore::table_name_for_object_type(property.object_type); + TableRef link_table = group.get_table(target_name); + REALM_ASSERT(link_table); + return table.add_column_link(is_array(property.type) ? type_LinkList : type_Link, + property.name, *link_table); + } + else if (is_array(property.type)) { + return table.add_column_list(to_core_type(property.type & ~PropertyType::Flags), + property.name, is_nullable(property.type)); + } + else { + auto key = table.add_column(to_core_type(property.type), property.name, is_nullable(property.type)); + if (property.requires_index()) + table.add_search_index(key); + return key; + } +} + +void replace_column(Group& group, Table& table, Property const& old_property, + Property const& new_property) +{ + table.remove_column(old_property.column_key); + add_column(group, table, new_property); +} + +TableRef create_table(Group& group, ObjectSchema const& object_schema) +{ + auto name = ObjectStore::table_name_for_object_type(object_schema.name); + + TableRef table = group.get_table(name); + if (table) + return table; + + if (auto* pk_property = object_schema.primary_key_property()) { + table = group.add_table_with_primary_key(name, to_core_type(pk_property->type), pk_property->name, + is_nullable(pk_property->type)); + } + else { + if (object_schema.is_embedded) { + table = group.add_embedded_table(name); + } + else { + table = group.get_or_add_table(name); + } + } + + return table; +} + +void add_initial_columns(Group& group, ObjectSchema const& object_schema) +{ + auto name = ObjectStore::table_name_for_object_type(object_schema.name); + TableRef table = group.get_table(name); + + for (auto const& prop : object_schema.persisted_properties) { +#if REALM_ENABLE_SYNC + // The sync::create_table* functions create the PK column for us. + if (prop.is_primary) + continue; +#endif // REALM_ENABLE_SYNC + add_column(group, *table, prop); + } +} + +void make_property_optional(Table& table, Property property) +{ + property.type |= PropertyType::Nullable; + const bool throw_on_null = false; + property.column_key = table.set_nullability(property.column_key, true, throw_on_null); +} + +void make_property_required(Group& group, Table& table, Property property) +{ + property.type &= ~PropertyType::Nullable; + table.remove_column(property.column_key); + property.column_key = add_column(group, table, property).value; +} + +void add_search_index(Table& table, Property property) +{ + table.add_search_index(table.get_column_key(property.name)); +} + +void remove_search_index(Table& table, Property property) +{ + table.remove_search_index(table.get_column_key(property.name)); +} + +} // anonymous namespace + +void ObjectStore::set_schema_version(Group& group, uint64_t version) { + ::create_metadata_tables(group); + ::set_schema_version(group, version); +} + +uint64_t ObjectStore::get_schema_version(Group const& group) { + ConstTableRef table = group.get_table(c_metadataTableName); + if (!table || table->get_column_count() == 0) { + return ObjectStore::NotVersioned; + } + return table->get_object(0).get(c_versionColumnName); +} + +StringData ObjectStore::get_primary_key_for_object(Group const& group, StringData object_type) { + if (ConstTableRef table = table_for_object_type(group, object_type)) { + if (auto col = table->get_primary_key_column()) { + return table->get_column_name(col); + } + } + return ""; +} + +void ObjectStore::set_primary_key_for_object(Group& group, StringData object_type, StringData primary_key) { + auto t = table_for_object_type(group, object_type); + ColKey pk_col; + if (primary_key.size()) { + pk_col = t->get_column_key(primary_key); + REALM_ASSERT(pk_col); + } + t->set_primary_key_column(pk_col); +} + +StringData ObjectStore::object_type_for_table_name(StringData table_name) { + if (table_name.begins_with(c_object_table_prefix)) { + return table_name.substr(sizeof(c_object_table_prefix) - 1); + } + return StringData(); +} + +std::string ObjectStore::table_name_for_object_type(StringData object_type) { + return std::string(c_object_table_prefix) + std::string(object_type); +} + +TableRef ObjectStore::table_for_object_type(Group& group, StringData object_type) { + auto name = table_name_for_object_type(object_type); + return group.get_table(name); +} + +ConstTableRef ObjectStore::table_for_object_type(Group const& group, StringData object_type) { + auto name = table_name_for_object_type(object_type); + return group.get_table(name); +} + +namespace { +struct SchemaDifferenceExplainer { + std::vector errors; + + void operator()(schema_change::AddTable op) + { + errors.emplace_back("Class '%1' has been added.", op.object->name); + } + + void operator()(schema_change::RemoveTable) + { + // We never do anything for RemoveTable + } + + void operator()(schema_change::ChangeTableType op) + { + if (op.object->is_embedded) + errors.emplace_back("Class '%1' has been changed from top-level to embedded.", op.object->name); + else + errors.emplace_back("Class '%1' has been changed from embedded to top-level.", op.object->name); + } + + void operator()(schema_change::AddInitialProperties) + { + // Nothing. Always preceded by AddTable. + } + + void operator()(schema_change::AddProperty op) + { + errors.emplace_back("Property '%1.%2' has been added.", op.object->name, op.property->name); + } + + void operator()(schema_change::RemoveProperty op) + { + errors.emplace_back("Property '%1.%2' has been removed.", op.object->name, op.property->name); + } + + void operator()(schema_change::ChangePropertyType op) + { + errors.emplace_back("Property '%1.%2' has been changed from '%3' to '%4'.", + op.object->name, op.new_property->name, + op.old_property->type_string(), + op.new_property->type_string()); + } + + void operator()(schema_change::MakePropertyNullable op) + { + errors.emplace_back("Property '%1.%2' has been made optional.", op.object->name, op.property->name); + } + + void operator()(schema_change::MakePropertyRequired op) + { + errors.emplace_back("Property '%1.%2' has been made required.", op.object->name, op.property->name); + } + + void operator()(schema_change::ChangePrimaryKey op) + { + if (op.property && !op.object->primary_key.empty()) { + errors.emplace_back("Primary Key for class '%1' has changed from '%2' to '%3'.", + op.object->name, op.object->primary_key, op.property->name); + } + else if (op.property) { + errors.emplace_back("Primary Key for class '%1' has been added.", op.object->name); + } + else { + errors.emplace_back("Primary Key for class '%1' has been removed.", op.object->name); + } + } + + void operator()(schema_change::AddIndex op) + { + errors.emplace_back("Property '%1.%2' has been made indexed.", op.object->name, op.property->name); + } + + void operator()(schema_change::RemoveIndex op) + { + errors.emplace_back("Property '%1.%2' has been made unindexed.", op.object->name, op.property->name); + } +}; + +class TableHelper { +public: + TableHelper(Group& g) : m_group(g) { } + + Table& operator()(const ObjectSchema* object_schema) + { + if (object_schema != m_current_object_schema) { + m_current_table = table_for_object_schema(m_group, *object_schema); + m_current_object_schema = object_schema; + } + REALM_ASSERT(m_current_table); + return *m_current_table; + } + +private: + Group& m_group; + const ObjectSchema* m_current_object_schema = nullptr; + TableRef m_current_table; +}; + +template +void verify_no_errors(Verifier&& verifier, std::vector const& changes) +{ + for (auto& change : changes) { + change.visit(verifier); + } + + if (!verifier.errors.empty()) { + throw ErrorType(verifier.errors); + } +} +} // anonymous namespace + +bool ObjectStore::needs_migration(std::vector const& changes) +{ + using namespace schema_change; + struct Visitor { + bool operator()(AddIndex) { return false; } + bool operator()(AddInitialProperties) { return false; } + bool operator()(AddProperty) { return true; } + bool operator()(AddTable) { return false; } + bool operator()(RemoveTable) { return false; } + bool operator()(ChangeTableType) { return true; } + bool operator()(ChangePrimaryKey) { return true; } + bool operator()(ChangePropertyType) { return true; } + bool operator()(MakePropertyNullable) { return true; } + bool operator()(MakePropertyRequired) { return true; } + bool operator()(RemoveIndex) { return false; } + bool operator()(RemoveProperty) { return true; } + }; + + return std::any_of(begin(changes), end(changes), + [](auto&& change) { return change.visit(Visitor()); }); +} + +void ObjectStore::verify_no_changes_required(std::vector const& changes) +{ + verify_no_errors(SchemaDifferenceExplainer(), changes); +} + +void ObjectStore::verify_no_migration_required(std::vector const& changes) +{ + using namespace schema_change; + struct Verifier : SchemaDifferenceExplainer { + using SchemaDifferenceExplainer::operator(); + + // Adding a table or adding/removing indexes can be done automatically. + // All other changes require migrations. + void operator()(AddTable) { } + void operator()(AddInitialProperties) { } + void operator()(AddIndex) { } + void operator()(RemoveIndex) { } + } verifier; + verify_no_errors(verifier, changes); +} + +bool ObjectStore::verify_valid_additive_changes(std::vector const& changes, bool update_indexes) +{ + using namespace schema_change; + struct Verifier : SchemaDifferenceExplainer { + using SchemaDifferenceExplainer::operator(); + + bool index_changes = false; + bool other_changes = false; + + // Additive mode allows adding things, extra columns, and adding/removing indexes + void operator()(AddTable) { other_changes = true; } + void operator()(AddInitialProperties) { other_changes = true; } + void operator()(AddProperty) { other_changes = true; } + void operator()(RemoveProperty) { } + void operator()(AddIndex) { index_changes = true; } + void operator()(RemoveIndex) { index_changes = true; } + } verifier; + verify_no_errors(verifier, changes); + return verifier.other_changes || (verifier.index_changes && update_indexes); +} + +void ObjectStore::verify_valid_external_changes(std::vector const& changes) +{ + using namespace schema_change; + struct Verifier : SchemaDifferenceExplainer { + using SchemaDifferenceExplainer::operator(); + + // Adding new things is fine + void operator()(AddTable) { } + void operator()(AddInitialProperties) { } + void operator()(AddProperty) { } + void operator()(AddIndex) { } + void operator()(RemoveIndex) { } + + // Deleting tables is not okay + void operator()(RemoveTable op) { + errors.emplace_back("Class '%1' has been removed.", op.object->name); + } + } verifier; + verify_no_errors(verifier, changes); +} + +void ObjectStore::verify_compatible_for_immutable_and_readonly(std::vector const& changes) +{ + using namespace schema_change; + struct Verifier : SchemaDifferenceExplainer { + using SchemaDifferenceExplainer::operator(); + + void operator()(AddTable) { } + void operator()(AddInitialProperties) { } + void operator()(ChangeTableType) { } + void operator()(RemoveProperty) { } + void operator()(AddIndex) { } + void operator()(RemoveIndex) { } + } verifier; + verify_no_errors(verifier, changes); +} + +static void apply_non_migration_changes(Group& group, std::vector const& changes) +{ + using namespace schema_change; + struct Applier : SchemaDifferenceExplainer { + Applier(Group& group) : group{group}, table{group} { } + Group& group; + TableHelper table; + + // Produce an exception listing the unsupported schema changes for + // everything but the explicitly supported ones + using SchemaDifferenceExplainer::operator(); + + void operator()(AddTable op) { create_table(group, *op.object); } + void operator()(AddInitialProperties op) { add_initial_columns(group, *op.object); } + void operator()(AddIndex op) { table(op.object).add_search_index(op.property->column_key); } + void operator()(RemoveIndex op) { table(op.object).remove_search_index(op.property->column_key); } + } applier{group}; + verify_no_errors(applier, changes); +} + +static void set_embedded(Table& table, ObjectSchema::IsEmbedded is_embedded) +{ + if (!table.set_embedded(is_embedded) && is_embedded) { + auto msg = util::format("Cannot convert object type '%1' to embedded because objects have multiple incoming links.", + ObjectStore::object_type_for_table_name(table.get_name())); + throw std::logic_error(std::move(msg)); + } +} + +static void create_initial_tables(Group& group, std::vector const& changes) +{ + using namespace schema_change; + struct Applier { + Applier(Group& group) : group{group}, table{group} { } + Group& group; + TableHelper table; + + void operator()(AddTable op) { create_table(group, *op.object); } + void operator()(RemoveTable) { } + void operator()(AddInitialProperties op) { add_initial_columns(group, *op.object); } + + // Note that in normal operation none of these will be hit, as if we're + // creating the initial tables there shouldn't be anything to update. + // Implementing these makes us better able to handle weird + // not-quite-correct files produced by other things and has no obvious + // downside. + void operator()(ChangeTableType op) { set_embedded(table(op.object), op.object->is_embedded); } + void operator()(AddProperty op) { add_column(group, table(op.object), *op.property); } + void operator()(RemoveProperty op) { table(op.object).remove_column(op.property->column_key); } + void operator()(MakePropertyNullable op) { make_property_optional(table(op.object), *op.property); } + void operator()(MakePropertyRequired op) { make_property_required(group, table(op.object), *op.property); } + void operator()(ChangePrimaryKey op) { ObjectStore::set_primary_key_for_object(group, op.object->name, op.property ? StringData{op.property->name} : ""); } + void operator()(AddIndex op) { add_search_index(table(op.object), *op.property); } + void operator()(RemoveIndex op) { remove_search_index(table(op.object), *op.property); } + + void operator()(ChangePropertyType op) + { + replace_column(group, table(op.object), *op.old_property, *op.new_property); + } + } applier{group}; + + for (auto& change : changes) { + change.visit(applier); + } +} + +void ObjectStore::apply_additive_changes(Group& group, std::vector const& changes, bool update_indexes) +{ + using namespace schema_change; + struct Applier { + Applier(Group& group, bool update_indexes) + : group{group}, table{group}, update_indexes{update_indexes} { } + Group& group; + TableHelper table; + bool update_indexes; + + void operator()(AddTable op) { create_table(group, *op.object); } + void operator()(RemoveTable) { } + void operator()(AddInitialProperties op) { add_initial_columns(group, *op.object); } + void operator()(AddProperty op) { add_column(group, table(op.object), *op.property); } + void operator()(AddIndex op) { if (update_indexes) table(op.object).add_search_index(op.property->column_key); } + void operator()(RemoveIndex op) { if (update_indexes) table(op.object).remove_search_index(op.property->column_key); } + void operator()(RemoveProperty) { } + + // No need for errors for these, as we've already verified that they aren't present + void operator()(ChangeTableType) { } + void operator()(ChangePrimaryKey) { } + void operator()(ChangePropertyType) { } + void operator()(MakePropertyNullable) { } + void operator()(MakePropertyRequired) { } + } applier{group, update_indexes}; + + for (auto& change : changes) { + change.visit(applier); + } +} + +static void apply_pre_migration_changes(Group& group, std::vector const& changes) +{ + using namespace schema_change; + struct Applier { + Applier(Group& group) : group{group}, table{group} { } + Group& group; + TableHelper table; + + void operator()(AddTable op) { create_table(group, *op.object); } + void operator()(RemoveTable) { } + void operator()(ChangeTableType op) { set_embedded(table(op.object), op.object->is_embedded); } + void operator()(AddInitialProperties op) { add_initial_columns(group, *op.object); } + void operator()(AddProperty op) { add_column(group, table(op.object), *op.property); } + void operator()(RemoveProperty) { /* delayed until after the migration */ } + void operator()(ChangePropertyType op) { replace_column(group, table(op.object), *op.old_property, *op.new_property); } + void operator()(MakePropertyNullable op) { make_property_optional(table(op.object), *op.property); } + void operator()(MakePropertyRequired op) { make_property_required(group, table(op.object), *op.property); } + void operator()(ChangePrimaryKey op) { table(op.object).set_primary_key_column(ColKey{}); } + void operator()(AddIndex op) { add_search_index(table(op.object), *op.property); } + void operator()(RemoveIndex op) { remove_search_index(table(op.object), *op.property); } + } applier{group}; + + for (auto& change : changes) { + change.visit(applier); + } +} + +enum class DidRereadSchema { Yes, No }; + +static void apply_post_migration_changes(Group& group, + std::vector const& changes, + Schema const& initial_schema, + DidRereadSchema did_reread_schema) +{ + using namespace schema_change; + struct Applier { + Applier(Group& group, Schema const& initial_schema, DidRereadSchema did_reread_schema) + : group{group}, initial_schema(initial_schema), table(group) + , did_reread_schema(did_reread_schema == DidRereadSchema::Yes) + { } + Group& group; + Schema const& initial_schema; + TableHelper table; + bool did_reread_schema; + + void operator()(RemoveProperty op) + { + if (!initial_schema.empty() && !initial_schema.find(op.object->name)->property_for_name(op.property->name)) + throw std::logic_error(util::format("Renamed property '%1.%2' does not exist.", op.object->name, op.property->name)); + auto table = table_for_object_schema(group, *op.object); + table->remove_column(op.property->column_key); + } + + void operator()(ChangePrimaryKey op) + { + Table& t = table(op.object); + if (op.property) { + auto col = t.get_column_key(op.property->name); + REALM_ASSERT(col); + t.set_primary_key_column(col); + } + else { + t.set_primary_key_column(ColKey()); + } + } + + void operator()(AddTable op) { create_table(group, *op.object); } + + void operator()(AddInitialProperties op) { + if (did_reread_schema) + add_initial_columns(group, *op.object); + else { + // If we didn't re-read the schema then AddInitialProperties was already taken care of + // during apply_pre_migration_changes. + } + } + + void operator()(AddIndex op) { table(op.object).add_search_index(op.property->column_key); } + void operator()(RemoveIndex op) { table(op.object).remove_search_index(op.property->column_key); } + + void operator()(ChangeTableType) { } + void operator()(RemoveTable) { } + void operator()(ChangePropertyType) { } + void operator()(MakePropertyNullable) { } + void operator()(MakePropertyRequired) { } + void operator()(AddProperty) { } + } applier{group, initial_schema, did_reread_schema}; + + for (auto& change : changes) { + change.visit(applier); + } +} + + +void ObjectStore::apply_schema_changes(Transaction& group, uint64_t schema_version, + Schema& target_schema, uint64_t target_schema_version, + SchemaMode mode, std::vector const& changes, + std::function migration_function) +{ + create_metadata_tables(group); + + if (mode == SchemaMode::Additive) { + bool target_schema_is_newer = (schema_version < target_schema_version + || schema_version == ObjectStore::NotVersioned); + + // With sync v2.x, indexes are no longer synced, so there's no reason to avoid creating them. + bool update_indexes = true; + apply_additive_changes(group, changes, update_indexes); + + if (target_schema_is_newer) + set_schema_version(group, target_schema_version); + + set_schema_keys(group, target_schema); + return; + } + + if (schema_version == ObjectStore::NotVersioned) { + create_initial_tables(group, changes); + set_schema_version(group, target_schema_version); + set_schema_keys(group, target_schema); + return; + } + + if (mode == SchemaMode::Manual) { + set_schema_keys(group, target_schema); + if (migration_function) { + migration_function(); + } + + verify_no_changes_required(schema_from_group(group).compare(target_schema)); + group.validate_primary_columns(); + set_schema_keys(group, target_schema); + set_schema_version(group, target_schema_version); + return; + } + + if (schema_version == target_schema_version) { + apply_non_migration_changes(group, changes); + set_schema_keys(group, target_schema); + return; + } + + auto old_schema = schema_from_group(group); + apply_pre_migration_changes(group, changes); + if (migration_function) { + set_schema_keys(group, target_schema); + migration_function(); + + // Migration function may have changed the schema, so we need to re-read it + auto schema = schema_from_group(group); + apply_post_migration_changes(group, schema.compare(target_schema), old_schema, DidRereadSchema::Yes); + group.validate_primary_columns(); + } + else { + apply_post_migration_changes(group, changes, {}, DidRereadSchema::No); + } + + set_schema_version(group, target_schema_version); + set_schema_keys(group, target_schema); +} + +Schema ObjectStore::schema_from_group(Group const& group) { + std::vector schema; + schema.reserve(group.size()); + for (auto key : group.get_table_keys()) { + auto object_type = object_type_for_table_name(group.get_table_name(key)); + if (object_type.size()) { + schema.emplace_back(group, object_type, key); + } + } + return schema; +} + +util::Optional ObjectStore::property_for_column_key(ConstTableRef& table, ColKey column_key) +{ + StringData column_name = table->get_column_name(column_key); + + Property property; + property.name = column_name; + property.type = ObjectSchema::from_core_type(column_key); + property.is_primary = table->get_primary_key_column() == column_key; + property.is_indexed = table->has_search_index(column_key); + property.column_key = column_key; + + if (property.type == PropertyType::Object) { + // set link type for objects and arrays + ConstTableRef linkTable = table->get_link_target(column_key); + property.object_type = ObjectStore::object_type_for_table_name(linkTable->get_name().data()); + } + return property; +} + +void ObjectStore::set_schema_keys(Group const& group, Schema& schema) +{ + for (auto& object_schema : schema) { + auto table = table_for_object_schema(group, object_schema); + if (!table) { + continue; + } + object_schema.table_key = table->get_key(); + for (auto& property : object_schema.persisted_properties) { + property.column_key = table->get_column_key(property.name); + } + } +} + +void ObjectStore::delete_data_for_object(Group& group, StringData object_type) +{ + if (TableRef table = table_for_object_type(group, object_type)) { + group.remove_table(table->get_key()); + } +} + +bool ObjectStore::is_empty(Group const& group) +{ + for (auto key : group.get_table_keys()) { + ConstTableRef table = group.get_table(key); + auto object_type = object_type_for_table_name(table->get_name()); + if (object_type.size() == 0 || object_type.begins_with("__")) { + continue; + } + if (!table->is_empty()) { + return false; + } + } + return true; +} + +void ObjectStore::rename_property(Group& group, Schema& target_schema, StringData object_type, StringData old_name, StringData new_name) +{ + TableRef table = table_for_object_type(group, object_type); + if (!table) { + throw std::logic_error(util::format("Cannot rename properties for type '%1' because it does not exist.", object_type)); + } + + auto target_object_schema = target_schema.find(object_type); + if (target_object_schema == target_schema.end()) { + throw std::logic_error(util::format("Cannot rename properties for type '%1' because it has been removed from the Realm.", object_type)); + } + + if (target_object_schema->property_for_name(old_name)) { + throw std::logic_error(util::format("Cannot rename property '%1.%2' to '%3' because the source property still exists.", + object_type, old_name, new_name)); + } + + ObjectSchema table_object_schema(group, object_type, table->get_key()); + Property *old_property = table_object_schema.property_for_name(old_name); + if (!old_property) { + throw std::logic_error(util::format("Cannot rename property '%1.%2' because it does not exist.", object_type, old_name)); + } + + Property *new_property = table_object_schema.property_for_name(new_name); + if (!new_property) { + // New property doesn't exist in the table, which means we're probably + // renaming to an intermediate property in a multi-version migration. + // This is safe because the migration will fail schema validation unless + // this property is renamed again to a valid name before the end. + table->rename_column(old_property->column_key, new_name); + return; + } + + if (old_property->type != new_property->type || old_property->object_type != new_property->object_type) { + throw std::logic_error(util::format("Cannot rename property '%1.%2' to '%3' because it would change from type '%4' to '%5'.", + object_type, old_name, new_name, old_property->type_string(), new_property->type_string())); + } + + if (is_nullable(old_property->type) && !is_nullable(new_property->type)) { + throw std::logic_error(util::format("Cannot rename property '%1.%2' to '%3' because it would change from optional to required.", + object_type, old_name, new_name)); + } + + table->remove_column(new_property->column_key); + table->rename_column(old_property->column_key, new_name); + + if (auto prop = target_object_schema->property_for_name(new_name)) { + prop->column_key = old_property->column_key; + } + + // update nullability for column + if (is_nullable(new_property->type) && !is_nullable(old_property->type)) { + auto prop = *new_property; + prop.column_key = old_property->column_key; + make_property_optional(*table, prop); + } +} + +InvalidSchemaVersionException::InvalidSchemaVersionException(uint64_t old_version, uint64_t new_version) +: logic_error(util::format("Provided schema version %1 is less than last set version %2.", new_version, old_version)) +, m_old_version(old_version), m_new_version(new_version) +{ +} + +static void append_errors(std::string& message, std::vector const& errors) +{ + for (auto const& error : errors) { + message += "\n- "; + message += error.what(); + } +} + +SchemaValidationException::SchemaValidationException(std::vector const& errors) +: std::logic_error([&] { + std::string message = "Schema validation failed due to the following errors:"; + append_errors(message, errors); + return message; +}()) +{ +} + +SchemaMismatchException::SchemaMismatchException(std::vector const& errors) +: std::logic_error([&] { + std::string message = "Migration is required due to the following errors:"; + append_errors(message, errors); + return message; +}()) +{ +} + +InvalidReadOnlySchemaChangeException::InvalidReadOnlySchemaChangeException(std::vector const& errors) +: std::logic_error([&] { + std::string message = "The following changes cannot be made in read-only schema mode:"; + append_errors(message, errors); + return message; +}()) +{ +} + +InvalidAdditiveSchemaChangeException::InvalidAdditiveSchemaChangeException(std::vector const& errors) +: std::logic_error([&] { + std::string message = "The following changes cannot be made in additive-only schema mode:"; + append_errors(message, errors); + return message; +}()) +{ +} + +InvalidExternalSchemaChangeException::InvalidExternalSchemaChangeException(std::vector const& errors) +: std::logic_error([&] { + std::string message = + "Unsupported schema changes were made by another client or process. For a " + "synchronized Realm, this may be due to the server reverting schema changes which " + "the local user did not have permission to make."; + append_errors(message, errors); + return message; +}()) +{ +} diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/placeholder.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/placeholder.cpp new file mode 100644 index 0000000..8936534 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/placeholder.cpp @@ -0,0 +1 @@ +// This file is intentionally left blank. diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/results.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/results.cpp new file mode 100644 index 0000000..3ae963c --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/results.cpp @@ -0,0 +1,1129 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// 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 "results.hpp" + +#include "impl/realm_coordinator.hpp" +#include "impl/results_notifier.hpp" +#include "audit.hpp" +#include "object_schema.hpp" +#include "object_store.hpp" +#include "schema.hpp" + +#include + +namespace realm { + +Results::Results() = default; +Results::~Results() = default; + +Results::Results(SharedRealm r, Query q, DescriptorOrdering o) +: m_realm(std::move(r)) +, m_query(std::move(q)) +, m_table(m_query.get_table()) +, m_descriptor_ordering(std::move(o)) +, m_mode(Mode::Query) +, m_mutex(m_realm && m_realm->is_frozen()) +{ +} + +Results::Results(SharedRealm r, ConstTableRef table) +: m_realm(std::move(r)) +, m_table(table) +, m_mode(Mode::Table) +, m_mutex(m_realm && m_realm->is_frozen()) +{ +} + +Results::Results(std::shared_ptr r, std::shared_ptr list) +: m_realm(std::move(r)) +, m_list(list) +, m_mode(Mode::List) +, m_mutex(m_realm && m_realm->is_frozen()) +{ +} + +Results::Results(std::shared_ptr r, std::shared_ptr list, DescriptorOrdering o) +: m_realm(std::move(r)) +, m_descriptor_ordering(std::move(o)) +, m_list(std::move(list)) +, m_mode(Mode::List) +, m_mutex(m_realm && m_realm->is_frozen()) +{ +} + +Results::Results(std::shared_ptr r, TableView tv, DescriptorOrdering o) +: m_realm(std::move(r)) +, m_table_view(std::move(tv)) +, m_descriptor_ordering(std::move(o)) +, m_mode(Mode::TableView) +, m_mutex(m_realm && m_realm->is_frozen()) +{ + m_table = m_table_view.get_parent(); +} + +Results::Results(std::shared_ptr r, std::shared_ptr lv, util::Optional q, SortDescriptor s) +: m_realm(std::move(r)) +, m_link_list(std::move(lv)) +, m_mode(Mode::LinkList) +, m_mutex(m_realm && m_realm->is_frozen()) +{ + m_table = m_link_list->get_target_table(); + if (q) { + m_query = std::move(*q); + m_mode = Mode::Query; + } + m_descriptor_ordering.append_sort(std::move(s)); +} + +Results::Results(const Results&) = default; +Results& Results::operator=(const Results&) = default; +Results::Results(Results&&) = default; +Results& Results::operator=(Results&&) = default; + +Results::Mode Results::get_mode() const noexcept +{ + util::CheckedUniqueLock lock(m_mutex); + return m_mode; +} + +bool Results::is_valid() const +{ + if (m_realm) { + m_realm->verify_thread(); + } + + // Here we cannot just use if (m_table) as it combines a check if the + // reference contains a value and if that value is valid. + // First we check if a table is referenced ... + if (m_table.unchecked_ptr() != nullptr) + return !!m_table; // ... and then we check if it is valid + + if (m_list) + return m_list->is_attached(); + + return true; +} + +void Results::validate_read() const +{ + // is_valid ensures that we're on the correct thread. + if (!is_valid()) + throw InvalidatedException(); +} + +void Results::validate_write() const +{ + validate_read(); + if (!m_realm || !m_realm->is_in_transaction()) + throw InvalidTransactionException("Must be in a write transaction"); +} + +size_t Results::size() +{ + util::CheckedUniqueLock lock(m_mutex); + return do_size(); +} + +size_t Results::do_size() +{ + validate_read(); + switch (m_mode) { + case Mode::Empty: return 0; + case Mode::Table: return m_table->size(); + case Mode::LinkList: return m_link_list->size(); + case Mode::List: + evaluate_sort_and_distinct_on_list(); + return m_list_indices ? m_list_indices->size() : m_list->size(); + case Mode::Query: + m_query.sync_view_if_needed(); + if (!m_descriptor_ordering.will_apply_distinct()) + return m_query.count(m_descriptor_ordering); + REALM_FALLTHROUGH; + case Mode::TableView: + do_evaluate_query_if_needed(); + return m_table_view.size(); + } + REALM_COMPILER_HINT_UNREACHABLE(); +} + +const ObjectSchema& Results::get_object_schema() const +{ + validate_read(); + + auto object_schema = m_object_schema.load(); + if (!object_schema) { + REALM_ASSERT(m_realm); + auto it = m_realm->schema().find(get_object_type()); + REALM_ASSERT(it != m_realm->schema().end()); + m_object_schema = object_schema = &*it; + } + + return *object_schema; +} + +StringData Results::get_object_type() const noexcept +{ + if (!m_table) { + return StringData(); + } + + return ObjectStore::object_type_for_table_name(m_table->get_name()); +} + +template +auto& Results::list_as() const +{ + return static_cast&>(*m_list); +} + +void Results::evaluate_sort_and_distinct_on_list() +{ + if (m_descriptor_ordering.is_empty()) + return; + + // We can't use the sorted list from the notifier if we're in a write + // transaction as we only check the transaction version to see if the data matches + if (m_notifier && m_notifier->get_list_indices(m_list_indices) && !m_realm->is_in_transaction()) + return; + + bool needs_update = m_list->has_changed(); + if (!m_list_indices) { + m_list_indices = std::vector{}; + needs_update = true; + } + if (!needs_update) + return; + if (m_list->is_empty()) { + m_list_indices->clear(); + return; + } + + util::Optional sort_order; + bool do_distinct = false; + auto sz = m_descriptor_ordering.size(); + for (size_t i = 0; i < sz; i++) { + auto descr = m_descriptor_ordering[i]; + if (descr->get_type() == DescriptorType::Sort) + sort_order = static_cast(descr)->is_ascending(0); + if (descr->get_type() == DescriptorType::Distinct) + do_distinct = true; + } + + if (do_distinct) + m_list->distinct(*m_list_indices, sort_order); + else if (sort_order) + m_list->sort(*m_list_indices, *sort_order); +} + +template +util::Optional Results::try_get(size_t ndx) +{ + validate_read(); + if (m_mode == Mode::List) { + evaluate_sort_and_distinct_on_list(); + if (m_list_indices) { + if (ndx < m_list_indices->size()) + return list_as().get((*m_list_indices)[ndx]); + } + else { + if (ndx < m_list->size()) + return list_as().get(ndx); + } + } + return util::none; +} + +Results::IteratorWrapper::IteratorWrapper(IteratorWrapper const& rgt) +{ + *this = rgt; +} + +Results::IteratorWrapper& Results::IteratorWrapper::operator=(IteratorWrapper const& rgt) +{ + if (rgt.m_it) + m_it = std::make_unique(*rgt.m_it); + return *this; +} + +Obj Results::IteratorWrapper::get(Table const& table, size_t ndx) +{ + // Using a Table iterator is much faster for repeated access into a table + // than indexing into it as the iterator caches the cluster the last accessed + // object is stored in. + if (!m_it && table.size() > 5) { + m_it = std::make_unique(table.begin()); + } + if (!m_it) { + return const_cast(table).get_object(ndx); + } + try { + return (*m_it)[ndx]; + } + catch (...) { + // Iterator might be outdated + m_it = std::make_unique(table.begin()); + return (*m_it)[ndx]; + } +} + +template<> +util::Optional Results::try_get(size_t row_ndx) +{ + validate_read(); + switch (m_mode) { + case Mode::Empty: + case Mode::List: + break; + case Mode::Table: + if (row_ndx < m_table->size()) + return m_table_iterator.get(*m_table, row_ndx); + break; + case Mode::LinkList: + if (update_linklist()) { + if (row_ndx < m_link_list->size()) + return m_link_list->get_object(row_ndx); + break; + } + REALM_FALLTHROUGH; + case Mode::Query: + case Mode::TableView: + do_evaluate_query_if_needed(); + if (row_ndx >= m_table_view.size()) + break; + if (m_update_policy == UpdatePolicy::Never && !m_table_view.is_obj_valid(row_ndx)) + return Obj{}; + return m_table_view.get(row_ndx); + } + return util::none; +} + +template +T Results::get(size_t row_ndx) +{ + util::CheckedUniqueLock lock(m_mutex); + if (auto row = try_get(row_ndx)) { + return *row; + } + throw OutOfBoundsIndexException{row_ndx, do_size()}; +} + +template +util::Optional Results::first() +{ + util::CheckedUniqueLock lock(m_mutex); + return try_get(0); +} + +template +util::Optional Results::last() +{ + util::CheckedUniqueLock lock(m_mutex); + validate_read(); + if (m_mode == Mode::Query) + do_evaluate_query_if_needed(); // avoid running the query twice (for size() and for get()) + return try_get(do_size() - 1); +} + +bool Results::update_linklist() +{ + REALM_ASSERT(m_update_policy == UpdatePolicy::Auto); + + if (!m_descriptor_ordering.is_empty()) { + m_query = do_get_query(); + m_mode = Mode::Query; + do_evaluate_query_if_needed(); + return false; + } + return true; +} + +void Results::evaluate_query_if_needed(bool wants_notifications) +{ + util::CheckedUniqueLock lock(m_mutex); + validate_read(); + do_evaluate_query_if_needed(wants_notifications); +} + +void Results::do_evaluate_query_if_needed(bool wants_notifications) +{ + if (m_update_policy == UpdatePolicy::Never) { + REALM_ASSERT(m_mode == Mode::TableView); + return; + } + + switch (m_mode) { + case Mode::Empty: + case Mode::Table: + case Mode::List: + case Mode::LinkList: + return; + case Mode::Query: + if (m_notifier && m_notifier->get_tableview(m_table_view)) { + m_mode = Mode::TableView; + break; + } + m_query.sync_view_if_needed(); + if (m_update_policy == UpdatePolicy::Auto) + m_table_view = m_query.find_all(m_descriptor_ordering); + m_mode = Mode::TableView; + REALM_FALLTHROUGH; + case Mode::TableView: + if (wants_notifications && !m_notifier) + prepare_async(ForCallback{false}); + else if (m_notifier) + m_notifier->get_tableview(m_table_view); + if (m_update_policy == UpdatePolicy::Auto) + m_table_view.sync_if_needed(); + if (auto audit = m_realm->audit_context()) + audit->record_query(m_realm->read_transaction_version(), m_table_view); + break; + } +} + +template<> +size_t Results::index_of(Obj const& row) +{ + util::CheckedUniqueLock lock(m_mutex); + validate_read(); + if (!row.is_valid()) { + throw DetatchedAccessorException{}; + } + if (m_table && row.get_table() != m_table) { + throw IncorrectTableException( + ObjectStore::object_type_for_table_name(m_table->get_name()), + ObjectStore::object_type_for_table_name(row.get_table()->get_name())); + } + + switch (m_mode) { + case Mode::Empty: + case Mode::List: + return not_found; + case Mode::Table: + return m_table->get_object_ndx(row.get_key()); + case Mode::LinkList: + if (update_linklist()) + return m_link_list->Lst::find_first(row.get_key()); + REALM_FALLTHROUGH; + case Mode::Query: + case Mode::TableView: + do_evaluate_query_if_needed(); + return m_table_view.find_by_source_ndx(row.get_key()); + } + REALM_COMPILER_HINT_UNREACHABLE(); +} + +template +size_t Results::index_of(T const& value) +{ + util::CheckedUniqueLock lock(m_mutex); + validate_read(); + if (m_mode != Mode::List) + return not_found; // Non-List results can only ever contain Objects + evaluate_sort_and_distinct_on_list(); + if (m_list_indices) { + for (size_t i = 0; i < m_list_indices->size(); ++i) { + if (list_as().get((*m_list_indices)[i]) == value) + return i; + } + return not_found; + } + return list_as().find_first(value); +} + +size_t Results::index_of(Query&& q) +{ + if (m_descriptor_ordering.will_apply_sort()) { + Results filtered(filter(std::move(q))); + filtered.assert_unlocked(); + auto first = filtered.first(); + return first ? index_of(*first) : not_found; + } + + auto query = get_query().and_query(std::move(q)); + query.sync_view_if_needed(); + ObjKey row = query.find(); + return row ? index_of(const_cast(*m_table).get_object(row)) : not_found; +} + +DataType Results::prepare_for_aggregate(ColKey column, const char* name) +{ + DataType type; + switch (m_mode) { + case Mode::Table: + type = m_table->get_column_type(column); + break; + case Mode::List: + type = m_list->get_table()->get_column_type(m_list->get_col_key()); + break; + case Mode::LinkList: + m_query = do_get_query(); + m_mode = Mode::Query; + REALM_FALLTHROUGH; + case Mode::Query: + case Mode::TableView: + do_evaluate_query_if_needed(); + type = m_table->get_column_type(column); + break; + default: + REALM_COMPILER_HINT_UNREACHABLE(); + } + switch (type) { + case type_Timestamp: case type_Double: case type_Float: case type_Int: case type_Decimal: break; + default: throw UnsupportedColumnTypeException{column, *m_table, name}; + } + return type; +} + +namespace { +template +struct AggregateHelper; + +template +struct AggregateHelper { + Table& table; + Mixed min(ColKey col, ObjKey* obj) { return table.minimum_int(col, obj); } + Mixed max(ColKey col, ObjKey* obj) { return table.maximum_int(col, obj); } + Mixed sum(ColKey col) { return table.sum_int(col); } + Mixed avg(ColKey col, size_t* count) { return table.average_int(col, count); } +}; + +template +struct AggregateHelper { + Table& table; + Mixed min(ColKey col, ObjKey* obj) { return table.minimum_double(col, obj); } + Mixed max(ColKey col, ObjKey* obj) { return table.maximum_double(col, obj); } + Mixed sum(ColKey col) { return table.sum_double(col); } + Mixed avg(ColKey col, size_t* count) { return table.average_double(col, count); } +}; + +template +struct AggregateHelper { + Table& table; + Mixed min(ColKey col, ObjKey* obj) { return table.minimum_float(col, obj); } + Mixed max(ColKey col, ObjKey* obj) { return table.maximum_float(col, obj); } + Mixed sum(ColKey col) { return table.sum_float(col); } + Mixed avg(ColKey col, size_t* count) { return table.average_float(col, count); } +}; + +template +struct AggregateHelper { + Table& table; + Mixed min(ColKey col, ObjKey* obj) { return table.minimum_timestamp(col, obj); } + Mixed max(ColKey col, ObjKey* obj) { return table.maximum_timestamp(col, obj); } + Mixed sum(ColKey col) { throw Results::UnsupportedColumnTypeException{col, table, "sum"}; } + Mixed avg(ColKey col, size_t*) { throw Results::UnsupportedColumnTypeException{col, table, "avg"}; } +}; + +template +struct AggregateHelper { + Table& table; + Mixed min(ColKey col, ObjKey* obj) { return table.minimum_decimal(col, obj); } + Mixed max(ColKey col, ObjKey* obj) { return table.maximum_decimal(col, obj); } + Mixed sum(ColKey col) { return table.sum_decimal(col); } + Mixed avg(ColKey col, size_t* count) { return table.average_decimal(col, count); } +}; + +struct ListAggregateHelper { + LstBase& list; + Mixed min(ColKey, size_t* ndx) { return list.min(ndx); } + Mixed max(ColKey, size_t* ndx) { return list.max(ndx); } + Mixed sum(ColKey) { return list.sum(); } + Mixed avg(ColKey, size_t* count) { return list.avg(count); } +}; + +template<> struct AggregateHelper : ListAggregateHelper +{ AggregateHelper(LstBase& l) : ListAggregateHelper{l} {} }; +template<> struct AggregateHelper : ListAggregateHelper +{ AggregateHelper(LstBase& l) : ListAggregateHelper{l} {} }; +template<> struct AggregateHelper : ListAggregateHelper +{ AggregateHelper(LstBase& l) : ListAggregateHelper{l} {} }; +template<> struct AggregateHelper : ListAggregateHelper +{ AggregateHelper(LstBase& l) : ListAggregateHelper{l} {} }; + +template<> +struct AggregateHelper : ListAggregateHelper { + AggregateHelper(LstBase& l) : ListAggregateHelper{l} {} + Mixed sum(ColKey) { throw Results::UnsupportedColumnTypeException{list.get_col_key(), *list.get_table(), "sum"}; } + Mixed avg(ColKey, size_t*) { throw Results::UnsupportedColumnTypeException{list.get_col_key(), *list.get_table(), "avg"}; } +}; + +template +Mixed call_with_helper(Func&& func, Table&& table, DataType type) +{ + switch (type) { + case type_Timestamp: return func(AggregateHelper{table}); + case type_Double: return func(AggregateHelper{table}); + case type_Float: return func(AggregateHelper{table}); + case type_Int: return func(AggregateHelper{table}); + case type_Decimal: return func(AggregateHelper{table}); + default: REALM_COMPILER_HINT_UNREACHABLE(); + } +} + +struct ReturnIndexHelper { + ObjKey key; + size_t index = npos; + operator ObjKey*() { return &key; } + operator size_t*() { return &index; } + operator bool() { return key || index != npos; } +}; +} // anonymous namespace + +template +util::Optional Results::aggregate(ColKey column, const char* name, + AggregateFunction&& func) +{ + util::CheckedUniqueLock lock(m_mutex); + validate_read(); + if (!m_table && !m_list) + return none; + + auto type = prepare_for_aggregate(column, name); + switch (m_mode) { + case Mode::Table: + return call_with_helper(func, *m_table, type); + case Mode::List: + return call_with_helper(func, *m_list, type); + default: + return call_with_helper(func, m_table_view, type); + } +} + +util::Optional Results::max(ColKey column) +{ + ReturnIndexHelper return_ndx; + auto results = aggregate(column, "max", [&](auto&& helper) { + return helper.max(column, return_ndx); + }); + return return_ndx ? results : none; +} + +util::Optional Results::min(ColKey column) +{ + ReturnIndexHelper return_ndx; + auto results = aggregate(column, "min", [&](auto&& helper) { + return helper.min(column, return_ndx); + }); + return return_ndx ? results : none; +} + +util::Optional Results::sum(ColKey column) +{ + return aggregate(column, "sum", [&](auto&& helper) { return helper.sum(column); }); +} + +util::Optional Results::average(ColKey column) +{ + size_t value_count = 0; + auto results = aggregate(column, "avg", [&](auto&& helper) { + return helper.avg(column, &value_count); + }); + return value_count == 0 ? none : results; +} + +void Results::clear() +{ + util::CheckedUniqueLock lock(m_mutex); + switch (m_mode) { + case Mode::Empty: + return; + case Mode::Table: + validate_write(); + const_cast(*m_table).clear(); + break; + case Mode::Query: + // Not using Query:remove() because building the tableview and + // clearing it is actually significantly faster + case Mode::TableView: + validate_write(); + do_evaluate_query_if_needed(); + + switch (m_update_policy) { + case UpdatePolicy::Auto: + m_table_view.clear(); + break; + case UpdatePolicy::AsyncOnly: + case UpdatePolicy::Never: { + // Copy the TableView because a frozen Results shouldn't let its size() change. + TableView copy(m_table_view); + copy.clear(); + break; + } + } + break; + case Mode::List: + validate_write(); + m_list->clear(); + break; + case Mode::LinkList: + validate_write(); + m_link_list->remove_all_target_rows(); + break; + } +} + +PropertyType Results::get_type() const +{ + util::CheckedUniqueLock lock(m_mutex); + return do_get_type(); +} + +PropertyType Results::do_get_type() const +{ + validate_read(); + switch (m_mode) { + case Mode::Empty: + case Mode::LinkList: + return PropertyType::Object; + case Mode::Query: + case Mode::TableView: + case Mode::Table: + return PropertyType::Object; + case Mode::List: + return ObjectSchema::from_core_type(m_list->get_col_key()); + } + REALM_COMPILER_HINT_UNREACHABLE(); +} + +Query Results::get_query() const +{ + util::CheckedUniqueLock lock(m_mutex); + return do_get_query(); +} + +Query Results::do_get_query() const +{ + validate_read(); + switch (m_mode) { + case Mode::Empty: + case Mode::Query: + case Mode::List: + return m_query; + case Mode::TableView: { + if (const_cast(m_query).get_table()) + return m_query; + + // A TableView has an associated Query if it was produced by Query::find_all. This is indicated + // by TableView::get_query returning a Query with a non-null table. + Query query = m_table_view.get_query(); + if (query.get_table()) { + return query; + } + + // The TableView has no associated query so create one with no conditions that is restricted + // to the rows in the TableView. + if (m_update_policy == UpdatePolicy::Auto) { + m_table_view.sync_if_needed(); + } + return Query(m_table, std::unique_ptr(new TableView(m_table_view))); + } + case Mode::LinkList: + return m_table->where(*m_link_list); + case Mode::Table: + return m_table->where(); + } + REALM_COMPILER_HINT_UNREACHABLE(); +} + +TableView Results::get_tableview() +{ + util::CheckedUniqueLock lock(m_mutex); + validate_read(); + switch (m_mode) { + case Mode::Empty: + case Mode::List: + return {}; + case Mode::LinkList: + if (update_linklist()) + return m_table->where(*m_link_list).find_all(); + REALM_FALLTHROUGH; + case Mode::Query: + case Mode::TableView: + do_evaluate_query_if_needed(); + return m_table_view; + case Mode::Table: + return m_table->where().find_all(); + } + REALM_COMPILER_HINT_UNREACHABLE(); +} + +static std::vector parse_keypath(StringData keypath, Schema const& schema, + const ObjectSchema *object_schema) +{ + auto check = [&](bool condition, const char* fmt, auto... args) { + if (!condition) { + throw std::invalid_argument(util::format("Cannot sort on key path '%1': %2.", + keypath, util::format(fmt, args...))); + } + }; + auto is_sortable_type = [](PropertyType type) { + return !is_array(type) && type != PropertyType::LinkingObjects && type != PropertyType::Data; + }; + + const char* begin = keypath.data(); + const char* end = keypath.data() + keypath.size(); + check(begin != end, "missing property name"); + + std::vector indices; + while (begin != end) { + auto sep = std::find(begin, end, '.'); + check(sep != begin && sep + 1 != end, "missing property name"); + StringData key(begin, sep - begin); + begin = sep + (sep != end); + + auto prop = object_schema->property_for_name(key); + check(prop, "property '%1.%2' does not exist", object_schema->name, key); + check(is_sortable_type(prop->type), "property '%1.%2' is of unsupported type '%3'", + object_schema->name, key, string_for_property_type(prop->type)); + if (prop->type == PropertyType::Object) + check(begin != end, "property '%1.%2' of type 'object' cannot be the final property in the key path", + object_schema->name, key); + else + check(begin == end, "property '%1.%2' of type '%3' may only be the final property in the key path", + object_schema->name, key, prop->type_string()); + + indices.push_back(ColKey(prop->column_key)); + if (prop->type == PropertyType::Object) + object_schema = &*schema.find(prop->object_type); + } + return indices; +} + +Results Results::sort(std::vector> const& keypaths) const +{ + if (keypaths.empty()) + return *this; + auto type = get_type(); + if (type != PropertyType::Object) { + if (keypaths.size() != 1) + throw std::invalid_argument(util::format("Cannot sort array of '%1' on more than one key path", + string_for_property_type(type & ~PropertyType::Flags))); + if (keypaths[0].first != "self") + throw std::invalid_argument( + util::format("Cannot sort on key path '%1': arrays of '%2' can only be sorted on 'self'", + keypaths[0].first, string_for_property_type(type & ~PropertyType::Flags))); + return sort({{{}}, {keypaths[0].second}}); + } + + std::vector> column_keys; + std::vector ascending; + column_keys.reserve(keypaths.size()); + ascending.reserve(keypaths.size()); + + for (auto& keypath : keypaths) { + column_keys.push_back(parse_keypath(keypath.first, m_realm->schema(), + &get_object_schema())); + ascending.push_back(keypath.second); + } + return sort({std::move(column_keys), std::move(ascending)}); +} + +Results Results::sort(SortDescriptor&& sort) const +{ + util::CheckedUniqueLock lock(m_mutex); + DescriptorOrdering new_order = m_descriptor_ordering; + new_order.append_sort(std::move(sort)); + if (m_mode == Mode::LinkList) + return Results(m_realm, m_link_list, util::none, std::move(sort)); + else if (m_mode == Mode::List) + return Results(m_realm, m_list, std::move(new_order)); + return Results(m_realm, do_get_query(), std::move(new_order)); +} + +Results Results::filter(Query&& q) const +{ + if (m_descriptor_ordering.will_apply_limit()) + throw UnimplementedOperationException("Filtering a Results with a limit is not yet implemented"); + return Results(m_realm, get_query().and_query(std::move(q)), m_descriptor_ordering); +} + +Results Results::limit(size_t max_count) const +{ + auto new_order = m_descriptor_ordering; + new_order.append_limit(max_count); + return Results(m_realm, get_query(), std::move(new_order)); +} + +Results Results::apply_ordering(DescriptorOrdering&& ordering) +{ + DescriptorOrdering new_order = m_descriptor_ordering; + for (size_t i = 0; i < ordering.size(); ++i) { + switch (ordering.get_type(i)) { + case DescriptorType::Sort: { + auto sort = dynamic_cast(ordering[i]); + new_order.append_sort(std::move(*sort)); + break; + } + case DescriptorType::Distinct: { + auto distinct = dynamic_cast(ordering[i]); + new_order.append_distinct(std::move(*distinct)); + break; + } + case DescriptorType::Limit: { + auto limit = dynamic_cast(ordering[i]); + new_order.append_limit(std::move(*limit)); + break; + } + case DescriptorType::Include: { + auto include = dynamic_cast(ordering[i]); + new_order.append_include(std::move(*include)); + break; + } + } + } + return Results(m_realm, get_query(), std::move(new_order)); +} + +Results Results::distinct(DistinctDescriptor&& uniqueness) const +{ + DescriptorOrdering new_order = m_descriptor_ordering; + new_order.append_distinct(std::move(uniqueness)); + util::CheckedUniqueLock lock(m_mutex); + if (m_mode == Mode::List) + return Results(m_realm, m_list, std::move(new_order)); + return Results(m_realm, do_get_query(), std::move(new_order)); +} + +Results Results::distinct(std::vector const& keypaths) const +{ + if (keypaths.empty()) + return *this; + auto type = get_type(); + if (type != PropertyType::Object) { + if (keypaths.size() != 1) + throw std::invalid_argument(util::format("Cannot sort array of '%1' on more than one key path", + string_for_property_type(type & ~PropertyType::Flags))); + if (keypaths[0] != "self") + throw std::invalid_argument( + util::format("Cannot sort on key path '%1': arrays of '%2' can only be sorted on 'self'", keypaths[0], + string_for_property_type(type & ~PropertyType::Flags))); + return distinct(DistinctDescriptor({{ColKey()}})); + } + + std::vector> column_keys; + column_keys.reserve(keypaths.size()); + for (auto& keypath : keypaths) + column_keys.push_back(parse_keypath(keypath, m_realm->schema(), &get_object_schema())); + return distinct({std::move(column_keys)}); +} + +Results Results::snapshot() const& +{ + validate_read(); + auto clone = *this; + clone.assert_unlocked(); + return static_cast(clone).snapshot(); +} + +Results Results::snapshot() && +{ + util::CheckedUniqueLock lock(m_mutex); + validate_read(); + switch (m_mode) { + case Mode::Empty: + return Results(); + + case Mode::Table: + case Mode::LinkList: + m_query = do_get_query(); + m_mode = Mode::Query; + + REALM_FALLTHROUGH; + case Mode::Query: + case Mode::TableView: + case Mode::List: // FIXME Correct? + do_evaluate_query_if_needed(false); + m_notifier.reset(); + m_update_policy = UpdatePolicy::Never; + return std::move(*this); + } + REALM_COMPILER_HINT_UNREACHABLE(); +} + +// This function cannot be called on frozen results and so does not require locking +void Results::prepare_async(ForCallback force) NO_THREAD_SAFETY_ANALYSIS +{ + REALM_ASSERT(m_realm); + if (m_notifier) + return; + if (!m_realm->verify_notifications_available(force)) + return; + if (m_update_policy == UpdatePolicy::Never) { + if (force) + throw std::logic_error("Cannot create asynchronous query for snapshotted Results."); + return; + } + + REALM_ASSERT(!force || !m_realm->is_frozen()); + if (!force) { + // Don't do implicit background updates if we can't actually deliver them + if (!m_realm->can_deliver_notifications()) + return; + // Don't do implicit background updates if there isn't actually anything + // that needs to be run. + if (!m_query.get_table() && m_descriptor_ordering.is_empty()) + return; + } + + if (m_list) + m_notifier = std::make_shared<_impl::ListResultsNotifier>(*this); + else + m_notifier = std::make_shared<_impl::ResultsNotifier>(*this); + _impl::RealmCoordinator::register_notifier(m_notifier); +} + +NotificationToken Results::add_notification_callback(CollectionChangeCallback cb) & +{ + prepare_async(ForCallback{true}); + return {m_notifier, m_notifier->add_callback(std::move(cb))}; +} + +// This function cannot be called on frozen results and so does not require locking +bool Results::is_in_table_order() const NO_THREAD_SAFETY_ANALYSIS +{ + REALM_ASSERT(!m_realm || !m_realm->is_frozen()); + switch (m_mode) { + case Mode::Empty: + case Mode::Table: + case Mode::List: + return true; + case Mode::LinkList: + return false; + case Mode::Query: + return m_query.produces_results_in_table_order() + && !m_descriptor_ordering.will_apply_sort(); + case Mode::TableView: + return m_table_view.is_in_table_order(); + } + REALM_COMPILER_HINT_UNREACHABLE(); +} + +ColKey Results::key(StringData name) const +{ + return m_table->get_column_key(name); +} +#define REALM_RESULTS_TYPE(T) \ + template T Results::get(size_t); \ + template util::Optional Results::first(); \ + template util::Optional Results::last(); \ + template size_t Results::index_of(T const&); + +template Obj Results::get(size_t); +template util::Optional Results::first(); +template util::Optional Results::last(); + +REALM_RESULTS_TYPE(bool) +REALM_RESULTS_TYPE(int64_t) +REALM_RESULTS_TYPE(float) +REALM_RESULTS_TYPE(double) +REALM_RESULTS_TYPE(StringData) +REALM_RESULTS_TYPE(BinaryData) +REALM_RESULTS_TYPE(Timestamp) +REALM_RESULTS_TYPE(ObjectId) +REALM_RESULTS_TYPE(Decimal) +REALM_RESULTS_TYPE(util::Optional) +REALM_RESULTS_TYPE(util::Optional) +REALM_RESULTS_TYPE(util::Optional) +REALM_RESULTS_TYPE(util::Optional) +REALM_RESULTS_TYPE(util::Optional) + +#undef REALM_RESULTS_TYPE + +Results Results::freeze(std::shared_ptr const& frozen_realm) +{ + util::CheckedUniqueLock lock(m_mutex); + if (m_mode == Mode::Empty) + return *this; + switch (m_mode) { + case Mode::Table: + return Results(frozen_realm, frozen_realm->import_copy_of(m_table)); + case Mode::List: + return Results(frozen_realm, frozen_realm->import_copy_of(*m_list), m_descriptor_ordering); + case Mode::LinkList: { + std::shared_ptr frozen_ll(frozen_realm->import_copy_of(std::make_unique(*m_link_list)).release()); + + // If query/sort was provided for the original Results, mode would have changed to Query, so no need + // include them here. + return Results(frozen_realm, std::move(frozen_ll)); + } + case Mode::Query: + return Results(frozen_realm, *frozen_realm->import_copy_of(m_query, PayloadPolicy::Copy), m_descriptor_ordering); + case Mode::TableView: { + Results results(frozen_realm, *frozen_realm->import_copy_of(m_table_view, PayloadPolicy::Copy), m_descriptor_ordering); + results.assert_unlocked(); + results.evaluate_query_if_needed(false); + return results; + } + default: + REALM_COMPILER_HINT_UNREACHABLE(); + } +} + +bool Results::is_frozen() +{ + return !m_realm || m_realm->is_frozen(); +} + +Results::OutOfBoundsIndexException::OutOfBoundsIndexException(size_t r, size_t c) +: std::out_of_range(c == 0 ? util::format("Requested index %1 in empty Results", r) + : util::format("Requested index %1 greater than max %2", r, c - 1)) +, requested(r), valid_count(c) {} + +Results::IncorrectTableException::IncorrectTableException(StringData e, StringData a) +: std::logic_error(util::format("Object of type '%1' does not match Results type '%2'", a, e)) +, expected(e), actual(a) {} + +static std::string unsupported_operation_msg(ColKey column, Table const& table, const char* operation) +{ + auto type = ObjectSchema::from_core_type(column); + const char* column_type = string_for_property_type(type & ~PropertyType::Array); + if (!is_array(type)) + return util::format("Cannot %1 property '%2': operation not supported for '%3' properties", + operation, table.get_column_name(column), column_type); + return util::format("Cannot %1 '%2' array: operation not supported", + operation, column_type); +} + +Results::UnsupportedColumnTypeException::UnsupportedColumnTypeException(ColKey column, Table const& table, + const char* operation) +: std::logic_error(unsupported_operation_msg(column, table, operation)) +, column_key(column) +, column_name(table.get_column_name(column)) +, property_type(ObjectSchema::from_core_type(column) & ~PropertyType::Array) +{ +} + +Results::UnsupportedColumnTypeException::UnsupportedColumnTypeException(ColKey column, TableView const& tv, + const char* operation) +: UnsupportedColumnTypeException(column, *tv.get_target_table(), operation) +{ +} + +Results::InvalidPropertyException::InvalidPropertyException(StringData object_type, StringData property_name) +: std::logic_error(util::format("Property '%1.%2' does not exist", object_type, property_name)) +, object_type(object_type), property_name(property_name) +{ +} + +Results::UnimplementedOperationException::UnimplementedOperationException(const char* msg) +: std::logic_error(msg) +{ +} + +} // namespace realm diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/schema.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/schema.cpp new file mode 100644 index 0000000..132c229 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/schema.cpp @@ -0,0 +1,320 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// 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 "schema.hpp" + +#include "object_schema.hpp" +#include "object_store.hpp" +#include "object_schema.hpp" +#include "property.hpp" + +#include +#include +#include + +using namespace realm; + +namespace realm { +bool operator==(Schema const& a, Schema const& b) noexcept +{ + return static_cast(a) == static_cast(b); +} +} + +Schema::Schema() noexcept = default; +Schema::~Schema() = default; +Schema::Schema(Schema const&) = default; +Schema::Schema(Schema &&) noexcept = default; +Schema& Schema::operator=(Schema const&) = default; +Schema& Schema::operator=(Schema&&) noexcept = default; + +Schema::Schema(std::initializer_list types) : Schema(base(types)) { } + +Schema::Schema(base types) noexcept +: base(std::move(types)) +{ + std::sort(begin(), end(), [](ObjectSchema const& lft, ObjectSchema const& rgt) { + return lft.name < rgt.name; + }); +} + +Schema::iterator Schema::find(StringData name) noexcept +{ + auto it = std::lower_bound(begin(), end(), name, [](ObjectSchema const& lft, StringData rgt) { + return lft.name < rgt; + }); + if (it != end() && it->name != name) { + it = end(); + } + return it; +} + +Schema::const_iterator Schema::find(StringData name) const noexcept +{ + return const_cast(this)->find(name); +} + +Schema::iterator Schema::find(ObjectSchema const& object) noexcept +{ + return find(object.name); +} + +Schema::const_iterator Schema::find(ObjectSchema const& object) const noexcept +{ + return const_cast(this)->find(object); +} + +namespace { + +struct CheckObjectPath { + const ObjectSchema& object; + std::string path; +}; + +// a non-recursive search that returns a path to any embedded object that has multiple paths from the start +std::string do_check(Schema const& schema, const ObjectSchema& start) +{ + std::queue to_visit; + std::unordered_set visited; + to_visit.push(CheckObjectPath{start, start.name}); + + while (to_visit.size() > 0) { + auto current = to_visit.front(); + visited.insert(current.object.name); + for (auto& prop : current.object.persisted_properties) { + if (prop.type == PropertyType::Object) { + auto it = schema.find(prop.object_type); + REALM_ASSERT(it != schema.end()); // this succeeds if the schema is otherwise valid + auto next_path = current.path + "." + prop.name; + if (visited.find(prop.object_type) == visited.end()) { + to_visit.push(CheckObjectPath{*it, next_path}); + } + else if (it->is_embedded) { + return next_path; + } + } + } + to_visit.pop(); + } + return ""; +} + +void check_for_embedded_objects_loop(Schema const& schema, std::vector& exceptions) +{ + for (auto const& object : schema) { + if (object.is_embedded) { + std::string loop = do_check(schema, object); + if (!loop.empty()) { + exceptions.push_back(util::format("Cycles containing embedded objects are not currently supported: '%1'", loop)); + } + } + } +} +} + +void Schema::validate() const +{ + std::vector exceptions; + + // As the types are added sorted by name, we can detect duplicates by just looking at the following element. + auto find_next_duplicate = [&](const_iterator start) { + return std::adjacent_find(start, cend(), [](ObjectSchema const& lft, ObjectSchema const& rgt) { + return lft.name == rgt.name; + }); + }; + + for (auto it = find_next_duplicate(cbegin()); it != cend(); it = find_next_duplicate(++it)) { + exceptions.push_back(ObjectSchemaValidationException("Type '%1' appears more than once in the schema.", + it->name)); + } + + for (auto const& object : *this) { + object.validate(*this, exceptions); + } + + // TODO: remove this client side check once the server supports it + // or generates a better error message. + if (exceptions.empty()) { + // only attempt to check for loops if the rest of the schema is valid + // because we rely on all link types being defined + check_for_embedded_objects_loop(*this, exceptions); + } + + if (exceptions.size()) { + throw SchemaValidationException(exceptions); + } +} + +static void compare(ObjectSchema const& existing_schema, + ObjectSchema const& target_schema, + std::vector& changes) +{ + for (auto& current_prop : existing_schema.persisted_properties) { + auto target_prop = target_schema.property_for_name(current_prop.name); + + if (!target_prop) { + changes.emplace_back(schema_change::RemoveProperty{&existing_schema, ¤t_prop}); + continue; + } + if (target_schema.property_is_computed(*target_prop)) { + changes.emplace_back(schema_change::RemoveProperty{&existing_schema, ¤t_prop}); + continue; + } + if (current_prop.type != target_prop->type || + current_prop.object_type != target_prop->object_type || + is_array(current_prop.type) != is_array(target_prop->type)) { + + changes.emplace_back(schema_change::ChangePropertyType{&existing_schema, ¤t_prop, target_prop}); + continue; + } + if (is_nullable(current_prop.type) != is_nullable(target_prop->type)) { + if (is_nullable(current_prop.type)) + changes.emplace_back(schema_change::MakePropertyRequired{&existing_schema, ¤t_prop}); + else + changes.emplace_back(schema_change::MakePropertyNullable{&existing_schema, ¤t_prop}); + } + if (target_prop->requires_index()) { + if (!current_prop.is_indexed) + changes.emplace_back(schema_change::AddIndex{&existing_schema, ¤t_prop}); + } + else if (current_prop.requires_index()) { + changes.emplace_back(schema_change::RemoveIndex{&existing_schema, ¤t_prop}); + } + } + + for (auto& target_prop : target_schema.persisted_properties) { + if (!existing_schema.property_for_name(target_prop.name)) { + changes.emplace_back(schema_change::AddProperty{&existing_schema, &target_prop}); + } + } + + if (existing_schema.primary_key != target_schema.primary_key) { + changes.emplace_back(schema_change::ChangePrimaryKey{&existing_schema, target_schema.primary_key_property()}); + } +} + +template +void Schema::zip_matching(T&& a, U&& b, Func&& func) noexcept +{ + size_t i = 0, j = 0; + while (i < a.size() && j < b.size()) { + auto& object_schema = a[i]; + auto& matching_schema = b[j]; + int cmp = object_schema.name.compare(matching_schema.name); + if (cmp == 0) { + func(&object_schema, &matching_schema); + ++i; + ++j; + } + else if (cmp < 0) { + func(&object_schema, nullptr); + ++i; + } + else { + func(nullptr, &matching_schema); + ++j; + } + } + for (; i < a.size(); ++i) + func(&a[i], nullptr); + for (; j < b.size(); ++j) + func(nullptr, &b[j]); + +} + +std::vector Schema::compare(Schema const& target_schema, bool include_table_removals) const +{ + std::vector changes; + + // Add missing tables + zip_matching(target_schema, *this, [&](const ObjectSchema* target, const ObjectSchema* existing) { + if (target && !existing) { + changes.emplace_back(schema_change::AddTable{target}); + } + else if (existing && !target) { + if (include_table_removals) + changes.emplace_back(schema_change::RemoveTable{existing}); + } + else if (existing->is_embedded != target->is_embedded) + changes.emplace_back(schema_change::ChangeTableType{target}); + }); + + // Modify columns + zip_matching(target_schema, *this, [&](const ObjectSchema* target, const ObjectSchema* existing) { + if (target && existing) + ::compare(*existing, *target, changes); + else if (target) { + // Target is a new table -- add all properties + changes.emplace_back(schema_change::AddInitialProperties{target}); + } + // nothing for tables in existing but not target + }); + return changes; +} + +void Schema::copy_keys_from(realm::Schema const& other) noexcept +{ + zip_matching(*this, other, [&](ObjectSchema* existing, const ObjectSchema* other) { + if (!existing || !other) + return; + + existing->table_key = other->table_key; + for (auto& current_prop : other->persisted_properties) { + auto target_prop = existing->property_for_name(current_prop.name); + if (target_prop) { + target_prop->column_key = current_prop.column_key; + } + } + }); +} + +namespace realm { +bool operator==(SchemaChange const& lft, SchemaChange const& rgt) noexcept +{ + if (lft.m_kind != rgt.m_kind) + return false; + + using namespace schema_change; + struct Visitor { + SchemaChange const& value; + + #define REALM_SC_COMPARE(type, ...) \ + bool operator()(type rgt) const \ + { \ + auto cmp = [](auto&& v) { return std::tie(__VA_ARGS__); }; \ + return cmp(value.type) == cmp(rgt); \ + } + + REALM_SC_COMPARE(AddIndex, v.object, v.property) + REALM_SC_COMPARE(AddProperty, v.object, v.property) + REALM_SC_COMPARE(AddInitialProperties, v.object) + REALM_SC_COMPARE(AddTable, v.object) + REALM_SC_COMPARE(RemoveTable, v.object) + REALM_SC_COMPARE(ChangeTableType, v.object) + REALM_SC_COMPARE(ChangePrimaryKey, v.object, v.property) + REALM_SC_COMPARE(ChangePropertyType, v.object, v.old_property, v.new_property) + REALM_SC_COMPARE(MakePropertyNullable, v.object, v.property) + REALM_SC_COMPARE(MakePropertyRequired, v.object, v.property) + REALM_SC_COMPARE(RemoveIndex, v.object, v.property) + REALM_SC_COMPARE(RemoveProperty, v.object, v.property) + + #undef REALM_SC_COMPARE + } visitor{lft}; + return rgt.visit(visitor); +} +} // namespace realm diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/shared_realm.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/shared_realm.cpp new file mode 100644 index 0000000..71eaea8 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/shared_realm.cpp @@ -0,0 +1,907 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// 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 "shared_realm.hpp" + +#include "impl/collection_notifier.hpp" +#include "impl/realm_coordinator.hpp" +#include "impl/transact_log_handler.hpp" + +#include "audit.hpp" +#include "binding_context.hpp" +#include "list.hpp" +#include "object.hpp" +#include "object_schema.hpp" +#include "object_store.hpp" +#include "results.hpp" +#include "schema.hpp" +#include "thread_safe_reference.hpp" + +#include "util/scheduler.hpp" + +#include +#include +#include + +#if REALM_ENABLE_SYNC +#include "sync/impl/sync_file.hpp" +#include "sync/sync_config.hpp" +#include "sync/sync_manager.hpp" + +#include +#include +#endif + +using namespace realm; +using namespace realm::_impl; + +Realm::Realm(Config config, util::Optional version, std::shared_ptr<_impl::RealmCoordinator> coordinator, MakeSharedTag) +: m_config(std::move(config)) +, m_frozen_version(std::move(version)) +, m_scheduler(m_config.scheduler) +{ + if (!coordinator->get_cached_schema(m_schema, m_schema_version, m_schema_transaction_version)) { + m_group = coordinator->begin_read(); + read_schema_from_group_if_needed(); + coordinator->cache_schema(m_schema, m_schema_version, m_schema_transaction_version); + m_group = nullptr; + } + + m_coordinator = std::move(coordinator); +} + +Realm::~Realm() +{ + if (m_coordinator) { + m_coordinator->unregister_realm(this); + } +} + +Group& Realm::read_group() +{ + verify_open(); + + if (!m_group) + begin_read(m_frozen_version.value_or(VersionID{})); + return *m_group; +} + +Transaction& Realm::transaction() +{ + REALM_ASSERT(!m_config.immutable()); + return static_cast(read_group()); +} + +Transaction& Realm::transaction() const +{ + REALM_ASSERT(!m_config.immutable()); + // FIXME: read_group() is not even remotly const + return static_cast(const_cast(this)->read_group()); +} + +std::shared_ptr Realm::transaction_ref() +{ + return std::static_pointer_cast(m_group); +} + +std::shared_ptr Realm::duplicate() const +{ + return std::static_pointer_cast(m_coordinator->begin_read(read_transaction_version(), is_frozen())); +} + +std::shared_ptr& Realm::Internal::get_db(Realm& realm) { + return realm.m_coordinator->m_db; +} + +void Realm::Internal::begin_read(Realm& realm, VersionID version_id) +{ + realm.begin_read(version_id); +} + +void Realm::begin_read(VersionID version_id) +{ + REALM_ASSERT(!m_group); + m_group = m_coordinator->begin_read(version_id, bool(m_frozen_version)); + add_schema_change_handler(); + read_schema_from_group_if_needed(); +} + +SharedRealm Realm::get_shared_realm(Config config) +{ + auto coordinator = RealmCoordinator::get_coordinator(config.path); + return coordinator->get_realm(std::move(config), util::none); +} + +SharedRealm Realm::get_frozen_realm(Config config, VersionID version) +{ + auto coordinator = RealmCoordinator::get_coordinator(config.path); + SharedRealm realm = coordinator->get_realm(std::move(config), util::Optional(version)); + realm->set_auto_refresh(false); + return realm; +} + +SharedRealm Realm::get_shared_realm(ThreadSafeReference ref, std::shared_ptr scheduler) +{ + if (!scheduler) + scheduler = util::Scheduler::make_default(); + SharedRealm realm = ref.resolve>(nullptr); + REALM_ASSERT(realm); + auto& config = realm->config(); + auto coordinator = RealmCoordinator::get_coordinator(config.path); + if (auto realm = coordinator->get_cached_realm(config, scheduler)) + return realm; + realm->m_scheduler = scheduler; + coordinator->bind_to_context(*realm); + return realm; +} + +#if REALM_ENABLE_SYNC +std::shared_ptr Realm::get_synchronized_realm(Config config) +{ + auto coordinator = RealmCoordinator::get_coordinator(config.path); + return coordinator->get_synchronized_realm(std::move(config)); +} +#endif + +void Realm::set_schema(Schema const& reference, Schema schema) +{ + m_dynamic_schema = false; + schema.copy_keys_from(reference); + m_schema = std::move(schema); + notify_schema_changed(); +} + +void Realm::read_schema_from_group_if_needed() +{ + if (m_config.immutable()) { + REALM_ASSERT(m_group); + if (m_schema.empty()) { + m_schema_version = ObjectStore::get_schema_version(*m_group); + m_schema = ObjectStore::schema_from_group(*m_group); + } + return; + } + + Group& group = read_group(); + auto current_version = transaction().get_version_of_current_transaction().version; + if (m_schema_transaction_version == current_version) + return; + + m_schema_transaction_version = current_version; + m_schema_version = ObjectStore::get_schema_version(group); + auto schema = ObjectStore::schema_from_group(group); + if (m_coordinator) + m_coordinator->cache_schema(schema, m_schema_version, + m_schema_transaction_version); + + if (m_dynamic_schema) { + if (m_schema == schema) { + // The structure of the schema hasn't changed. Bring the table column indices up to date. + m_schema.copy_keys_from(schema); + } + else { + // The structure of the schema has changed, so replace our copy of the schema. + m_schema = std::move(schema); + } + } + else { + ObjectStore::verify_valid_external_changes(m_schema.compare(schema)); + m_schema.copy_keys_from(schema); + } + notify_schema_changed(); +} + +bool Realm::reset_file(Schema& schema, std::vector& required_changes) +{ + // FIXME: this does not work if multiple processes try to open the file at + // the same time, or even multiple threads if there is not any external + // synchronization. The latter is probably fixable, but making it + // multi-process-safe requires some sort of multi-process exclusive lock + m_group = nullptr; + m_coordinator->close(); + util::File::remove(m_config.path); + + m_schema = ObjectStore::schema_from_group(read_group()); + m_schema_version = ObjectStore::get_schema_version(read_group()); + required_changes = m_schema.compare(schema); + m_coordinator->clear_schema_cache_and_set_schema_version(m_schema_version); + return false; +} + +bool Realm::schema_change_needs_write_transaction(Schema& schema, + std::vector& changes, + uint64_t version) +{ + if (version == m_schema_version && changes.empty()) + return false; + + switch (m_config.schema_mode) { + case SchemaMode::Automatic: + if (version < m_schema_version && m_schema_version != ObjectStore::NotVersioned) + throw InvalidSchemaVersionException(m_schema_version, version); + return true; + + case SchemaMode::Immutable: + if (version != m_schema_version) + throw InvalidSchemaVersionException(m_schema_version, version); + REALM_FALLTHROUGH; + case SchemaMode::ReadOnlyAlternative: + ObjectStore::verify_compatible_for_immutable_and_readonly(changes); + return false; + + case SchemaMode::ResetFile: + if (m_schema_version == ObjectStore::NotVersioned) + return true; + if (m_schema_version == version && !ObjectStore::needs_migration(changes)) + return true; + reset_file(schema, changes); + return true; + + case SchemaMode::Additive: { + bool will_apply_index_changes = version > m_schema_version; + if (ObjectStore::verify_valid_additive_changes(changes, will_apply_index_changes)) + return true; + return version != m_schema_version; + } + + case SchemaMode::Manual: + if (version < m_schema_version && m_schema_version != ObjectStore::NotVersioned) + throw InvalidSchemaVersionException(m_schema_version, version); + if (version == m_schema_version) { + ObjectStore::verify_no_changes_required(changes); + REALM_UNREACHABLE(); // changes is non-empty so above line always throws + } + return true; + } + REALM_COMPILER_HINT_UNREACHABLE(); +} + +Schema Realm::get_full_schema() +{ + if (!m_config.immutable()) + do_refresh(); + + // If the user hasn't specified a schema previously then m_schema is always + // the full schema + if (m_dynamic_schema) + return m_schema; + + // Otherwise we may have a subset of the file's schema, so we need to get + // the complete thing to calculate what changes to make + if (m_config.immutable()) + return ObjectStore::schema_from_group(read_group()); + + Schema actual_schema; + uint64_t actual_version; + uint64_t version = -1; + bool got_cached = m_coordinator->get_cached_schema(actual_schema, actual_version, version); + if (!got_cached || version != transaction().get_version_of_current_transaction().version) + return ObjectStore::schema_from_group(read_group()); + return actual_schema; +} + +void Realm::set_schema_subset(Schema schema) +{ + REALM_ASSERT(m_dynamic_schema); + REALM_ASSERT(m_schema_version != ObjectStore::NotVersioned); + + std::vector changes = m_schema.compare(schema); + switch (m_config.schema_mode) { + case SchemaMode::Automatic: + case SchemaMode::ResetFile: + ObjectStore::verify_no_migration_required(changes); + break; + + case SchemaMode::Immutable: + case SchemaMode::ReadOnlyAlternative: + ObjectStore::verify_compatible_for_immutable_and_readonly(changes); + break; + + case SchemaMode::Additive: + ObjectStore::verify_valid_additive_changes(changes); + break; + + case SchemaMode::Manual: + ObjectStore::verify_no_changes_required(changes); + break; + } + + set_schema(m_schema, std::move(schema)); +} + +void Realm::update_schema(Schema schema, uint64_t version, MigrationFunction migration_function, + DataInitializationFunction initialization_function, bool in_transaction) +{ + schema.validate(); + + bool was_in_read_transaction = is_in_read_transaction(); + Schema actual_schema = get_full_schema(); + std::vector required_changes = actual_schema.compare(schema); + + if (!schema_change_needs_write_transaction(schema, required_changes, version)) { + if (!was_in_read_transaction) + m_group = nullptr; + set_schema(actual_schema, std::move(schema)); + return; + } + // Either the schema version has changed or we need to do non-migration changes + + // Cancel the write transaction if we exit this function before committing it + auto cleanup = util::make_scope_exit([&]() noexcept { + // When in_transaction is true, caller is responsible to cancel the transaction. + if (!in_transaction && is_in_transaction()) + cancel_transaction(); + if (!was_in_read_transaction) + m_group = nullptr; + }); + + if (!in_transaction) { + transaction().promote_to_write(); + + // Beginning the write transaction may have advanced the version and left + // us with nothing to do if someone else initialized the schema on disk + if (m_new_schema) { + actual_schema = *m_new_schema; + required_changes = actual_schema.compare(schema); + if (!schema_change_needs_write_transaction(schema, required_changes, version)) { + cancel_transaction(); + cache_new_schema(); + set_schema(actual_schema, std::move(schema)); + return; + } + } + cache_new_schema(); + } + + uint64_t old_schema_version = m_schema_version; + bool additive = m_config.schema_mode == SchemaMode::Additive; + if (migration_function && !additive) { + auto wrapper = [&] { + auto config = m_config; + config.schema_mode = SchemaMode::ReadOnlyAlternative; + config.schema = util::none; + // Don't go through the normal codepath for opening a Realm because + // we're using a mismatched config + auto old_realm = std::make_shared(std::move(config), none, m_coordinator, MakeSharedTag{}); + migration_function(old_realm, shared_from_this(), m_schema); + }; + + // migration function needs to see the target schema on the "new" Realm + std::swap(m_schema, schema); + std::swap(m_schema_version, version); + m_in_migration = true; + auto restore = util::make_scope_exit([&]() noexcept { + std::swap(m_schema, schema); + std::swap(m_schema_version, version); + m_in_migration = false; + }); + + ObjectStore::apply_schema_changes(transaction(), version, m_schema, m_schema_version, + m_config.schema_mode, required_changes, wrapper); + } + else { + ObjectStore::apply_schema_changes(transaction(), m_schema_version, schema, version, + m_config.schema_mode, required_changes); + REALM_ASSERT_DEBUG(additive || (required_changes = ObjectStore::schema_from_group(read_group()).compare(schema)).empty()); + } + + if (initialization_function && old_schema_version == ObjectStore::NotVersioned) { + // Initialization function needs to see the latest schema + uint64_t temp_version = ObjectStore::get_schema_version(read_group()); + std::swap(m_schema, schema); + std::swap(m_schema_version, temp_version); + auto restore = util::make_scope_exit([&]() noexcept { + std::swap(m_schema, schema); + std::swap(m_schema_version, temp_version); + }); + initialization_function(shared_from_this()); + } + + m_schema = std::move(schema); + m_new_schema = ObjectStore::schema_from_group(read_group()); + m_schema_version = ObjectStore::get_schema_version(read_group()); + m_dynamic_schema = false; + m_coordinator->clear_schema_cache_and_set_schema_version(version); + + if (!in_transaction) { + m_coordinator->commit_write(*this); + cache_new_schema(); + } + + notify_schema_changed(); +} + +void Realm::add_schema_change_handler() +{ + if (m_config.immutable()) + return; + m_group->set_schema_change_notification_handler([&] { + m_new_schema = ObjectStore::schema_from_group(read_group()); + m_schema_version = ObjectStore::get_schema_version(read_group()); + if (m_dynamic_schema) { + m_schema = *m_new_schema; + } + else + m_schema.copy_keys_from(*m_new_schema); + + notify_schema_changed(); + }); +} + +void Realm::cache_new_schema() +{ + if (!is_closed()) { + auto new_version = transaction().get_version_of_current_transaction().version; + if (m_new_schema) + m_coordinator->cache_schema(std::move(*m_new_schema), + m_schema_version, new_version); + else + m_coordinator->advance_schema_cache(m_schema_transaction_version, new_version); + m_schema_transaction_version = new_version; + m_new_schema = util::none; + } +} + +void Realm::translate_schema_error() +{ + // Read the new (incompatible) schema without changing our read transaction + auto new_schema = ObjectStore::schema_from_group(*m_coordinator->begin_read()); + + // Should always throw + ObjectStore::verify_valid_external_changes(m_schema.compare(new_schema, true)); + + // Something strange happened so just rethrow the old exception + throw; +} + +void Realm::notify_schema_changed() +{ + if (m_binding_context) { + m_binding_context->schema_did_change(m_schema); + } +} + +static void check_can_create_any_transaction(const Realm* realm) +{ + if (realm->config().immutable()) { + throw InvalidTransactionException("Can't perform transactions on read-only Realms."); + } +} + +static void check_can_create_write_transaction(const Realm* realm) +{ + if (realm->config().immutable() || realm->config().read_only_alternative()) { + throw InvalidTransactionException("Can't perform transactions on read-only Realms."); + } + if (realm->is_frozen()) { + throw InvalidTransactionException("Can't perform transactions on a frozen Realm"); + } + if (!realm->is_closed() && realm->get_number_of_versions() > realm->config().max_number_of_active_versions) { + throw InvalidTransactionException(util::format("Number of active versions (%1) in the Realm exceeded the limit of %2", + realm->get_number_of_versions(), + realm->config().max_number_of_active_versions)); + } +} + +void Realm::verify_thread() const +{ + if (m_scheduler && !m_scheduler->is_on_thread()) + throw IncorrectThreadException(); +} + +void Realm::verify_in_write() const +{ + if (!is_in_transaction()) { + throw InvalidTransactionException("Cannot modify managed objects outside of a write transaction."); + } +} + +void Realm::verify_open() const +{ + if (is_closed()) { + throw ClosedRealmException(); + } +} + +bool Realm::verify_notifications_available(bool throw_on_error) const +{ + if (is_frozen()) { + if (throw_on_error) + throw InvalidTransactionException("Notifications are not available on frozen lists since they do not change."); + return false; + } + if (config().immutable()) { + if (throw_on_error) + throw InvalidTransactionException("Cannot create asynchronous query for immutable Realms"); + return false; + } + if (is_in_transaction()) { + if (throw_on_error) + throw InvalidTransactionException("Cannot create asynchronous query while in a write transaction"); + return false; + } + + return true; +} + +VersionID Realm::read_transaction_version() const +{ + verify_thread(); + verify_open(); + check_can_create_any_transaction(this); + return static_cast(*m_group).get_version_of_current_transaction(); +} + +uint_fast64_t Realm::get_number_of_versions() const +{ + verify_open(); + check_can_create_any_transaction(this); + return m_coordinator->get_number_of_versions(); +} + +bool Realm::is_in_transaction() const noexcept +{ + return !m_config.immutable() + && !is_closed() + && m_group && transaction().get_transact_stage() == DB::transact_Writing; +} + +util::Optional Realm::current_transaction_version() const +{ + util::Optional ret; + if (m_group) { + ret = static_cast(*m_group).get_version_of_current_transaction(); + } + else if (m_frozen_version) { + ret = m_frozen_version; + } + return ret; +} + +void Realm::enable_wait_for_change() +{ + m_coordinator->enable_wait_for_change(); +} + +bool Realm::wait_for_change() +{ + if (m_frozen_version) { + return false; + } + return m_group ? m_coordinator->wait_for_change(transaction_ref()) : false; +} + +void Realm::wait_for_change_release() +{ + m_coordinator->wait_for_change_release(); +} + +void Realm::begin_transaction() +{ + verify_thread(); + check_can_create_write_transaction(this); + + if (is_in_transaction()) { + throw InvalidTransactionException("The Realm is already in a write transaction"); + } + + // Any of the callbacks to user code below could drop the last remaining + // strong reference to `this` + auto retain_self = shared_from_this(); + + // If we're already in the middle of sending notifications, just begin the + // write transaction without sending more notifications. If this actually + // advances the read version this could leave the user in an inconsistent + // state, but that's unavoidable. + if (m_is_sending_notifications) { + _impl::NotifierPackage notifiers; + transaction::begin(transaction_ref(), m_binding_context.get(), notifiers); + return; + } + + // make sure we have a read transaction + read_group(); + + m_is_sending_notifications = true; + auto cleanup = util::make_scope_exit([this]() noexcept { + m_is_sending_notifications = false; + }); + + try { + m_coordinator->promote_to_write(*this); + } + catch (_impl::UnsupportedSchemaChange const&) { + translate_schema_error(); + } + cache_new_schema(); +} + +void Realm::commit_transaction() +{ + check_can_create_write_transaction(this); + verify_thread(); + + if (!is_in_transaction()) { + throw InvalidTransactionException("Can't commit a non-existing write transaction"); + } + + if (auto audit = audit_context()) { + auto prev_version = transaction().get_version_of_current_transaction(); + m_coordinator->commit_write(*this); + audit->record_write(prev_version, transaction().get_version_of_current_transaction()); + // m_shared_group->unpin_version(prev_version); + } + else { + m_coordinator->commit_write(*this); + } + cache_new_schema(); +} + +void Realm::cancel_transaction() +{ + check_can_create_write_transaction(this); + verify_thread(); + + if (!is_in_transaction()) { + throw InvalidTransactionException("Can't cancel a non-existing write transaction"); + } + + transaction::cancel(transaction(), m_binding_context.get()); +} + +void Realm::invalidate() +{ + verify_open(); + verify_thread(); + check_can_create_any_transaction(this); + + if (m_is_sending_notifications) { + return; + } + + if (is_in_transaction()) { + cancel_transaction(); + } + + m_group = nullptr; +} + +bool Realm::compact() +{ + verify_thread(); + verify_open(); + + if (m_config.immutable() || m_config.read_only_alternative()) { + throw InvalidTransactionException("Can't compact a read-only Realm"); + } + if (is_in_transaction()) { + throw InvalidTransactionException("Can't compact a Realm within a write transaction"); + } + + verify_open(); + m_group = nullptr; + return m_coordinator->compact(); +} + +void Realm::write_copy(StringData path, BinaryData key) +{ + if (key.data() && key.size() != 64) { + throw InvalidEncryptionKeyException(); + } + verify_thread(); + try { + read_group().write(path, key.data()); + } + catch (...) { + _impl::translate_file_exception(path); + } +} + +OwnedBinaryData Realm::write_copy() +{ + verify_thread(); + BinaryData buffer = read_group().write_to_mem(); + + // Since OwnedBinaryData does not have a constructor directly taking + // ownership of BinaryData, we have to do this to avoid copying the buffer + return OwnedBinaryData(std::unique_ptr((char*)buffer.data()), buffer.size()); +} + +void Realm::notify() +{ + if (is_closed() || is_in_transaction() || is_frozen()) { + return; + } + + verify_thread(); + + // Any of the callbacks to user code below could drop the last remaining + // strong reference to `this` + auto retain_self = shared_from_this(); + + if (m_binding_context) { + m_binding_context->before_notify(); + if (is_closed() || is_in_transaction()) { + return; + } + } + + auto cleanup = util::make_scope_exit([this]() noexcept { m_is_sending_notifications = false; }); + if (!m_coordinator->can_advance(*this)) { + m_is_sending_notifications = true; + m_coordinator->process_available_async(*this); + return; + } + + if (m_binding_context) { + m_binding_context->changes_available(); + + // changes_available() may have advanced the read version, and if + // so we don't need to do anything further + if (!m_coordinator->can_advance(*this)) + return; + } + + m_is_sending_notifications = true; + if (m_auto_refresh) { + if (m_group) { + try { + m_coordinator->advance_to_ready(*this); + } + catch (_impl::UnsupportedSchemaChange const&) { + translate_schema_error(); + } + if (!is_closed()) + cache_new_schema(); + } + else { + if (m_binding_context) { + m_binding_context->did_change({}, {}); + } + if (!is_closed()) { + m_coordinator->process_available_async(*this); + } + } + } +} + +bool Realm::refresh() +{ + verify_thread(); + check_can_create_any_transaction(this); + return do_refresh(); +} + +bool Realm::do_refresh() +{ + // Frozen Realms never change. + if (is_frozen()) { + return false; + } + + // can't be any new changes if we're in a write transaction + if (is_in_transaction()) { + return false; + } + // don't advance if we're already in the process of advancing as that just + // makes things needlessly complicated + if (m_is_sending_notifications) { + return false; + } + + // Any of the callbacks to user code below could drop the last remaining + // strong reference to `this` + auto retain_self = shared_from_this(); + + m_is_sending_notifications = true; + auto cleanup = util::make_scope_exit([this]() noexcept { m_is_sending_notifications = false; }); + + if (m_binding_context) { + m_binding_context->before_notify(); + } + if (m_group) { + try { + bool version_changed = m_coordinator->advance_to_latest(*this); + if (is_closed()) + return false; + cache_new_schema(); + return version_changed; + } + catch (_impl::UnsupportedSchemaChange const&) { + translate_schema_error(); + } + } + + // No current read transaction, so just create a new one + read_group(); + m_coordinator->process_available_async(*this); + return true; +} + +void Realm::set_auto_refresh(bool auto_refresh) +{ + if (is_frozen() && auto_refresh) { + throw std::logic_error("Auto-refresh cannot be enabled for frozen Realms."); + } + m_auto_refresh = auto_refresh; +} + + +bool Realm::can_deliver_notifications() const noexcept +{ + if (m_config.immutable() || !m_config.automatic_change_notifications) { + return false; + } + + if (!m_scheduler || !m_scheduler->can_deliver_notifications()) { + return false; + } + + return true; +} + +uint64_t Realm::get_schema_version(const Realm::Config &config) +{ + auto coordinator = RealmCoordinator::get_coordinator(config.path); + auto version = coordinator->get_schema_version(); + if (version == ObjectStore::NotVersioned) + version = ObjectStore::get_schema_version(coordinator->get_realm(config, util::none)->read_group()); + return version; +} + + +bool Realm::is_frozen() const +{ + bool result = bool(m_frozen_version); + REALM_ASSERT_DEBUG((result && m_group) ? m_group->is_frozen() : true); + return result; +} + +SharedRealm Realm::freeze() +{ + auto config = m_config; + auto version = read_transaction_version(); + config.scheduler = util::Scheduler::get_frozen(version); + return Realm::get_frozen_realm(std::move(config), version); +} + +void Realm::close() +{ + if (m_coordinator) { + m_coordinator->unregister_realm(this); + } + if (!m_config.immutable() && m_group) { + transaction().close(); + } + + m_group = nullptr; + m_binding_context = nullptr; + m_coordinator = nullptr; +} + +AuditInterface* Realm::audit_context() const noexcept +{ + return m_coordinator ? m_coordinator->audit_context() : nullptr; +} + +MismatchedConfigException::MismatchedConfigException(StringData message, StringData path) +: std::logic_error(util::format(message.data(), path)) { } + +MismatchedRealmException::MismatchedRealmException(StringData message) +: std::logic_error(message.data()) { } + diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/app.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/app.cpp new file mode 100644 index 0000000..f5b400c --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/app.cpp @@ -0,0 +1,1153 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 utilied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#include "sync/app.hpp" + +#include "realm/util/base64.hpp" +#include "realm/util/uri.hpp" +#include "sync/app_credentials.hpp" +#include "sync/app_utils.hpp" +#include "sync/generic_network_transport.hpp" +#include "sync/impl/sync_client.hpp" +#include "sync/impl/sync_file.hpp" +#include "sync/impl/sync_metadata.hpp" +#include "sync/sync_manager.hpp" +#include "sync/sync_user.hpp" + +#include +#include + +namespace realm { +namespace app { + +using util::Optional; + +// MARK: - Helpers +// wrap an optional json key into the Optional type +template +Optional get_optional(const nlohmann::json& json, const std::string& key) +{ + auto it = json.find(key); + return it != json.end() ? Optional(it->get()) : realm::util::none; +} + +enum class RequestTokenType { + NoAuth, + AccessToken, + RefreshToken +}; + +// generate the request headers for a HTTP call, by default it will generate headers with a refresh token if a user is passed +static std::map get_request_headers(std::shared_ptr with_user_authorization = nullptr, + RequestTokenType token_type = RequestTokenType::RefreshToken) +{ + std::map headers { + { "Content-Type", "application/json;charset=utf-8" }, + { "Accept", "application/json" } + }; + + if (with_user_authorization) { + switch (token_type) { + case RequestTokenType::NoAuth: + break; + case RequestTokenType::AccessToken: + headers.insert({ "Authorization", + util::format("Bearer %1", with_user_authorization->access_token()) + }); + break; + case RequestTokenType::RefreshToken: + headers.insert({ "Authorization", + util::format("Bearer %1", with_user_authorization->refresh_token()) + }); + break; + } + } + return headers; +} + +const static std::string default_base_url = "https://realm.mongodb.com"; +const static std::string base_path = "/api/client/v2.0"; +const static std::string app_path = "/app"; +const static std::string auth_path = "/auth"; +const static std::string sync_path = "/realm-sync"; +const static uint64_t default_timeout_ms = 60000; +const static std::string username_password_provider_key = "local-userpass"; +const static std::string user_api_key_provider_key_path = "api_keys"; +static std::unordered_map> s_apps_cache; +std::mutex s_apps_mutex; + +SharedApp App::get_shared_app(const Config& config, const SyncClientConfig& sync_client_config) +{ + std::lock_guard lock(s_apps_mutex); + auto& app = s_apps_cache[config.app_id]; + if (!app) { + app = std::make_shared(config); + app->configure(sync_client_config); + } + return app; +} + +std::shared_ptr App::get_cached_app(const std::string& app_id) +{ + std::lock_guard lock(s_apps_mutex); + if (auto it = s_apps_cache.find(app_id); it != s_apps_cache.end()) { + return it->second; + } + + return nullptr; +} + +void App::clear_cached_apps() +{ + std::lock_guard lock(s_apps_mutex); + s_apps_cache.clear(); +} + +App::App(const Config& config) +: m_config(std::move(config)) +, m_base_url(config.base_url.value_or(default_base_url)) +, m_base_route(m_base_url + base_path) +, m_app_route(m_base_route + app_path + "/" + config.app_id) +, m_auth_route(m_app_route + auth_path) +, m_request_timeout_ms(config.default_request_timeout_ms.value_or(default_timeout_ms)) +{ + REALM_ASSERT(m_config.transport_generator); + + if (m_config.platform.empty()) { + throw std::runtime_error("You must specify the Platform in App::Config"); + } + + if (m_config.platform_version.empty()) { + throw std::runtime_error("You must specify the Platform Version in App::Config"); + } + + if (m_config.sdk_version.empty()) { + throw std::runtime_error("You must specify the SDK Version in App::Config"); + } + + // change the scheme in the base url to ws from http to satisfy the sync client + auto sync_route = m_app_route + sync_path; + size_t uri_scheme_start = sync_route.find("http"); + if (uri_scheme_start == 0) + sync_route.replace(uri_scheme_start, 4, "ws"); + + m_sync_manager = std::make_shared(); +} + +void App::configure(const SyncClientConfig& sync_client_config) +{ + // change the scheme in the base url to ws from http to satisfy the sync client + auto sync_route = m_app_route + sync_path; + size_t uri_scheme_start = sync_route.find("http"); + if (uri_scheme_start == 0) + sync_route.replace(uri_scheme_start, 4, "ws"); + + m_sync_manager->configure(shared_from_this(), sync_route, sync_client_config); + if (auto metadata = m_sync_manager->app_metadata()) { + m_base_route = metadata->hostname + base_path; + std::string this_app_path = app_path + "/" + m_config.app_id; + m_app_route = m_base_route + this_app_path; + m_auth_route = m_app_route + auth_path; + m_sync_manager->set_sync_route(metadata->ws_hostname + base_path + this_app_path + sync_path); + } +} + +static void handle_default_response(const Response& response, + std::function)> completion_block) +{ + if (auto error = AppUtils::check_for_errors(response)) { + return completion_block(error); + } else { + return completion_block({}); + } +}; + +//MARK: - Template specializations + +template<> +App::UsernamePasswordProviderClient App::provider_client() +{ + return App::UsernamePasswordProviderClient(shared_from_this()); +} + +template<> +App::UserAPIKeyProviderClient App::provider_client() +{ + return App::UserAPIKeyProviderClient(*this); +} + +// MARK: - UsernamePasswordProviderClient + +void App::UsernamePasswordProviderClient::register_email(const std::string &email, + const std::string &password, + std::function)> completion_block) +{ + REALM_ASSERT(m_parent); + std::string route = util::format("%1/providers/%2/register", m_parent->m_auth_route, username_password_provider_key); + + auto handler = [completion_block](const Response& response) { + handle_default_response(response, completion_block); + }; + + nlohmann::json body = { + { "email", email }, + { "password", password } + }; + + m_parent->do_request(Request { + HttpMethod::post, + route, + m_parent->m_request_timeout_ms, + get_request_headers(), + body.dump() + }, handler); +} + +void App::UsernamePasswordProviderClient::confirm_user(const std::string& token, + const std::string& token_id, + std::function)> completion_block) +{ + REALM_ASSERT(m_parent); + std::string route = util::format("%1/providers/%2/confirm", m_parent->m_auth_route, username_password_provider_key); + + auto handler = [completion_block](const Response& response) { + handle_default_response(response, completion_block); + }; + + nlohmann::json body = { + { "token", token }, + { "tokenId", token_id } + }; + + m_parent->do_request(Request { + HttpMethod::post, + route, + m_parent->m_request_timeout_ms, + get_request_headers(), + body.dump() + }, handler); +} + +void App::UsernamePasswordProviderClient::resend_confirmation_email(const std::string& email, + std::function)> completion_block) +{ + REALM_ASSERT(m_parent); + std::string route = util::format("%1/providers/%2/confirm/send", m_parent->m_auth_route, username_password_provider_key); + + auto handler = [completion_block](const Response& response) { + handle_default_response(response, completion_block); + }; + + nlohmann::json body { + { "email", email } + }; + + m_parent->do_request(Request { + HttpMethod::post, + route, + m_parent->m_request_timeout_ms, + get_request_headers(), + body.dump() + }, handler); +} + +void App::UsernamePasswordProviderClient::retry_custom_confirmation(const std::string& email, + std::function)> completion_block) +{ + REALM_ASSERT(m_parent); + std::string route = util::format("%1/providers/%2/confirm/call", m_parent->m_auth_route, username_password_provider_key); + + auto handler = [completion_block](const Response& response) { + handle_default_response(response, completion_block); + }; + + nlohmann::json body { + { "email", email } + }; + + m_parent->do_request(Request { + HttpMethod::post, + route, + m_parent->m_request_timeout_ms, + get_request_headers(), + body.dump() + }, handler); +} + +void App::UsernamePasswordProviderClient::send_reset_password_email(const std::string& email, + std::function)> completion_block) +{ + REALM_ASSERT(m_parent); + std::string route = util::format("%1/providers/%2/reset/send", m_parent->m_auth_route, username_password_provider_key); + + auto handler = [completion_block](const Response& response) { + handle_default_response(response, completion_block); + }; + + nlohmann::json body = { + { "email", email } + }; + + m_parent->do_request(Request { + HttpMethod::post, + route, + m_parent->m_request_timeout_ms, + get_request_headers(), + body.dump() + }, handler); +} + +void App::UsernamePasswordProviderClient::reset_password(const std::string& password, + const std::string& token, + const std::string& token_id, + std::function)> completion_block) +{ + REALM_ASSERT(m_parent); + std::string route = util::format("%1/providers/%2/reset", m_parent->m_auth_route, username_password_provider_key); + + auto handler = [completion_block](const Response& response) { + handle_default_response(response, completion_block); + }; + + nlohmann::json body = { + { "password", password }, + { "token", token }, + { "tokenId", token_id } + }; + + m_parent->do_request(Request { + HttpMethod::post, + route, + m_parent->m_request_timeout_ms, + get_request_headers(), + body.dump() + }, handler); +} + +void App::UsernamePasswordProviderClient::call_reset_password_function(const std::string& email, + const std::string& password, + const bson::BsonArray& args, + std::function)> completion_block) +{ + REALM_ASSERT(m_parent); + std::string route = util::format("%1/providers/%2/reset/call", m_parent->m_auth_route, username_password_provider_key); + + auto handler = [completion_block](const Response& response) { + handle_default_response(response, completion_block); + }; + + bson::BsonDocument arg = { + { "email", email }, + { "password", password }, + { "arguments", args } + }; + + std::stringstream body; + body << bson::Bson(arg); + + m_parent->do_request(Request { + HttpMethod::post, + route, + m_parent->m_request_timeout_ms, + get_request_headers(), + body.str() + }, handler); +} + +// MARK: - UserAPIKeyProviderClient + +std::string App::UserAPIKeyProviderClient::url_for_path(const std::string &path="") const +{ + if (!path.empty()) { + return m_auth_request_client.url_for_path(util::format("%1/%2/%3", + auth_path, + user_api_key_provider_key_path, + path)); + } + + return m_auth_request_client.url_for_path(util::format("%1/%2", + auth_path, + user_api_key_provider_key_path)); +} + +void App::UserAPIKeyProviderClient::create_api_key(const std::string &name, std::shared_ptr user, + std::function)> completion_block) +{ + std::string route = url_for_path(); + + auto handler = [completion_block](const Response& response) { + + if (auto error = AppUtils::check_for_errors(response)) { + return completion_block({}, error); + } + + nlohmann::json json; + try { + json = nlohmann::json::parse(response.body); + } catch (const std::exception& e) { + return completion_block({}, AppError(make_error_code(JSONErrorCode::malformed_json), e.what())); + } + + try { + auto user_api_key = App::UserAPIKey { + ObjectId(value_from_json(json, "_id").c_str()), + get_optional(json, "key"), + value_from_json(json, "name"), + value_from_json(json, "disabled") + }; + return completion_block(user_api_key, {}); + } catch (const std::exception& e) { + return completion_block({}, AppError(make_error_code(JSONErrorCode::malformed_json), e.what())); + } + }; + + nlohmann::json body = { + { "name", name } + }; + Request req; + req.method = HttpMethod::post; + req.url = route; + req.body = body.dump(); + req.uses_refresh_token = true; + + m_auth_request_client.do_authenticated_request(req, user, handler); +} + +void App::UserAPIKeyProviderClient::fetch_api_key(const realm::ObjectId& id, std::shared_ptr user, + std::function)> completion_block) +{ + std::string route = url_for_path(id.to_string()); + + auto handler = [completion_block](const Response& response) { + + if (auto error = AppUtils::check_for_errors(response)) { + return completion_block({}, error); + } + + nlohmann::json json; + try { + json = nlohmann::json::parse(response.body); + } catch (const std::exception& e) { + return completion_block({}, AppError(make_error_code(JSONErrorCode::malformed_json), e.what())); + } + + try { + auto user_api_key = App::UserAPIKey { + ObjectId(value_from_json(json, "_id").c_str()), + get_optional(json, "key"), + value_from_json(json, "name"), + value_from_json(json, "disabled") + }; + return completion_block(user_api_key, {}); + } catch (const std::exception& e) { + return completion_block({}, AppError(make_error_code(JSONErrorCode::malformed_json), e.what())); + } + }; + + Request req; + req.method = HttpMethod::get; + req.url = route; + req.uses_refresh_token = true; + + m_auth_request_client.do_authenticated_request(req, user, handler); +} + +void App::UserAPIKeyProviderClient::fetch_api_keys(std::shared_ptr user, + std::function, Optional)> completion_block) +{ + std::string route = url_for_path(); + + auto handler = [completion_block](const Response& response) { + + if (auto error = AppUtils::check_for_errors(response)) { + return completion_block(std::vector(), error); + } + + nlohmann::json json; + try { + json = nlohmann::json::parse(response.body); + } catch (const std::exception& e) { + return completion_block(std::vector(), AppError(make_error_code(JSONErrorCode::malformed_json), e.what())); + } + + try { + auto api_key_array = std::vector(); + auto json_array = json.get>(); + for (nlohmann::json& api_key_json : json_array) { + api_key_array.push_back( + App::UserAPIKey { + ObjectId(value_from_json(api_key_json, "_id").c_str()), + get_optional(api_key_json, "key"), + value_from_json(api_key_json, "name"), + value_from_json(api_key_json, "disabled") + }); + } + return completion_block(api_key_array, {}); + } catch (const std::exception& e) { + return completion_block(std::vector(), AppError(make_error_code(JSONErrorCode::malformed_json), e.what())); + } + }; + + Request req; + req.method = HttpMethod::get; + req.url = route; + req.uses_refresh_token = true; + + m_auth_request_client.do_authenticated_request(req, user, handler); +} + + +void App::UserAPIKeyProviderClient::delete_api_key(const realm::ObjectId& id, std::shared_ptr user, + std::function)> completion_block) +{ + std::string route = url_for_path(id.to_string()); + + auto handler = [completion_block](const Response& response) { + if (auto error = AppUtils::check_for_errors(response)) { + return completion_block(error); + } else { + return completion_block({}); + } + }; + + Request req; + req.method = HttpMethod::del; + req.url = route; + req.uses_refresh_token = true; + + m_auth_request_client.do_authenticated_request(req, user, handler); +} + +void App::UserAPIKeyProviderClient::enable_api_key(const realm::ObjectId& id, std::shared_ptr user, + std::function error)> completion_block) +{ + std::string route = url_for_path(util::format("%1/enable", id.to_string())); + + auto handler = [completion_block](const Response& response) { + if (auto error = AppUtils::check_for_errors(response)) { + return completion_block(error); + } else { + return completion_block({}); + } + }; + + Request req; + req.method = HttpMethod::put; + req.url = route; + req.uses_refresh_token = true; + + m_auth_request_client.do_authenticated_request(req, user, handler); +} + +void App::UserAPIKeyProviderClient::disable_api_key(const realm::ObjectId& id, std::shared_ptr user, + std::function error)> completion_block) +{ + std::string route = url_for_path(util::format("%1/disable", id.to_string())); + + auto handler = [completion_block](const Response& response) { + if (auto error = AppUtils::check_for_errors(response)) { + return completion_block(error); + } else { + return completion_block({}); + } + }; + + Request req; + req.method = HttpMethod::put; + req.url = route; + req.uses_refresh_token = true; + + m_auth_request_client.do_authenticated_request(req, user, handler); +} +// MARK: - App + +std::shared_ptr App::current_user() const +{ + return m_sync_manager->get_current_user(); +} + +std::vector> App::all_users() const +{ + return m_sync_manager->all_users(); +} + +void App::get_profile(std::shared_ptr sync_user, + std::function, util::Optional)> completion_block) +{ + auto profile_handler = [completion_block, this, sync_user](const Response& profile_response) { + if (auto error = AppUtils::check_for_errors(profile_response)) { + return completion_block(nullptr, error); + } + + nlohmann::json profile_json; + try { + profile_json = nlohmann::json::parse(profile_response.body); + } catch (const std::domain_error& e) { + return completion_block(nullptr, AppError(make_error_code(JSONErrorCode::malformed_json), e.what())); + } + + try { + std::vector identities; + nlohmann::json identities_json = value_from_json(profile_json, "identities"); + + for (size_t i = 0; i < identities_json.size(); i++) + { + auto identity_json = identities_json[i]; + identities.push_back(SyncUserIdentity(value_from_json(identity_json, "id"), + value_from_json(identity_json, "provider_type"))); + } + + sync_user->update_identities(identities); + + auto profile_data = value_from_json(profile_json, "data"); + + sync_user->update_user_profile(SyncUserProfile(get_optional(profile_data, "name"), + get_optional(profile_data, "email"), + get_optional(profile_data, "picture_url"), + get_optional(profile_data, "first_name"), + get_optional(profile_data, "last_name"), + get_optional(profile_data, "gender"), + get_optional(profile_data, "birthday"), + get_optional(profile_data, "min_age"), + get_optional(profile_data, "max_age"))); + + sync_user->set_state(SyncUser::State::LoggedIn); + m_sync_manager->set_current_user(sync_user->identity()); + } catch (const AppError& err) { + return completion_block(nullptr, err); + } + + return completion_block(sync_user, {}); + }; + + std::string profile_route = util::format("%1/auth/profile", m_base_route); + + Request req; + req.method = HttpMethod::get; + req.url = profile_route; + req.timeout_ms = m_request_timeout_ms; + req.uses_refresh_token = false; + + do_authenticated_request(req, sync_user, profile_handler); +} + +void App::attach_auth_options(bson::BsonDocument& body) +{ + bson::BsonDocument options; + + if (m_config.local_app_version) { + options["appVersion"] = *m_config.local_app_version; + } + + options["appId"] = m_config.app_id; + options["platform"] = m_config.platform; + options["platformVersion"] = m_config.platform_version; + options["sdkVersion"] = m_config.sdk_version; + + body["options"] = bson::BsonDocument({{"device", options}}); +} + +void App::log_in_with_credentials(const AppCredentials& credentials, + const std::shared_ptr linking_user, + std::function, Optional)> completion_block) +{ + // construct the route + std::string route = util::format("%1/providers/%2/login%3", + m_auth_route, + credentials.provider_as_string(), + linking_user ? "?link=true" : ""); + + auto handler = [completion_block, credentials, linking_user, this](const Response& response) { + if (auto error = AppUtils::check_for_errors(response)) { + return completion_block(nullptr, error); + } + + nlohmann::json json; + try { + json = nlohmann::json::parse(response.body); + } catch (const std::exception& e) { + return completion_block(nullptr, AppError(make_error_code(JSONErrorCode::malformed_json), e.what())); + } + + std::shared_ptr sync_user; + try { + if (linking_user) { + linking_user->update_access_token(value_from_json(json, "access_token")); + } else { + sync_user = m_sync_manager->get_user(value_from_json(json, "user_id"), + value_from_json(json, "refresh_token"), + value_from_json(json, "access_token"), + credentials.provider_as_string(), + value_from_json(json, "device_id")); + } + } catch (const AppError& err) { + return completion_block(nullptr, err); + } + + App::get_profile(linking_user ? linking_user : sync_user, completion_block); + }; + + bson::Bson credentials_as_bson = bson::parse(credentials.serialize_as_json()); + bson::BsonDocument body = static_cast(credentials_as_bson); + attach_auth_options(body); + + std::stringstream s; + s << bson::Bson(body); + + // if we try logging in with an anonymous user while there + // is already an anonymous session active, reuse it + if (credentials.provider() == AuthProvider::ANONYMOUS) { + for (auto user : m_sync_manager->all_users()) { + if (user->provider_type() == credentials.provider_as_string() && user->is_logged_in()) { + completion_block(switch_user(user), util::none); + return; + } + } + } + + do_request({ + HttpMethod::post, + route, + m_request_timeout_ms, + get_request_headers(linking_user, RequestTokenType::AccessToken), + s.str() + }, handler); +} + +void App::log_in_with_credentials(const AppCredentials& credentials, + std::function, Optional)> completion_block) +{ + App::log_in_with_credentials(credentials, nullptr, completion_block); +} + +void App::log_out(std::shared_ptr user, std::function)> completion_block) +{ + if (!user || user->state() != SyncUser::State::LoggedIn) { + return completion_block(util::none); + } + + auto handler = [completion_block, user](const Response& response) { + if (auto error = AppUtils::check_for_errors(response)) { + return completion_block(error); + } + return completion_block(util::none); + }; + + auto refresh_token = user->refresh_token(); + user->log_out(); + + std::string route = util::format("%1/auth/session", m_base_route); + + Request req; + req.method = HttpMethod::del; + req.url = route; + req.timeout_ms = m_request_timeout_ms; + req.uses_refresh_token = true; + req.headers = get_request_headers(); + req.headers.insert({ "Authorization", + util::format("Bearer %1", refresh_token) + }); + + do_request(req, [completion_block, req](Response response) { + if (auto error = AppUtils::check_for_errors(response)) { + // We do not care about handling auth errors on log out + completion_block(error); + } else { + completion_block(util::none); + } + }); +} + +void App::log_out(std::function)> completion_block) { + log_out(current_user(), completion_block); +} + +std::shared_ptr App::switch_user(std::shared_ptr user) const +{ + if (!user || user->state() != SyncUser::State::LoggedIn) { + throw AppError(make_client_error_code(ClientErrorCode::user_not_logged_in), + "User is no longer valid or is logged out"); + } + + auto users = m_sync_manager->all_users(); + auto it = std::find(users.begin(), + users.end(), + user); + + if (it == users.end()) { + throw AppError(make_client_error_code(ClientErrorCode::user_not_found), + "User does not exist"); + } + + m_sync_manager->set_current_user(user->identity()); + return current_user(); +} + +void App::remove_user(std::shared_ptr user, + std::function)> completion_block) +{ + if (!user || user->state() == SyncUser::State::Removed) { + return completion_block(AppError(make_client_error_code(ClientErrorCode::user_not_found), + "User has already been removed")); + } + + auto users = m_sync_manager->all_users(); + + auto it = std::find(users.begin(), + users.end(), + user); + + if (it == users.end()) { + return completion_block(AppError(make_client_error_code(ClientErrorCode::user_not_found), + "No user has been found")); + } + + if (user->is_logged_in()) { + log_out(user, [user, completion_block, this](const Optional& error){ + m_sync_manager->remove_user(user->identity()); + return completion_block(error); + }); + } else { + m_sync_manager->remove_user(user->identity()); + return completion_block({}); + } +} + +void App::link_user(std::shared_ptr user, + const AppCredentials& credentials, + std::function, Optional)> completion_block) +{ + if (!user || user->state() != SyncUser::State::LoggedIn) { + return completion_block(nullptr, AppError(make_client_error_code(ClientErrorCode::user_not_found), + "The specified user is not logged in")); + } + + auto users = m_sync_manager->all_users(); + + auto it = std::find(users.begin(), + users.end(), + user); + + if (it == users.end()) { + return completion_block(nullptr, AppError(make_client_error_code(ClientErrorCode::user_not_found), + "The specified user was not found")); + } + + App::log_in_with_credentials(credentials, user, completion_block); +} + +void App::refresh_custom_data(std::shared_ptr sync_user, + std::function)> completion_block) +{ + refresh_access_token(sync_user, completion_block); +} + +std::string App::url_for_path(const std::string& path="") const +{ + return util::format("%1%2", m_base_route, path); +} + +// FIXME: This passes back the response to bubble up any potential errors, making this somewhat leaky +void App::init_app_metadata(std::function, util::Optional)> completion_block) +{ + if (m_sync_manager->app_metadata()) { + return completion_block(util::none, util::none); + } + + std::string route = util::format("%1/location", + m_app_route); + + Request req; + req.method = HttpMethod::get; + req.url = route; + req.timeout_ms = m_request_timeout_ms; + + m_config.transport_generator()->send_request_to_server(req, [this, completion_block](const Response& response) { + nlohmann::json json; + try { + json = nlohmann::json::parse(response.body); + } catch (const std::exception& e) { + return completion_block(AppError(make_error_code(JSONErrorCode::malformed_json), e.what()), + response); + } + + try { + auto hostname = value_from_json(json, "hostname"); + auto ws_hostname = value_from_json(json, "ws_hostname"); + m_sync_manager->perform_metadata_update([&](const SyncMetadataManager& manager){ + manager.set_app_metadata(value_from_json(json, "deployment_model"), + value_from_json(json, "location"), + hostname, ws_hostname); + }); + + auto metadata = m_sync_manager->app_metadata(); + + m_base_route = hostname + base_path; + std::string this_app_path = app_path + "/" + m_config.app_id; + m_app_route = m_base_route + this_app_path; + m_auth_route = m_app_route + auth_path; + m_sync_manager->set_sync_route(ws_hostname + base_path + this_app_path + sync_path); + } catch (const AppError& err) { + return completion_block(err, response); + } + + completion_block(util::none, util::none); + }); +} + +void App::do_request(Request request, + std::function completion_block) +{ + request.timeout_ms = default_timeout_ms; + + // if we do not have metadata yet, we need to initialize it + if (!m_sync_manager->app_metadata()) { + init_app_metadata([completion_block, request, this](const util::Optional error, + const util::Optional response) mutable { + if (error) { + return completion_block(*response); + } + + // if this is the first time we have received app metadata, the + // original request will not have the correct URL hostname for + // non global deployments. + auto app_metadata = m_sync_manager->app_metadata(); + if (app_metadata && app_metadata->deployment_model != "GLOBAL" && request.url.rfind(m_base_url, 0) != std::string::npos) { + request.url.replace(0, m_base_url.size(), app_metadata->hostname); + } + + m_config.transport_generator()->send_request_to_server(request, completion_block); + }); + } else { + m_config.transport_generator()->send_request_to_server(request, completion_block); + } +} + +void App::do_authenticated_request(Request request, + std::shared_ptr sync_user, + std::function completion_block) +{ + request.headers = get_request_headers(sync_user, + request.uses_refresh_token ? + RequestTokenType::RefreshToken : RequestTokenType::AccessToken); + + do_request(request, [completion_block, request, sync_user, this](Response response) { + if (auto error = AppUtils::check_for_errors(response)) { + App::handle_auth_failure(error.value(), response, request, sync_user, completion_block); + } else { + completion_block(response); + } + }); +} + +void App::handle_auth_failure(const AppError& error, + const Response& response, + Request request, + std::shared_ptr sync_user, + std::function completion_block) +{ + auto access_token_handler = [this, + request, + completion_block, + response, + sync_user](const Optional& error) { + if (!error) { + // assign the new access_token to the auth header + Request newRequest = request; + newRequest.headers = get_request_headers(sync_user, RequestTokenType::AccessToken); + m_config.transport_generator()->send_request_to_server(newRequest, completion_block); + } else { + // pass the error back up the chain + completion_block(response); + } + }; + + // Only handle auth failures + if (*error.http_status_code && *error.http_status_code == 401) { + if (request.uses_refresh_token) { + if (sync_user && sync_user->is_logged_in()) { + sync_user->log_out(); + } + completion_block(response); + return; + } + + App::refresh_access_token(sync_user, access_token_handler); + } else { + completion_block(response); + } +} + +/// MARK: - refresh access token +void App::refresh_access_token(std::shared_ptr sync_user, + std::function)> completion_block) +{ + if (!sync_user) { + completion_block(AppError(make_client_error_code(ClientErrorCode::user_not_found), + "No current user exists")); + return; + } + + if (!sync_user->is_logged_in()) { + completion_block(AppError(make_client_error_code(ClientErrorCode::user_not_logged_in), + "The user is not logged in")); + return; + } + + auto handler = [completion_block, sync_user](const Response& response) { + + if (auto error = AppUtils::check_for_errors(response)) { + return completion_block(error); + } + + try { + nlohmann::json json = nlohmann::json::parse(response.body); + auto access_token = value_from_json(json, "access_token"); + sync_user->update_access_token(std::move(access_token)); + } catch (const AppError& err) { + return completion_block(err); + } + + return completion_block(util::none); + }; + + std::string route = util::format("%1/auth/session", m_base_route); + + do_request(Request { + HttpMethod::post, + route, + m_request_timeout_ms, + get_request_headers(sync_user, RequestTokenType::RefreshToken) + }, handler); +} + +std::string App::function_call_url_path() const { + return util::format("%1/app/%2/functions/call", m_base_route, m_config.app_id); +} +void App::call_function(std::shared_ptr user, + const std::string& name, + const bson::BsonArray& args_bson, + const util::Optional& service_name, + std::function, + util::Optional)> completion_block) +{ + auto handler = [completion_block](const Response& response) { + if (auto error = AppUtils::check_for_errors(response)) { + return completion_block(error, util::none); + } + completion_block(util::none, util::Optional(bson::parse(response.body))); + }; + + bson::BsonDocument args { + { "arguments", args_bson }, + { "name", name } + }; + + if (service_name) { + args["service"] = *service_name; + } + + do_authenticated_request(Request{ + HttpMethod::post, + function_call_url_path(), + m_request_timeout_ms, + {}, + bson::Bson(args).toJson(), + false + }, + user, + handler); +} + +void App::call_function(std::shared_ptr user, + const std::string& name, + const bson::BsonArray& args_bson, + std::function, + util::Optional)> completion_block) +{ + call_function(user, + name, + args_bson, + util::none, + completion_block); +} + +void App::call_function(const std::string& name, + const bson::BsonArray& args_bson, + const util::Optional& service_name, + std::function, + util::Optional)> completion_block) +{ + call_function(m_sync_manager->get_current_user(), + name, + args_bson, + service_name, + completion_block); +} + +void App::call_function(const std::string& name, + const bson::BsonArray& args_bson, + std::function, + util::Optional)> completion_block) +{ + call_function(m_sync_manager->get_current_user(), + name, + args_bson, + completion_block); +} + +Request App::make_streaming_request(std::shared_ptr user, + const std::string &name, + const bson::BsonArray &args_bson, + const util::Optional &service_name) const { + auto args = bson::BsonDocument{ + {"arguments", args_bson}, + {"name", name}, + }; + if (service_name) { + args["service"] = *service_name; + } + const auto args_json = bson::Bson(args).toJson(); + + auto args_base64 = std::string(util::base64_encoded_size(args_json.size()), '\0'); + util::base64_encode(args_json.data(), args_json.size(), args_base64.data(), args_base64.size()); + + auto url = function_call_url_path() + "?baas_request=" + util::uri_percent_encode(args_base64); + if (user) { + url += "&baas_at="; + url += user->access_token(); // doesn't need url encoding + } + + return Request{ + HttpMethod::get, + url, + m_request_timeout_ms, + {{"Accept", "text/event-stream"}}, + }; +} + +PushClient App::push_notification_client(const std::string& service_name) +{ + return PushClient(service_name, + m_config.app_id, + m_request_timeout_ms, + shared_from_this()); +} + +} // namespace app +} // namespace realm diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/app_credentials.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/app_credentials.cpp new file mode 100644 index 0000000..bed0bee --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/app_credentials.cpp @@ -0,0 +1,196 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 utilied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#include "sync/app_credentials.hpp" +#include "util/bson/bson.hpp" + +#include +#include + +namespace realm { +namespace app { + +std::string const kAppProviderKey = "provider"; + +IdentityProvider const IdentityProviderAnonymous = "anon-user"; +IdentityProvider const IdentityProviderGoogle = "oauth2-google"; +IdentityProvider const IdentityProviderFacebook = "oauth2-facebook"; +IdentityProvider const IdentityProviderApple = "oauth2-apple"; +IdentityProvider const IdentityProviderUsernamePassword = "local-userpass"; +IdentityProvider const IdentityProviderCustom = "custom-token"; +IdentityProvider const IdentityProviderFunction = "custom-function"; +IdentityProvider const IdentityProviderUserAPIKey = "api-key"; +IdentityProvider const IdentityProviderServerAPIKey = "api-key"; + +IdentityProvider provider_type_from_enum(AuthProvider provider) +{ + switch (provider) + { + case AuthProvider::ANONYMOUS: + return IdentityProviderAnonymous; + case AuthProvider::APPLE: + return IdentityProviderApple; + case AuthProvider::FACEBOOK: + return IdentityProviderFacebook; + case AuthProvider::GOOGLE: + return IdentityProviderGoogle; + case AuthProvider::CUSTOM: + return IdentityProviderCustom; + case AuthProvider::USERNAME_PASSWORD: + return IdentityProviderUsernamePassword; + case AuthProvider::FUNCTION: + return IdentityProviderFunction; + case AuthProvider::USER_API_KEY: + return IdentityProviderUserAPIKey; + case AuthProvider::SERVER_API_KEY: + return IdentityProviderServerAPIKey; + } + throw std::runtime_error("unknown provider type in provider_type_from_enum"); +} + +AppCredentials::AppCredentials(AuthProvider provider, std::function factory) +: m_provider(provider) +, m_payload_factory(factory) +{ +} + +AuthProvider AppCredentials::provider() const +{ + return m_provider; +} + +std::string AppCredentials::provider_as_string() const +{ + return provider_type_from_enum(m_provider); +} + +std::string AppCredentials::serialize_as_json() const +{ + return m_payload_factory(); +} + +AppCredentials AppCredentials::anonymous() +{ + return AppCredentials(AuthProvider::ANONYMOUS, + [=] { + return nlohmann::json({ + {kAppProviderKey, IdentityProviderAnonymous} + }).dump(); + }); +} + +AppCredentials AppCredentials::apple(AppCredentialsToken id_token) +{ + return AppCredentials(AuthProvider::APPLE, + [=] { + return nlohmann::json({ + {kAppProviderKey, IdentityProviderApple}, + {"id_token", id_token} + }).dump(); + }); +} + +AppCredentials AppCredentials::facebook(AppCredentialsToken access_token) +{ + return AppCredentials(AuthProvider::FACEBOOK, + [=] { + return nlohmann::json({ + {kAppProviderKey, IdentityProviderFacebook}, + {"accessToken", access_token} + }).dump(); + }); +} + +AppCredentials AppCredentials::google(AppCredentialsToken auth_token) +{ + return AppCredentials(AuthProvider::GOOGLE, + [=] { + return nlohmann::json({ + {kAppProviderKey, IdentityProviderGoogle}, + {"authCode", auth_token} + }).dump(); + }); +} + +AppCredentials AppCredentials::custom(AppCredentialsToken token) +{ + return AppCredentials(AuthProvider::CUSTOM, + [=] { + return nlohmann::json({ + {kAppProviderKey, IdentityProviderCustom}, + {"token", token} + }).dump(); + }); +} + +AppCredentials AppCredentials::username_password(std::string username, + std::string password) +{ + return AppCredentials(AuthProvider::USERNAME_PASSWORD, + [=] { + return nlohmann::json({ + {kAppProviderKey, IdentityProviderUsernamePassword}, + {"username", username}, + {"password", password} + }).dump(); + }); +} + +AppCredentials AppCredentials::function(const bson::BsonDocument& payload) +{ + return AppCredentials(AuthProvider::FUNCTION, + [=] { + std::stringstream output; + output << bson::Bson(payload); + return output.str(); + }); +} + +AppCredentials AppCredentials::function(const std::string& serialized_payload) +{ + return AppCredentials(AuthProvider::FUNCTION, + [=] { + return serialized_payload; + }); +} + + +AppCredentials AppCredentials::user_api_key(std::string api_key) +{ + return AppCredentials(AuthProvider::USER_API_KEY, + [=] { + return nlohmann::json({ + {kAppProviderKey, IdentityProviderUserAPIKey}, + {"key", api_key} + }).dump(); + }); +} + +AppCredentials AppCredentials::server_api_key(std::string api_key) +{ + return AppCredentials(AuthProvider::SERVER_API_KEY, + [=] { + return nlohmann::json({ + {kAppProviderKey, IdentityProviderServerAPIKey}, + {"key", api_key} + }).dump(); + }); +} + +} // namespace app +} // namespace realm diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/app_utils.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/app_utils.cpp new file mode 100644 index 0000000..d032ff3 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/app_utils.cpp @@ -0,0 +1,88 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 utilied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#include "sync/app_utils.hpp" + +namespace realm { +namespace app { + +util::Optional AppUtils::check_for_errors(const Response& response) +{ + bool http_status_code_is_fatal = response.http_status_code >= 300 || + (response.http_status_code < 200 && response.http_status_code != 0); + + auto find_case_insensitive_header = [&response](const std::string& needle) { + for (auto it = response.headers.begin(); it != response.headers.end(); ++it) { + if (std::equal(it->first.begin(), it->first.end(), + needle.begin(), needle.end(), + [](char a, char b) { + return tolower(a) == tolower(b); + })) { + return it; + } + } + return response.headers.end(); + }; + + try { + auto ct = find_case_insensitive_header("content-type"); + if (ct != response.headers.end() && ct->second == "application/json") { + auto body = nlohmann::json::parse(response.body); + auto message = body.find("error"); + auto link = body.find("link"); + std::string parsed_link = link == body.end() ? "" : link->get(); + + if (auto error_code = body.find("error_code"); error_code != body.end() && + !error_code->get().empty()) + { + return AppError(make_error_code(service_error_code_from_string(body["error_code"].get())), + message != body.end() ? message->get() : "no error message", + std::move(parsed_link), + response.http_status_code); + } else if (message != body.end()) { + return AppError(make_error_code(ServiceErrorCode::unknown), + message->get(), + std::move(parsed_link), + response.http_status_code); + } + } + } catch (const std::exception&) { + // ignore parse errors from our attempt to read the error from json + } + + if (response.custom_status_code != 0) { + std::string error_msg = (!response.body.empty()) ? response.body : "non-zero custom status code considered fatal"; + return AppError(make_custom_error_code(response.custom_status_code), + error_msg, + "", + response.http_status_code); + } + + if (http_status_code_is_fatal) + { + return AppError(make_http_error_code(response.http_status_code), + "http error code considered fatal", + "", + response.http_status_code); + } + + return {}; +} + +} // namespace app +} // namespace realm diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/async_open_task.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/async_open_task.cpp new file mode 100644 index 0000000..1a66be7 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/async_open_task.cpp @@ -0,0 +1,89 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2019 Realm Inc. +// +// 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 "sync/async_open_task.hpp" + +#include "impl/realm_coordinator.hpp" +#include "sync/sync_manager.hpp" +#include "sync/sync_session.hpp" +#include "thread_safe_reference.hpp" + +namespace realm { + +AsyncOpenTask::AsyncOpenTask(std::shared_ptr<_impl::RealmCoordinator> coordinator, std::shared_ptr session) +: m_coordinator(coordinator) +, m_session(session) +{ +} + +void AsyncOpenTask::start(std::function callback) +{ + auto session = m_session.load(); + if (!session) + return; + + std::shared_ptr self(shared_from_this()); + session->wait_for_download_completion([callback, self, this](std::error_code ec) { + auto session = m_session.exchange(nullptr); + if (!session) + return; // Swallow all events if the task as been canceled. + + // Release our references to the coordinator after calling the callback + auto coordinator = std::move(m_coordinator); + m_coordinator = nullptr; + + if (ec) + return callback({}, std::make_exception_ptr(std::system_error(ec))); + + ThreadSafeReference realm; + try { + realm = coordinator->get_unbound_realm(); + } + catch (...) { + return callback({}, std::current_exception()); + } + callback(std::move(realm), nullptr); + }); +} + +void AsyncOpenTask::cancel() +{ + if (auto session = m_session.exchange(nullptr)) { + // Does a better way exists for canceling the download? + session->log_out(); + m_coordinator = nullptr; + } +} + +uint64_t AsyncOpenTask::register_download_progress_notifier(std::function callback) +{ + if (auto session = m_session.load()) { + return session->register_progress_notifier(callback, realm::SyncSession::NotifierType::download, false); + } + else { + return 0; + } +} + +void AsyncOpenTask::unregister_download_progress_notifier(uint64_t token) +{ + if (auto session = m_session.load()) + session->unregister_progress_notifier(token); +} + +} diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/generic_network_transport.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/generic_network_transport.cpp new file mode 100644 index 0000000..fc91118 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/generic_network_transport.cpp @@ -0,0 +1,258 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 utilied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#include "sync/generic_network_transport.hpp" + +#include + +namespace realm { +namespace app { + +namespace { + +std::string get_error_message(JSONErrorCode error) +{ + switch (error) { + case JSONErrorCode::bad_token: + return "bad token"; + case JSONErrorCode::malformed_json: + return "malformed json"; + case JSONErrorCode::missing_json_key: + return "missing json key"; + case JSONErrorCode::bad_bson_parse: + return "bad bson parse"; + } + return "unknown"; +} + +struct JSONErrorCategory : public std::error_category { + const char* name() const noexcept final override + { + return "realm::app::JSONError"; + } + + std::string message(int error_code) const override final + { + return get_error_message(JSONErrorCode(error_code)); + } +}; + +JSONErrorCategory g_json_error_category; + +static const std::map service_error_map = { + {"MissingAuthReq", ServiceErrorCode::missing_auth_req}, + {"InvalidSession", ServiceErrorCode::invalid_session}, + {"UserAppDomainMismatch", ServiceErrorCode::user_app_domain_mismatch}, + {"DomainNotAllowed", ServiceErrorCode::domain_not_allowed}, + {"ReadSizeLimitExceeded", ServiceErrorCode::read_size_limit_exceeded}, + {"InvalidParameter", ServiceErrorCode::invalid_parameter}, + {"MissingParameter", ServiceErrorCode::missing_parameter}, + {"TwilioError", ServiceErrorCode::twilio_error}, + {"GCMError", ServiceErrorCode::gcm_error}, + {"HTTPError", ServiceErrorCode::http_error}, + {"AWSError", ServiceErrorCode::aws_error}, + {"MongoDBError", ServiceErrorCode::mongodb_error}, + {"ArgumentsNotAllowed", ServiceErrorCode::arguments_not_allowed}, + {"FunctionExecutionError", ServiceErrorCode::function_execution_error}, + {"NoMatchingRule", ServiceErrorCode::no_matching_rule_found}, + {"InternalServerError", ServiceErrorCode::internal_server_error}, + {"AuthProviderNotFound", ServiceErrorCode::auth_provider_not_found}, + {"AuthProviderAlreadyExists", ServiceErrorCode::auth_provider_already_exists}, + {"ServiceNotFound", ServiceErrorCode::service_not_found}, + {"ServiceTypeNotFound", ServiceErrorCode::service_type_not_found}, + {"ServiceAlreadyExists", ServiceErrorCode::service_already_exists}, + {"ServiceCommandNotFound", ServiceErrorCode::service_command_not_found}, + {"ValueNotFound", ServiceErrorCode::value_not_found}, + {"ValueAlreadyExists", ServiceErrorCode::value_already_exists}, + {"ValueDuplicateName", ServiceErrorCode::value_duplicate_name}, + {"FunctionNotFound", ServiceErrorCode::function_not_found}, + {"FunctionAlreadyExists", ServiceErrorCode::function_already_exists}, + {"FunctionDuplicateName", ServiceErrorCode::function_duplicate_name}, + {"FunctionSyntaxError", ServiceErrorCode::function_syntax_error}, + {"FunctionInvalid", ServiceErrorCode::function_invalid}, + {"IncomingWebhookNotFound", ServiceErrorCode::incoming_webhook_not_found}, + {"IncomingWebhookAlreadyExists", ServiceErrorCode::incoming_webhook_already_exists}, + {"IncomingWebhookDuplicateName", ServiceErrorCode::incoming_webhook_duplicate_name}, + {"RuleNotFound", ServiceErrorCode::rule_not_found}, + {"APIKeyNotFound", ServiceErrorCode::api_key_not_found}, + {"RuleAlreadyExists", ServiceErrorCode::rule_already_exists}, + {"AuthProviderDuplicateName", ServiceErrorCode::auth_provider_duplicate_name}, + {"RestrictedHost", ServiceErrorCode::restricted_host}, + {"APIKeyAlreadyExists", ServiceErrorCode::api_key_already_exists}, + {"IncomingWebhookAuthFailed", ServiceErrorCode::incoming_webhook_auth_failed}, + {"ExecutionTimeLimitExceeded", ServiceErrorCode::execution_time_limit_exceeded}, + {"NotCallable", ServiceErrorCode::not_callable}, + {"UserAlreadyConfirmed", ServiceErrorCode::user_already_confirmed}, + {"UserNotFound", ServiceErrorCode::user_not_found}, + {"UserDisabled", ServiceErrorCode::user_disabled}, + {"AuthError", ServiceErrorCode::auth_error}, + {"BadRequest", ServiceErrorCode::bad_request}, + {"AccountNameInUse", ServiceErrorCode::account_name_in_use}, + {"Unknown", ServiceErrorCode::unknown}, +}; + +std::string get_error_message(ServiceErrorCode error) +{ + for (auto it : service_error_map) { + if (it.second == error) { + return it.first; + } + } + return "unknown"; +} + +struct ServiceErrorCategory : public std::error_category { + const char* name() const noexcept final override + { + return "realm::app::ServiceError"; + } + + std::string message(int error_code) const override final + { + return get_error_message(ServiceErrorCode(error_code)); + } +}; + +ServiceErrorCategory g_service_error_category; + + +struct HttpErrorCategory : public std::error_category { + const char* name() const noexcept final override + { + return "realm::app::HttpError"; + } + + std::string message(int code) const override final + { + if (code >= 100 && code < 200) { + return util::format("Informational: %1", code); + } + else if (code >= 200 && code < 300) { + return util::format("Success: %1", code); + } + else if (code >= 300 && code < 400) { + return util::format("Redirection: %1", code); + } + else if (code >= 400 && code < 500) { + return util::format("Client Error: %1", code); + } + else if (code >= 500 && code < 600) { + return util::format("Server Error: %1", code); + } + return util::format("Unknown HTTP Error: %1", code); + } +}; + +HttpErrorCategory g_http_error_category; + +struct CustomErrorCategory : public std::error_category { + const char* name() const noexcept final override + { + return "realm::app::CustomError"; + } + + std::string message(int code) const override final + { + return util::format("code %1", code); + } +}; + +CustomErrorCategory g_custom_error_category; + +struct ClientErrorCategory : public std::error_category { + const char* name() const noexcept final override + { + return "realm::app::ClientError"; + } + + std::string message(int code) const override final + { + return util::format("code %1", code); + } +}; + +ClientErrorCategory g_client_error_category; + +} // unnamed namespace + +std::ostream& operator<<(std::ostream& os, AppError error) +{ + return os << error.error_code.message() << ": " << error.message; +} + +const std::error_category& json_error_category() noexcept +{ + return g_json_error_category; +} + +std::error_code make_error_code(JSONErrorCode error) noexcept +{ + return std::error_code{int(error), g_json_error_category}; +} + +const std::error_category& service_error_category() noexcept +{ + return g_service_error_category; +} + +std::error_code make_error_code(ServiceErrorCode error) noexcept +{ + return std::error_code{int(error), g_service_error_category}; +} + +ServiceErrorCode service_error_code_from_string(const std::string& code) +{ + auto search = service_error_map.find(code); + if (search != service_error_map.end()) { + return search->second; + } + return ServiceErrorCode::unknown; +} + +const std::error_category& http_error_category() noexcept +{ + return g_http_error_category; +} + +std::error_code make_http_error_code(int http_code) noexcept +{ + return std::error_code{http_code, g_http_error_category}; +} + +const std::error_category& custom_error_category() noexcept +{ + return g_custom_error_category; +} + +std::error_code make_custom_error_code(int code) noexcept +{ + return std::error_code{code, g_custom_error_category}; +} + +const std::error_category& client_error_category() noexcept +{ + return g_client_error_category; +} + +std::error_code make_client_error_code(ClientErrorCode error) noexcept +{ + return std::error_code{int(error), g_client_error_category}; +} + +} // namespace app +} // namespace realm diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/impl/apple/network_reachability_observer.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/impl/apple/network_reachability_observer.cpp new file mode 100644 index 0000000..ad040a4 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/impl/apple/network_reachability_observer.cpp @@ -0,0 +1,127 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// 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 "sync/impl/apple/network_reachability_observer.hpp" + +#if NETWORK_REACHABILITY_AVAILABLE + +using namespace realm; +using namespace realm::_impl; + +namespace { + +NetworkReachabilityStatus reachability_status_for_flags(SCNetworkReachabilityFlags flags) +{ + if (!(flags & kSCNetworkReachabilityFlagsReachable)) + return NotReachable; + + if (flags & kSCNetworkReachabilityFlagsConnectionRequired) { + if (!(flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) || + (flags & kSCNetworkReachabilityFlagsInterventionRequired)) + return NotReachable; + } + + NetworkReachabilityStatus status = ReachableViaWiFi; + +#if TARGET_OS_IPHONE + if (flags & kSCNetworkReachabilityFlagsIsWWAN) + status = ReachableViaWWAN; +#endif + + return status; +} + +} // (anonymous namespace) + +NetworkReachabilityObserver::NetworkReachabilityObserver(util::Optional hostname, + std::function handler) +: m_callback_queue(dispatch_queue_create("io.realm.sync.reachability", DISPATCH_QUEUE_SERIAL)) +, m_change_handler(std::move(handler)) +{ + if (hostname) { + m_reachability_ref = util::adoptCF(SystemConfiguration::shared().network_reachability_create_with_name(nullptr, + hostname->c_str())); + } else { + struct sockaddr zeroAddress = {}; + zeroAddress.sa_len = sizeof(zeroAddress); + zeroAddress.sa_family = AF_INET; + + m_reachability_ref = util::adoptCF(SystemConfiguration::shared().network_reachability_create_with_address(nullptr, + &zeroAddress)); + } +} + +NetworkReachabilityObserver::~NetworkReachabilityObserver() +{ + stop_observing(); + dispatch_release(m_callback_queue); +} + +NetworkReachabilityStatus NetworkReachabilityObserver::reachability_status() const +{ + SCNetworkReachabilityFlags flags; + + if (SystemConfiguration::shared().network_reachability_get_flags(m_reachability_ref.get(), &flags)) + return reachability_status_for_flags(flags); + + return NotReachable; +} + +bool NetworkReachabilityObserver::start_observing() +{ + m_previous_status = reachability_status(); + + auto callback = [](SCNetworkReachabilityRef, SCNetworkReachabilityFlags, void* self) { + static_cast(self)->reachability_changed(); + }; + + SCNetworkReachabilityContext context = {0, this, nullptr, nullptr, nullptr}; + + if (!SystemConfiguration::shared().network_reachability_set_callback(m_reachability_ref.get(), callback, &context)) + return false; + + if (!SystemConfiguration::shared().network_reachability_set_dispatch_queue(m_reachability_ref.get(), m_callback_queue)) + return false; + + return true; +} + +void NetworkReachabilityObserver::stop_observing() +{ + SystemConfiguration::shared().network_reachability_set_dispatch_queue(m_reachability_ref.get(), nullptr); + SystemConfiguration::shared().network_reachability_set_callback(m_reachability_ref.get(), nullptr, nullptr); + + // Wait for all previously-enqueued blocks to execute to guarantee that + // no callback will be called after returning from this method + dispatch_sync(m_callback_queue, ^{}); +} + +void NetworkReachabilityObserver::reachability_changed() +{ + auto current_status = reachability_status(); + + // When observing reachability of the specific host the callback might be called + // several times (because of DNS queries) with the same reachability flags while + // the caller should be notified only when the reachability status is really changed. + if (current_status != m_previous_status) { + m_change_handler(current_status); + m_previous_status = current_status; + } +} + +#endif diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/impl/apple/system_configuration.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/impl/apple/system_configuration.cpp new file mode 100644 index 0000000..6c4c127 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/impl/apple/system_configuration.cpp @@ -0,0 +1,98 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2017 Realm Inc. +// +// 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 "sync/impl/apple/system_configuration.hpp" + +#if NETWORK_REACHABILITY_AVAILABLE + +#include +#include "dlfcn.h" + +using namespace realm; +using namespace realm::_impl; + +SystemConfiguration::SystemConfiguration() +{ + m_framework_handle = dlopen("/System/Library/Frameworks/SystemConfiguration.framework/SystemConfiguration", RTLD_LAZY); + + if (m_framework_handle) { + m_create_with_name = (create_with_name_t)dlsym(m_framework_handle, "SCNetworkReachabilityCreateWithName"); + m_create_with_address = (create_with_address_t)dlsym(m_framework_handle, "SCNetworkReachabilityCreateWithAddress"); + m_set_dispatch_queue = (set_dispatch_queue_t)dlsym(m_framework_handle, "SCNetworkReachabilitySetDispatchQueue"); + m_set_callback = (set_callback_t)dlsym(m_framework_handle, "SCNetworkReachabilitySetCallback"); + m_get_flags = (get_flags_t)dlsym(m_framework_handle, "SCNetworkReachabilityGetFlags"); + } else { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + asl_log(nullptr, nullptr, ASL_LEVEL_WARNING, "network reachability is not available"); +#pragma clang diagnostic pop + } +} + +SystemConfiguration& SystemConfiguration::shared() +{ + static SystemConfiguration system_configuration; + + return system_configuration; +} + +SCNetworkReachabilityRef SystemConfiguration::network_reachability_create_with_name(CFAllocatorRef allocator, + const char *hostname) +{ + if (m_create_with_name) + return m_create_with_name(allocator, hostname); + + return nullptr; +} + +SCNetworkReachabilityRef SystemConfiguration::network_reachability_create_with_address(CFAllocatorRef allocator, + const sockaddr *address) +{ + if (m_create_with_address) + return m_create_with_address(allocator, address); + + return nullptr; +} + +bool SystemConfiguration::network_reachability_set_dispatch_queue(SCNetworkReachabilityRef target, dispatch_queue_t queue) +{ + if (m_set_dispatch_queue) + return m_set_dispatch_queue(target, queue); + + return false; +} + +bool SystemConfiguration::network_reachability_set_callback(SCNetworkReachabilityRef target, + SCNetworkReachabilityCallBack callback, + SCNetworkReachabilityContext *context) +{ + if (m_set_callback) + return m_set_callback(target, callback, context); + + return false; +} + +bool SystemConfiguration::network_reachability_get_flags(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags *flags) +{ + if (m_get_flags) + return m_get_flags(target, flags); + + return false; +} + +#endif // NETWORK_REACHABILITY_AVAILABLE diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/impl/sync_file.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/impl/sync_file.cpp new file mode 100644 index 0000000..711c356 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/impl/sync_file.cpp @@ -0,0 +1,448 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// 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 "sync/impl/sync_file.hpp" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#include + +inline static int mkstemp(char* _template) { return _open(_mktemp(_template), _O_CREAT | _O_TEMPORARY, _S_IREAD | _S_IWRITE); } +#else +#include +#endif + + +using File = realm::util::File; + +namespace realm { + +namespace { + +uint8_t value_of_hex_digit(char hex_digit) +{ + if (hex_digit >= '0' && hex_digit <= '9') { + return hex_digit - '0'; + } else if (hex_digit >= 'A' && hex_digit <= 'F') { + return 10 + hex_digit - 'A'; + } else if (hex_digit >= 'a' && hex_digit <= 'f') { + return 10 + hex_digit - 'a'; + } else { + throw std::invalid_argument("Cannot get the value of a character that isn't a hex digit."); + } +} + +bool filename_is_reserved(const std::string& filename) { + return (filename == "." || filename == ".."); +} + +bool character_is_unreserved(char character) +{ + bool is_capital_letter = (character >= 'A' && character <= 'Z'); + bool is_lowercase_letter = (character >= 'a' && character <= 'z'); + bool is_number = (character >= '0' && character <= '9'); + bool is_allowed_symbol = (character == '-' || character == '_' || character == '.'); + return is_capital_letter || is_lowercase_letter || is_number || is_allowed_symbol; +} + +char decoded_char_for(const std::string& percent_encoding, size_t index) +{ + if (index+2 >= percent_encoding.length()) { + throw std::invalid_argument("Malformed string: not enough characters after '%' before end of string."); + } + REALM_ASSERT(percent_encoding[index] == '%'); + return (16*value_of_hex_digit(percent_encoding[index + 1])) + value_of_hex_digit(percent_encoding[index + 2]); +} + +} // (anonymous namespace) + +namespace util { + +std::string make_percent_encoded_string(const std::string& raw_string) +{ + std::string buffer; + buffer.reserve(raw_string.size()); + for (size_t i=0; i 0); + std::string escaped_path = util::make_percent_encoded_string(path); + if (filename_is_reserved(escaped_path)) + throw std::invalid_argument(util::format("A path can't have an identifier reserved by the filesystem: '%1'", escaped_path)); + return escaped_path; +} + +} // util + +SyncFileManager::SyncFileManager(const std::string& base_path, const std::string& app_id) +: m_base_path(util::file_path_by_appending_component(base_path, + c_sync_directory, + util::FilePathType::Directory)) +, m_app_path(util::file_path_by_appending_component(m_base_path, + util::validate_and_clean_path(app_id), + util::FilePathType::Directory)) +{ + util::try_make_dir(m_base_path); + util::try_make_dir(m_app_path); +} + +std::string SyncFileManager::get_special_directory(std::string directory_name) const +{ + auto dir_path = file_path_by_appending_component(m_app_path, + directory_name, + util::FilePathType::Directory); + util::try_make_dir(dir_path); + return dir_path; +} + +std::string SyncFileManager::user_directory(const std::string& user_identity) const +{ + std::string user_path = get_user_directory_path(user_identity); + util::try_make_dir(user_path); + return user_path; +} + +void SyncFileManager::remove_user_directory(const std::string& user_identity) const +{ + std::string user_path = get_user_directory_path(user_identity); + util::try_remove_dir_recursive(user_path); +} + +bool SyncFileManager::try_rename_user_directory(const std::string& old_name, const std::string& new_name) const +{ + const auto& old_name_escaped = util::validate_and_clean_path(old_name); + const auto& new_name_escaped = util::validate_and_clean_path(new_name); + const std::string& base = m_app_path; + const auto& old_path = file_path_by_appending_component(base, old_name_escaped, util::FilePathType::Directory); + const auto& new_path = file_path_by_appending_component(base, new_name_escaped, util::FilePathType::Directory); + + try { + File::move(old_path, new_path); + } catch (File::NotFound const&) { + return false; + } + return true; +} + +bool SyncFileManager::remove_realm(const std::string& absolute_path) const +{ + REALM_ASSERT(absolute_path.length() > 0); + bool success = true; + // Remove the Realm file (e.g. "example.realm"). + success = File::try_remove(absolute_path); + // Remove the lock file (e.g. "example.realm.lock"). + auto lock_path = util::file_path_by_appending_extension(absolute_path, "lock"); + success = File::try_remove(lock_path); + // Remove the management directory (e.g. "example.realm.management"). + auto management_path = util::file_path_by_appending_extension(absolute_path, "management"); + try { + util::try_remove_dir_recursive(management_path); + } + catch (File::AccessError const&) { + success = false; + } + return success; +} + +bool SyncFileManager::copy_realm_file(const std::string& old_path, const std::string& new_path) const +{ + REALM_ASSERT(old_path.length() > 0); + try { + if (File::exists(new_path)) { + return false; + } + File::copy(old_path, new_path); + } + catch (File::NotFound const&) { + return false; + } + catch (File::AccessError const&) { + return false; + } + return true; +} + +bool SyncFileManager::remove_realm(const std::string& user_identity, const std::string& raw_realm_path) const +{ + auto escaped = util::validate_and_clean_path(raw_realm_path); + auto realm_path = util::file_path_by_appending_component(user_directory(user_identity), escaped); + return remove_realm(realm_path); +} + +bool SyncFileManager::try_file_exists(const std::string& path) noexcept +{ + try { + // May throw; for example when the path is too long + return util::File::exists(path); + } + catch (const std::exception&) { + return false; + } +} + +static bool try_file_remove(const std::string& path) noexcept +{ + try { + return util::File::try_remove(path); + } + catch (const std::exception&) { + return false; + } +} + +std::string SyncFileManager::realm_file_path(const std::string& user_identity, const std::string& local_user_identity, const std::string& realm_file_name) const +{ + auto escaped_file_name = util::validate_and_clean_path(realm_file_name); + std::string preferred_name = util::file_path_by_appending_component(user_directory(user_identity), escaped_file_name); + std::string preferred_path = preferred_name + c_realm_file_suffix; + + if (!try_file_exists(preferred_path)) { + // Shorten the Realm path to just `/.realm` + // If that also fails, give up and report error to user. + std::string hashed_name = fallback_hashed_realm_file_path(preferred_name); + std::string hashed_path = hashed_name + c_realm_file_suffix; + if (try_file_exists(hashed_path)) { + // detected that the hashed fallback has been used previously + // it was created for a reason so keep using it + return hashed_path; + } + + // retain support for legacy paths + std::string old_path = legacy_realm_file_path(local_user_identity, realm_file_name); + if (try_file_exists(old_path)) { + return old_path; + } + + // retain support for legacy local identity paths + std::string old_local_identity_path = legacy_local_identity_path(local_user_identity, realm_file_name); + if (try_file_exists(old_local_identity_path)) { + return old_local_identity_path; + } + + // since this appears to be a new file, test the normal location + // we use a test file with the same name and a suffix of the + // same length so we can catch "filename too long" errors on windows + try { + std::string test_path = preferred_name + c_realm_file_test_suffix; + auto defer = util::make_scope_exit([test_path]() noexcept { + try_file_remove(test_path); + }); + util::File f(test_path, util::File::Mode::mode_Write); + // if the test file succeeds, delete it and return the preferred location + } + catch (const File::AccessError& e_absolute) { + // the preferred test failed, test the hashed path + try { + std::string test_hashed_path = hashed_name + c_realm_file_test_suffix; + auto defer = util::make_scope_exit([test_hashed_path]() noexcept { + try_file_remove(test_hashed_path); + }); + util::File f(test_hashed_path, util::File::Mode::mode_Write); + // at this point the create succeeded, clean up the test file and return the hashed path + return hashed_path; + } + catch (const File::AccessError& e_hashed) { + // hashed test path also failed, give up and report error to user. + throw std::logic_error(util::format("A valid realm path cannot be created for the " + "Realm identity '%1' at neither '%2' nor '%3'. %4", + realm_file_name, preferred_path, hashed_path, e_hashed.what())); + } + } + } + + return preferred_path; +} + +std::string SyncFileManager::metadata_path() const +{ + auto dir_path = file_path_by_appending_component(get_utility_directory(), + c_metadata_directory, + util::FilePathType::Directory); + util::try_make_dir(dir_path); + return util::file_path_by_appending_component(dir_path, c_metadata_realm); +} + +bool SyncFileManager::remove_metadata_realm() const +{ + auto dir_path = file_path_by_appending_component(get_utility_directory(), + c_metadata_directory, + util::FilePathType::Directory); + try { + util::try_remove_dir_recursive(dir_path); + return true; + } + catch (File::AccessError const&) { + return false; + } +} + +std::string SyncFileManager::fallback_hashed_realm_file_path(const std::string& preferred_path) const +{ + std::array hash; + util::sha256(preferred_path.data(), preferred_path.size(), hash.data()); + std::string hashed_name = util::file_path_by_appending_component(m_app_path, util::hex_dump(hash.data(), hash.size(), "")); + return hashed_name; +} + +std::string SyncFileManager::legacy_realm_file_path(const std::string& local_user_identity, const std::string& realm_file_name) const +{ + auto path = util::file_path_by_appending_component(m_app_path, c_legacy_sync_directory, util::FilePathType::Directory); + path = util::file_path_by_appending_component(path, util::validate_and_clean_path(local_user_identity), util::FilePathType::Directory); + path = util::file_path_by_appending_component(path, util::validate_and_clean_path(realm_file_name)); + return path; +} + +std::string SyncFileManager::legacy_local_identity_path(const std::string& local_user_identity, const std::string& realm_file_name) const +{ + auto escaped_file_name = util::validate_and_clean_path(realm_file_name); + std::string user_path = get_user_directory_path(local_user_identity); + std::string path_name = util::file_path_by_appending_component(user_path, escaped_file_name); + std::string path = path_name + c_realm_file_suffix; + + return path; +} + +std::string SyncFileManager::get_user_directory_path(const std::string& user_identity) const { + return file_path_by_appending_component(m_app_path, + util::validate_and_clean_path(user_identity), + util::FilePathType::Directory); +} + +} // realm diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/impl/sync_metadata.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/impl/sync_metadata.cpp new file mode 100644 index 0000000..8144487 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/impl/sync_metadata.cpp @@ -0,0 +1,780 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// 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 "sync/impl/sync_metadata.hpp" +#include "impl/realm_coordinator.hpp" + +#include "object_schema.hpp" +#include "object_store.hpp" +#include "property.hpp" +#include "results.hpp" +#include "schema.hpp" +#include "util/uuid.hpp" +#if REALM_PLATFORM_APPLE +#include "impl/apple/keychain_helper.hpp" +#endif + +#include +#include + +namespace { +static const char * const c_sync_userMetadata = "UserMetadata"; +static const char * const c_sync_identityMetadata = "UserIdentity"; +static const char * const c_sync_app_metadata = "AppMetadata"; + +static const char * const c_sync_current_user_identity = "current_user_identity"; + +/* User keys*/ +static const char * const c_sync_marked_for_removal = "marked_for_removal"; +static const char * const c_sync_identity = "identity"; +static const char * const c_sync_local_uuid = "local_uuid"; +static const char * const c_sync_refresh_token = "refresh_token"; +static const char * const c_sync_access_token = "access_token"; +static const char * const c_sync_identities = "identities"; +static const char * const c_sync_state = "state"; +static const char * const c_sync_device_id = "device_id"; + +/* User Profile keys */ +static const char * const c_sync_profile = "profile"; +static const char * const c_sync_profile_name = "name"; +static const char * const c_sync_profile_first_name = "first_name"; +static const char * const c_sync_profile_last_name = "last_name"; +static const char * const c_sync_profile_picture_url = "picture_url"; +static const char * const c_sync_profile_email = "email"; +static const char * const c_sync_profile_gender = "gender"; +static const char * const c_sync_profile_birthday = "birthday"; +static const char * const c_sync_profile_min_age = "min_age"; +static const char * const c_sync_profile_max_age = "max_age"; + +/* Identity keys */ +static const char * const c_sync_user_id = "id"; +static const char * const c_sync_provider_type = "provider_type"; + +static const char * const c_sync_fileActionMetadata = "FileActionMetadata"; +static const char * const c_sync_original_name = "original_name"; +static const char * const c_sync_new_name = "new_name"; +static const char * const c_sync_action = "action"; +static const char * const c_sync_url = "url"; + +static const char * const c_sync_clientMetadata = "ClientMetadata"; +static const char * const c_sync_uuid = "uuid"; + +static const char * const c_sync_app_metadata_id = "id"; +static const char * const c_sync_app_metadata_deployment_model = "deployment_model"; +static const char * const c_sync_app_metadata_location = "location"; +static const char * const c_sync_app_metadata_hostname = "hostname"; +static const char * const c_sync_app_metadata_ws_hostname = "ws_hostname"; + +realm::Schema make_schema() +{ + using namespace realm; + return Schema{ + {c_sync_identityMetadata, { + {c_sync_user_id, PropertyType::String}, + {c_sync_provider_type, PropertyType::String} + }}, + {c_sync_profile, { + {c_sync_profile_name, PropertyType::String|PropertyType::Nullable}, + {c_sync_profile_first_name, PropertyType::String|PropertyType::Nullable}, + {c_sync_profile_last_name, PropertyType::String|PropertyType::Nullable}, + {c_sync_profile_picture_url, PropertyType::String|PropertyType::Nullable}, + {c_sync_profile_gender, PropertyType::String|PropertyType::Nullable}, + {c_sync_profile_birthday, PropertyType::String|PropertyType::Nullable}, + {c_sync_profile_email, PropertyType::String|PropertyType::Nullable}, + {c_sync_profile_max_age, PropertyType::String|PropertyType::Nullable}, + {c_sync_profile_min_age, PropertyType::String|PropertyType::Nullable} + }}, + {c_sync_userMetadata, { + {c_sync_identity, PropertyType::String}, + {c_sync_local_uuid, PropertyType::String}, + {c_sync_marked_for_removal, PropertyType::Bool}, + {c_sync_refresh_token, PropertyType::String|PropertyType::Nullable}, + {c_sync_provider_type, PropertyType::String}, + {c_sync_access_token, PropertyType::String|PropertyType::Nullable}, + {c_sync_identities, PropertyType::Object|PropertyType::Array, c_sync_identityMetadata}, + {c_sync_profile, PropertyType::Object|PropertyType::Nullable, c_sync_profile}, + {c_sync_state, PropertyType::Int}, + {c_sync_device_id, PropertyType::String} + }}, + {c_sync_fileActionMetadata, { + {c_sync_original_name, PropertyType::String, Property::IsPrimary{true}}, + {c_sync_new_name, PropertyType::String|PropertyType::Nullable}, + {c_sync_action, PropertyType::Int}, + {c_sync_url, PropertyType::String}, + {c_sync_identity, PropertyType::String}, + }}, + {c_sync_clientMetadata, { + {c_sync_uuid, PropertyType::String}, + }}, + {c_sync_current_user_identity, { + {c_sync_current_user_identity, PropertyType::String} + }}, + {c_sync_app_metadata, { + {c_sync_app_metadata_id, PropertyType::Int, Property::IsPrimary{true}}, + {c_sync_app_metadata_deployment_model, PropertyType::String}, + {c_sync_app_metadata_location, PropertyType::String}, + {c_sync_app_metadata_hostname, PropertyType::String}, + {c_sync_app_metadata_ws_hostname, PropertyType::String} + }} + }; +} + +} // anonymous namespace + +namespace realm { + +// MARK: - Sync metadata manager + +SyncMetadataManager::SyncMetadataManager(std::string path, + bool should_encrypt, + util::Optional> encryption_key) +{ + constexpr uint64_t SCHEMA_VERSION = 4; + + Realm::Config config; + config.automatic_change_notifications = false; + config.path = path; + config.schema = make_schema(); + config.schema_version = SCHEMA_VERSION; + config.schema_mode = SchemaMode::Automatic; +#if REALM_PLATFORM_APPLE + if (should_encrypt && !encryption_key) { + encryption_key = keychain::metadata_realm_encryption_key(util::File::exists(path)); + } +#endif + if (should_encrypt) { + if (!encryption_key) { + throw std::invalid_argument("Metadata Realm encryption was specified, but no encryption key was provided."); + } + config.encryption_key = std::move(*encryption_key); + } + + config.migration_function = [](SharedRealm old_realm, SharedRealm realm, Schema&) { + if (old_realm->schema_version() < 2) { + TableRef old_table = ObjectStore::table_for_object_type(old_realm->read_group(), c_sync_userMetadata); + TableRef table = ObjectStore::table_for_object_type(realm->read_group(), c_sync_userMetadata); + + // Column indices. + ColKey old_idx_identity = old_table->get_column_key(c_sync_identity); + ColKey old_idx_url = old_table->get_column_key(c_sync_provider_type); + ColKey idx_local_uuid = table->get_column_key(c_sync_local_uuid); + ColKey idx_url = table->get_column_key(c_sync_provider_type); + + auto to = table->begin(); + for (auto& from : *old_table) { + REALM_ASSERT(to != table->end()); + // Set the UUID equal to the user identity for existing users. + auto identity = from.get(old_idx_identity); + to->set(idx_local_uuid, identity); + // Migrate the auth server URLs to a non-nullable property. + auto url = from.get(old_idx_url); + to->set(idx_url, url.is_null() ? "" : url); + ++to; + } + } + }; + + SharedRealm realm = Realm::get_shared_realm(config); + + // Get data about the (hardcoded) schemas + auto object_schema = realm->schema().find(c_sync_userMetadata); + m_user_schema = { + object_schema->persisted_properties[0].column_key, + object_schema->persisted_properties[1].column_key, + object_schema->persisted_properties[2].column_key, + object_schema->persisted_properties[3].column_key, + object_schema->persisted_properties[4].column_key, + object_schema->persisted_properties[5].column_key, + object_schema->persisted_properties[6].column_key, + object_schema->persisted_properties[7].column_key, + object_schema->persisted_properties[8].column_key, + object_schema->persisted_properties[9].column_key + }; + + object_schema = realm->schema().find(c_sync_fileActionMetadata); + m_file_action_schema = { + object_schema->persisted_properties[0].column_key, + object_schema->persisted_properties[1].column_key, + object_schema->persisted_properties[2].column_key, + object_schema->persisted_properties[3].column_key, + object_schema->persisted_properties[4].column_key, + }; + + object_schema = realm->schema().find(c_sync_clientMetadata); + m_client_schema = { + object_schema->persisted_properties[0].column_key, + }; + + object_schema = realm->schema().find(c_sync_current_user_identity); + m_current_user_identity_schema = { + object_schema->persisted_properties[0].column_key + }; + + object_schema = realm->schema().find(c_sync_profile); + m_profile_schema = { + object_schema->persisted_properties[0].column_key, + object_schema->persisted_properties[1].column_key, + object_schema->persisted_properties[2].column_key, + object_schema->persisted_properties[3].column_key, + object_schema->persisted_properties[4].column_key, + object_schema->persisted_properties[5].column_key, + object_schema->persisted_properties[6].column_key, + object_schema->persisted_properties[7].column_key + }; + + object_schema = realm->schema().find(c_sync_app_metadata); + m_app_metadata_schema = { + object_schema->persisted_properties[0].column_key, + object_schema->persisted_properties[1].column_key, + object_schema->persisted_properties[2].column_key, + object_schema->persisted_properties[3].column_key, + object_schema->persisted_properties[4].column_key + }; + + m_metadata_config = std::move(config); + + m_client_uuid = [&]() -> std::string { + TableRef table = ObjectStore::table_for_object_type(realm->read_group(), c_sync_clientMetadata); + if (table->is_empty()) { + realm->begin_transaction(); + if (table->is_empty()) { + auto uuid = util::uuid_string(); + table->create_object().set(m_client_schema.idx_uuid, uuid); + realm->commit_transaction(); + return uuid; + } + realm->cancel_transaction(); + } + return table->begin()->get(m_client_schema.idx_uuid); + }(); +} + +SyncUserMetadataResults SyncMetadataManager::all_unmarked_users() const +{ + return get_users(false); +} + +SyncUserMetadataResults SyncMetadataManager::all_users_marked_for_removal() const +{ + return get_users(true); +} + +SyncUserMetadataResults SyncMetadataManager::get_users(bool marked) const +{ + auto realm = get_realm(); + TableRef table = ObjectStore::table_for_object_type(realm->read_group(), c_sync_userMetadata); + Query query = table->where().equal(m_user_schema.idx_marked_for_removal, marked); + + Results results(realm, std::move(query)); + return SyncUserMetadataResults(std::move(results), std::move(realm), m_user_schema); +} + +util::Optional SyncMetadataManager::get_current_user_identity() const +{ + auto realm = get_realm(); + TableRef table = ObjectStore::table_for_object_type(realm->read_group(), c_sync_current_user_identity); + + if (!table->is_empty()) { + auto first = table->begin(); + return util::Optional(first->get(c_sync_current_user_identity)); + } + + return util::Optional(); +} + +SyncFileActionMetadataResults SyncMetadataManager::all_pending_actions() const +{ + auto realm = get_realm(); + TableRef table = ObjectStore::table_for_object_type(realm->read_group(), c_sync_fileActionMetadata); + Results results(realm, table->where()); + return SyncFileActionMetadataResults(std::move(results), std::move(realm), m_file_action_schema); +} + +void SyncMetadataManager::set_current_user_identity(const std::string& identity) +{ + auto realm = get_realm(); + + realm->begin_transaction(); + + TableRef currentUserIdentityTable = ObjectStore::table_for_object_type(realm->read_group(), + c_sync_current_user_identity); + + Obj currentUserIdentityObj; + if (currentUserIdentityTable->is_empty()) + currentUserIdentityObj = currentUserIdentityTable->create_object(); + else + currentUserIdentityObj = *currentUserIdentityTable->begin(); + + currentUserIdentityObj.set(c_sync_current_user_identity, identity); + + realm->commit_transaction(); +} + +util::Optional SyncMetadataManager::get_or_make_user_metadata(const std::string& identity, + const std::string& provider_type, + bool make_if_absent) const +{ + auto realm = get_realm(); + auto& schema = m_user_schema; + + // Retrieve or create the row for this object. + TableRef table = ObjectStore::table_for_object_type(realm->read_group(), c_sync_userMetadata); + Query query = table->where().equal(schema.idx_identity, identity) + .equal(schema.idx_provider_type, provider_type); + Results results(realm, std::move(query)); + REALM_ASSERT_DEBUG(results.size() < 2); + auto row = results.first(); + + if (!row) { + if (!make_if_absent) + return none; + + realm->begin_transaction(); + // Check the results again. + row = results.first(); + if (!row) { + // Because "making this user" is our last action, set this new user as the current user + TableRef currentUserIdentityTable = ObjectStore::table_for_object_type(realm->read_group(), + c_sync_current_user_identity); + + Obj currentUserIdentityObj; + if (currentUserIdentityTable->is_empty()) + currentUserIdentityObj = currentUserIdentityTable->create_object(); + else + currentUserIdentityObj = *currentUserIdentityTable->begin(); + + auto obj = table->create_object(); + + currentUserIdentityObj.set(c_sync_current_user_identity, identity); + + std::string uuid = util::uuid_string(); + obj.set(schema.idx_identity, identity); + obj.set(schema.idx_provider_type, provider_type); + obj.set(schema.idx_local_uuid, uuid); + obj.set(schema.idx_marked_for_removal, false); + obj.set(schema.idx_state, (int64_t)SyncUser::State::LoggedIn); + realm->commit_transaction(); + return SyncUserMetadata(schema, std::move(realm), std::move(obj)); + } else { + // Someone beat us to adding this user. + if (row->get(schema.idx_marked_for_removal)) { + // User is dead. Revive or return none. + if (make_if_absent) { + row->set(schema.idx_marked_for_removal, false); + realm->commit_transaction(); + } else { + realm->cancel_transaction(); + return none; + } + } else { + // User is alive, nothing else to do. + realm->cancel_transaction(); + } + return SyncUserMetadata(schema, std::move(realm), std::move(*row)); + } + } + + // Got an existing user. + if (row->get(schema.idx_marked_for_removal)) { + // User is dead. Revive or return none. + if (make_if_absent) { + realm->begin_transaction(); + row->set(schema.idx_marked_for_removal, false); + realm->commit_transaction(); + } else { + return none; + } + } + + return SyncUserMetadata(schema, std::move(realm), std::move(*row)); +} + +void SyncMetadataManager::make_file_action_metadata(StringData original_name, + StringData partition_key_value, + StringData local_uuid, + SyncFileActionMetadata::Action action, + StringData new_name) const +{ + // This function can't use get_shared_realm() because it's called on a + // background thread and that's currently not supported by the libuv + // implementation of EventLoopSignal + auto coordinator = _impl::RealmCoordinator::get_coordinator(m_metadata_config); + auto group_ptr = coordinator->begin_read(); + auto& group = *group_ptr; + REALM_ASSERT(typeid(group) == typeid(Transaction)); + auto& transaction = static_cast(group); + transaction.promote_to_write(); + + // Retrieve or create the row for this object. + TableRef table = ObjectStore::table_for_object_type(group, c_sync_fileActionMetadata); + + auto& schema = m_file_action_schema; + Obj obj = table->create_object_with_primary_key(original_name); + + obj.set(schema.idx_new_name, new_name); + obj.set(schema.idx_action, static_cast(action)); + obj.set(schema.idx_url, partition_key_value); + obj.set(schema.idx_user_identity, local_uuid); + transaction.commit(); +} + +util::Optional SyncMetadataManager::get_file_action_metadata(StringData original_name) const +{ + auto realm = get_realm(); + auto& schema = m_file_action_schema; + TableRef table = ObjectStore::table_for_object_type(realm->read_group(), c_sync_fileActionMetadata); + auto row_idx = table->find_first_string(schema.idx_original_name, original_name); + if (!row_idx) + return none; + + return SyncFileActionMetadata(std::move(schema), std::move(realm), table->get_object(row_idx)); +} + +std::shared_ptr SyncMetadataManager::get_realm() const +{ + auto realm = Realm::get_shared_realm(m_metadata_config); + realm->refresh(); + return realm; +} + +/// Magic key to fetch app metadata, which there should always only be one of. +static const auto app_metadata_pk = 1; + +void SyncMetadataManager::set_app_metadata(const std::string& deployment_model, + const std::string& location, + const std::string& hostname, + const std::string& ws_hostname) const +{ + if (m_app_metadata) { + return; + } + + auto realm = get_realm(); + auto& schema = m_app_metadata_schema; + + realm->begin_transaction(); + + auto table = ObjectStore::table_for_object_type(realm->read_group(), c_sync_app_metadata); + auto obj = table->create_object_with_primary_key(app_metadata_pk); + obj.set(schema.idx_deployment_model, deployment_model); + obj.set(schema.idx_location, location); + obj.set(schema.idx_hostname, hostname); + obj.set(schema.idx_ws_hostname, ws_hostname); + + realm->commit_transaction(); +} + +util::Optional SyncMetadataManager::get_app_metadata() +{ + if (!m_app_metadata) { + auto realm = get_realm(); + auto table = ObjectStore::table_for_object_type(realm->read_group(), c_sync_app_metadata); + if (!table->size()) + return util::none; + + auto obj = table->get_object_with_primary_key(app_metadata_pk); + auto& schema = m_app_metadata_schema; + m_app_metadata = SyncAppMetadata { + obj.get(schema.idx_deployment_model), + obj.get(schema.idx_location), + obj.get(schema.idx_hostname), + obj.get(schema.idx_ws_hostname) + }; + } + + return m_app_metadata; +} + +// MARK: - Sync user metadata + +SyncUserMetadata::SyncUserMetadata(Schema schema, SharedRealm realm, const Obj& obj) +: m_realm(std::move(realm)) +, m_schema(std::move(schema)) +, m_obj(obj) +{ } + +std::string SyncUserMetadata::identity() const +{ + REALM_ASSERT(m_realm); + m_realm->verify_thread(); + m_realm->refresh(); + return m_obj.get(m_schema.idx_identity); +} + +SyncUser::State SyncUserMetadata::state() const +{ + REALM_ASSERT(m_realm); + m_realm->verify_thread(); + m_realm->refresh(); + return SyncUser::State(m_obj.get(m_schema.idx_state)); +} + +std::string SyncUserMetadata::local_uuid() const +{ + REALM_ASSERT(m_realm); + m_realm->verify_thread(); + m_realm->refresh(); + return m_obj.get(m_schema.idx_local_uuid); +} + +std::string SyncUserMetadata::refresh_token() const +{ + REALM_ASSERT(m_realm); + m_realm->verify_thread(); + m_realm->refresh(); + StringData result = m_obj.get(m_schema.idx_refresh_token); + return result.is_null() ? "" : std::string(result); +} + +std::string SyncUserMetadata::access_token() const +{ + REALM_ASSERT(m_realm); + m_realm->verify_thread(); + StringData result = m_obj.get(m_schema.idx_access_token); + return result.is_null() ? "" : std::string(result); +} + +std::string SyncUserMetadata::device_id() const +{ + REALM_ASSERT(m_realm); + m_realm->verify_thread(); + StringData result = m_obj.get(m_schema.idx_device_id); + return result.is_null() ? "" : std::string(result); +} + +inline SyncUserIdentity user_identity_from_obj(const ConstObj& obj) +{ + return SyncUserIdentity(obj.get(c_sync_user_id), obj.get(c_sync_provider_type)); +} + +std::vector SyncUserMetadata::identities() const +{ + REALM_ASSERT(m_realm); + m_realm->verify_thread(); + m_realm->refresh(); + auto linklist = m_obj.get_linklist(m_schema.idx_identities); + + std::vector identities; + for (size_t i = 0; i < linklist.size(); i++) + { + auto obj_key = linklist.get(i); + auto obj = linklist.get_target_table()->get_object(obj_key); + identities.push_back(user_identity_from_obj(obj)); + } + + return identities; +} + +std::string SyncUserMetadata::provider_type() const +{ + REALM_ASSERT(m_realm); + m_realm->verify_thread(); + m_realm->refresh(); + return m_obj.get(m_schema.idx_provider_type); +} + +void SyncUserMetadata::set_refresh_token(const std::string& refresh_token) +{ + if (m_invalid) + return; + + REALM_ASSERT_DEBUG(m_realm); + m_realm->verify_thread(); + m_realm->begin_transaction(); + m_obj.set(m_schema.idx_refresh_token, refresh_token); + m_realm->commit_transaction(); +} + +void SyncUserMetadata::set_state(SyncUser::State state) +{ + if (m_invalid) + return; + + REALM_ASSERT_DEBUG(m_realm); + m_realm->verify_thread(); + m_realm->begin_transaction(); + m_obj.set(m_schema.idx_state, (int64_t)state); + m_realm->commit_transaction(); +} + +void SyncUserMetadata::set_identities(std::vector identities) +{ + if (m_invalid) + return; + + REALM_ASSERT_DEBUG(m_realm); + m_realm->verify_thread(); + m_realm->begin_transaction(); + + auto link_list = m_obj.get_linklist(m_schema.idx_identities); + + link_list.clear(); + + for (size_t i = 0; i < identities.size(); i++) + { + auto obj = link_list.get_target_table()->create_object(); + obj.set(c_sync_user_id, identities[i].id); + obj.set(c_sync_provider_type, identities[i].provider_type); + link_list.add(obj.get_key()); + } + + m_realm->commit_transaction(); +} + +void SyncUserMetadata::set_access_token(const std::string& user_token) +{ + if (m_invalid) + return; + + REALM_ASSERT_DEBUG(m_realm); + m_realm->verify_thread(); + m_realm->begin_transaction(); + m_obj.set(m_schema.idx_access_token, user_token); + m_realm->commit_transaction(); +} + +void SyncUserMetadata::set_device_id(const std::string& device_id) +{ + if (m_invalid) + return; + + REALM_ASSERT_DEBUG(m_realm); + m_realm->verify_thread(); + m_realm->begin_transaction(); + m_obj.set(m_schema.idx_device_id, device_id); + m_realm->commit_transaction(); +} + +void SyncUserMetadata::set_user_profile(const SyncUserProfile& profile) +{ + if (m_invalid) + return; + + REALM_ASSERT_DEBUG(m_realm); + m_realm->verify_thread(); + m_realm->begin_transaction(); + + Obj obj; + if (m_obj.is_null(m_schema.idx_profile)) { + obj = m_obj.create_and_set_linked_object(m_schema.idx_profile); + } else { + obj = m_obj.get_linked_object(m_schema.idx_profile); + } + + if (profile.name) + obj.set(c_sync_profile_name, *profile.name); + if (profile.first_name) + obj.set(c_sync_profile_first_name, *profile.first_name); + if (profile.last_name) + obj.set(c_sync_profile_last_name, *profile.last_name); + if (profile.gender) + obj.set(c_sync_profile_gender, *profile.gender); + if (profile.picture_url) + obj.set(c_sync_profile_picture_url, *profile.picture_url); + if (profile.birthday) + obj.set(c_sync_profile_birthday, *profile.birthday); + if (profile.min_age) + obj.set(c_sync_profile_min_age, *profile.min_age); + if (profile.max_age) + obj.set(c_sync_profile_max_age, *profile.max_age); + if (profile.email) + obj.set(c_sync_profile_email, *profile.email); + + m_realm->commit_transaction(); +} + +void SyncUserMetadata::mark_for_removal() +{ + if (m_invalid) + return; + + m_realm->verify_thread(); + m_realm->begin_transaction(); + m_obj.set(m_schema.idx_marked_for_removal, true); + m_realm->commit_transaction(); +} + +void SyncUserMetadata::remove() +{ + m_invalid = true; + m_realm->begin_transaction(); + m_obj.remove(); + m_realm->commit_transaction(); + m_realm = nullptr; +} + +// MARK: - File action metadata + +SyncFileActionMetadata::SyncFileActionMetadata(Schema schema, SharedRealm realm, const Obj& obj) +: m_realm(std::move(realm)) +, m_schema(std::move(schema)) +, m_obj(obj) +{ } + +std::string SyncFileActionMetadata::original_name() const +{ + REALM_ASSERT(m_realm); + m_realm->verify_thread(); + m_realm->refresh(); + return m_obj.get(m_schema.idx_original_name); +} + +util::Optional SyncFileActionMetadata::new_name() const +{ + REALM_ASSERT(m_realm); + m_realm->verify_thread(); + m_realm->refresh(); + StringData result =m_obj.get(m_schema.idx_new_name); + return result.is_null() ? util::none : util::make_optional(std::string(result)); +} + +std::string SyncFileActionMetadata::user_local_uuid() const +{ + REALM_ASSERT(m_realm); + m_realm->verify_thread(); + m_realm->refresh(); + return m_obj.get(m_schema.idx_user_identity); +} + +SyncFileActionMetadata::Action SyncFileActionMetadata::action() const +{ + REALM_ASSERT(m_realm); + m_realm->verify_thread(); + m_realm->refresh(); + return static_cast(m_obj.get(m_schema.idx_action)); +} + +std::string SyncFileActionMetadata::url() const +{ + REALM_ASSERT(m_realm); + m_realm->verify_thread(); + m_realm->refresh(); + return m_obj.get(m_schema.idx_url); +} + +void SyncFileActionMetadata::remove() +{ + REALM_ASSERT(m_realm); + m_realm->verify_thread(); + m_realm->begin_transaction(); + m_obj.remove(); + m_realm->commit_transaction(); + m_realm = nullptr; +} + +} // namespace realm diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/push_client.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/push_client.cpp new file mode 100644 index 0000000..bb17ccc --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/push_client.cpp @@ -0,0 +1,84 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 utilied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#include "sync/push_client.hpp" +#include "sync/app_utils.hpp" + +namespace realm { +namespace app { + +void PushClient::register_device(const std::string& registration_token, + std::shared_ptr sync_user, + std::function)> completion_block) +{ + auto handler = [completion_block](const Response& response) { + if (auto error = AppUtils::check_for_errors(response)) { + return completion_block(error); + } else { + return completion_block({}); + } + }; + auto push_route = util::format("/app/%1/push/providers/%2/registration", m_app_id, m_service_name); + std::string route = m_auth_request_client->url_for_path(push_route); + + bson::BsonDocument args { + {"registrationToken", registration_token} + }; + + std::stringstream s; + s << bson::Bson(args); + + m_auth_request_client->do_authenticated_request({ + HttpMethod::put, + route, + m_timeout_ms, + {}, + s.str(), + false + }, + sync_user, + handler); +} + +void PushClient::deregister_device(std::shared_ptr sync_user, + std::function)> completion_block) +{ + auto handler = [completion_block](const Response& response) { + if (auto error = AppUtils::check_for_errors(response)) { + return completion_block(error); + } else { + return completion_block({}); + } + }; + auto push_route = util::format("/app/%1/push/providers/%2/registration", m_app_id, m_service_name); + std::string route = m_auth_request_client->url_for_path(push_route); + + m_auth_request_client->do_authenticated_request({ + HttpMethod::del, + route, + m_timeout_ms, + {}, + "", + false + }, + sync_user, + handler); +} + +} // namespace app +} // namespace realm diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/remote_mongo_client.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/remote_mongo_client.cpp new file mode 100644 index 0000000..e7c448a --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/remote_mongo_client.cpp @@ -0,0 +1,36 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 utilied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#include "sync/remote_mongo_client.hpp" +#include "sync/remote_mongo_database.hpp" + +namespace realm { +namespace app { + +MongoDatabase MongoClient::operator[](const std::string& name) +{ + return MongoDatabase(name, m_user, m_service, m_service_name); +} + +MongoDatabase MongoClient::db(const std::string& name) +{ + return MongoDatabase(name, m_user, m_service, m_service_name); +} + +} // namespace app +} // namespace realm diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/remote_mongo_collection.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/remote_mongo_collection.cpp new file mode 100644 index 0000000..e9ca68c --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/remote_mongo_collection.cpp @@ -0,0 +1,643 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 utilied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#include "sync/remote_mongo_collection.hpp" +#include "realm/util/uri.hpp" + +namespace realm { +namespace app { + +using ResponseHandler = std::function, util::Optional)>; + +namespace { + +ResponseHandler get_delete_count_handler( + std::function)> completion_block) +{ + return [completion_block](util::Optional error, util::Optional value) { + if (value && !error) { + try { + auto document = static_cast(*value); + auto count = static_cast(document["deletedCount"]); + return completion_block(count, error); + } + catch (const std::exception& e) { + return completion_block(0, AppError(make_error_code(JSONErrorCode::bad_bson_parse), e.what())); + } + } + + return completion_block(0, error); + }; +} + +ResponseHandler get_update_handler( + std::function)> completion_block) +{ + return [completion_block](util::Optional error, util::Optional value) { + if (error) { + return completion_block({}, error); + } + + try { + auto document = static_cast(*value); + auto matched_count = static_cast(document["matchedCount"]); + auto modified_count = static_cast(document["modifiedCount"]); + + util::Optional upserted_id; + auto it = document.find("upsertedId"); + if (it != document.end()) { + upserted_id = static_cast(document["upsertedId"]); + } + + return completion_block(MongoCollection::UpdateResult{ + matched_count, + modified_count, + upserted_id + }, error); + } + catch (const std::exception& e) { + return completion_block({}, AppError(make_error_code(JSONErrorCode::bad_bson_parse), e.what())); + } + }; +} + +ResponseHandler get_document_handler( + std::function, util::Optional)> completion_block) +{ + return [completion_block](util::Optional error, util::Optional value) { + if (error) { + return completion_block(util::none, error); + } + + if (!value) { + // no docs were found + return completion_block(util::none, util::none); + } + + if (bson::holds_alternative(*value)) { + // no docs were found + return completion_block(util::none, util::none); + } + + return completion_block(static_cast(*value), util::none); + }; +} + +} // anonymous namespace + +void MongoCollection::find(const bson::BsonDocument& filter_bson, + FindOptions options, + std::function, util::Optional)> completion_block) +{ + find_bson(filter_bson, options, [completion_block](util::Optional error, util::Optional value) { + if (error) { + return completion_block(util::none, error); + } + + return completion_block(static_cast(*value), util::none); + }); +} + +void MongoCollection::find(const bson::BsonDocument& filter_bson, + std::function, util::Optional)> completion_block) +{ + find(filter_bson, {}, completion_block); +} + +void MongoCollection::find_one(const bson::BsonDocument& filter_bson, + FindOptions options, + std::function, util::Optional)> completion_block) +{ + find_one_bson(filter_bson, options, get_document_handler(completion_block)); +} + +void MongoCollection::find_one(const bson::BsonDocument& filter_bson, + std::function, + util::Optional)> completion_block) +{ + find_one(filter_bson, {}, completion_block); +} + +void MongoCollection::insert_one(const bson::BsonDocument& value_bson, + std::function, util::Optional)> completion_block) +{ + insert_one_bson(value_bson, [completion_block](util::Optional error, util::Optional value) { + if (error) { + return completion_block(util::none, error); + } + + auto document = static_cast(*value); + + return completion_block(document["insertedId"], util::none); + }); +} + +void MongoCollection::aggregate(const bson::BsonArray& pipeline, + std::function, util::Optional)> completion_block) +{ + aggregate_bson(pipeline, [completion_block](util::Optional error, util::Optional value) { + if (error) { + return completion_block(util::none, error); + } + + return completion_block(static_cast(*value), util::none); + }); +} + +void MongoCollection::count(const bson::BsonDocument& filter_bson, + int64_t limit, + std::function)> completion_block) +{ + count_bson(filter_bson, limit, [completion_block](util::Optional error, util::Optional value) { + if (error) { + return completion_block(0, error); + } + + return completion_block(static_cast(*value), util::none); + }); +} + +void MongoCollection::count(const bson::BsonDocument& filter_bson, + std::function)> completion_block) +{ + count(filter_bson, 0, completion_block); +} + +void MongoCollection::insert_many(bson::BsonArray documents, + std::function, util::Optional)> completion_block) +{ + insert_many_bson(documents, [completion_block](util::Optional error, util::Optional value) { + if (error) { + return completion_block({}, error); + } + + auto bson = static_cast(*value); + auto inserted_ids = static_cast(bson["insertedIds"]); + return completion_block(std::vector(inserted_ids.begin(), inserted_ids.end()), error); + }); +} + +void MongoCollection::delete_one(const bson::BsonDocument& filter_bson, + std::function)> completion_block) +{ + delete_one_bson(filter_bson, get_delete_count_handler(completion_block)); +} + +void MongoCollection::delete_many(const bson::BsonDocument& filter_bson, + std::function)> completion_block) +{ + delete_many_bson(filter_bson, get_delete_count_handler(completion_block)); +} + +void MongoCollection::update_one(const bson::BsonDocument& filter_bson, + const bson::BsonDocument& update_bson, + bool upsert, + std::function)> completion_block) +{ + update_one_bson(filter_bson, update_bson, upsert, get_update_handler(completion_block)); +} + +void MongoCollection::update_one(const bson::BsonDocument& filter_bson, + const bson::BsonDocument& update_bson, + std::function)> completion_block) +{ + update_one(filter_bson, update_bson, {}, completion_block); +} + +void MongoCollection::update_many(const bson::BsonDocument& filter_bson, + const bson::BsonDocument& update_bson, + bool upsert, + std::function)> completion_block) +{ + update_many_bson(filter_bson, update_bson, upsert, get_update_handler(completion_block)); +} + +void MongoCollection::update_many(const bson::BsonDocument& filter_bson, + const bson::BsonDocument& update_bson, + std::function)> completion_block) +{ + update_many(filter_bson, update_bson, {}, completion_block); +} + +void MongoCollection::find_one_and_update(const bson::BsonDocument& filter_bson, + const bson::BsonDocument& update_bson, + MongoCollection::FindOneAndModifyOptions options, + std::function, util::Optional)> completion_block) +{ + find_one_and_update_bson(filter_bson, update_bson, options, get_document_handler(completion_block)); +} + +void MongoCollection::find_one_and_update(const bson::BsonDocument& filter_bson, + const bson::BsonDocument& update_bson, + std::function, util::Optional)> completion_block) +{ + find_one_and_update(filter_bson, update_bson, {}, completion_block); +} + +void MongoCollection::find_one_and_replace(const bson::BsonDocument& filter_bson, + const bson::BsonDocument& replacement_bson, + MongoCollection::FindOneAndModifyOptions options, + std::function, util::Optional)> completion_block) +{ + find_one_and_replace_bson(filter_bson, replacement_bson, options, get_document_handler(completion_block)); +} + +void MongoCollection::find_one_and_replace(const bson::BsonDocument& filter_bson, + const bson::BsonDocument& replacement_bson, + std::function, util::Optional)> completion_block) +{ + find_one_and_replace(filter_bson, replacement_bson, {}, completion_block); +} + +void MongoCollection::find_one_and_delete(const bson::BsonDocument& filter_bson, + MongoCollection::FindOneAndModifyOptions options, + std::function, util::Optional)> completion_block) +{ + find_one_and_delete_bson(filter_bson, options, get_document_handler(completion_block)); +} + +void MongoCollection::find_one_and_delete(const bson::BsonDocument& filter_bson, + std::function, util::Optional)> completion_block) +{ + find_one_and_delete(filter_bson, {}, completion_block); +} + +void MongoCollection::find_bson(const bson::BsonDocument& filter_bson, + FindOptions options, + std::function, util::Optional)> completion_block) try +{ + auto base_args = m_base_operation_args; + base_args["query"] = filter_bson; + + if (options.limit) { + base_args["limit"] = *options.limit; + } + + if (options.projection_bson) { + base_args["project"] = *options.projection_bson; + } + + if (options.sort_bson) { + base_args["sort"] = *options.sort_bson; + } + + m_service->call_function(m_user, "find", + bson::BsonArray({ base_args }), + m_service_name, + completion_block); +} catch (const std::exception& e) { + return completion_block(AppError(make_error_code(JSONErrorCode::malformed_json), e.what()), util::none); +} + +void MongoCollection::find_one_bson(const bson::BsonDocument& filter_bson, + FindOptions options, + std::function, util::Optional)> completion_block) try +{ + auto base_args = m_base_operation_args; + base_args["query"] = filter_bson; + + if (options.limit) { + base_args["limit"] = *options.limit; + } + + if (options.projection_bson) { + base_args["project"] = *options.projection_bson; + } + + if (options.sort_bson) { + base_args["sort"] = *options.sort_bson; + } + + m_service->call_function(m_user, "findOne", + bson::BsonArray({ base_args }), + m_service_name, + completion_block); +} +catch (const std::exception& e) { + return completion_block(AppError(make_error_code(JSONErrorCode::malformed_json), e.what()), util::none); +} + +void MongoCollection::insert_one_bson(const bson::BsonDocument& value_bson, + std::function, util::Optional)> completion_block) +{ + auto base_args = m_base_operation_args; + base_args["document"] = value_bson; + + m_service->call_function(m_user, "insertOne", + bson::BsonArray({ base_args }), + m_service_name, + completion_block); +} + +void MongoCollection::aggregate_bson(const bson::BsonArray& pipline, + std::function, util::Optional)> completion_block) +{ + auto base_args = m_base_operation_args; + base_args["pipeline"] = pipline; + + m_service->call_function(m_user, "aggregate", + bson::BsonArray({ base_args }), + m_service_name, + completion_block); +} + +void MongoCollection::count_bson(const bson::BsonDocument& filter_bson, + int64_t limit, + std::function, util::Optional)> completion_block) +{ + auto base_args = m_base_operation_args; + base_args["query"] = filter_bson; + + if (limit != 0) { + base_args["limit"] = limit; + } + + m_service->call_function(m_user, "count", + bson::BsonArray({ base_args }), + m_service_name, + completion_block); +} + +void MongoCollection::insert_many_bson(bson::BsonArray documents, + std::function, util::Optional)> completion_block) +{ + auto base_args = m_base_operation_args; + base_args["documents"] = documents; + + m_service->call_function(m_user, "insertMany", + bson::BsonArray({ base_args }), + m_service_name, + completion_block); +} + +void MongoCollection::delete_one_bson(const bson::BsonDocument& filter_bson, + std::function, util::Optional)> completion_block) +{ + auto base_args = m_base_operation_args; + base_args["query"] = filter_bson; + + m_service->call_function(m_user, "deleteOne", + bson::BsonArray({ base_args }), + m_service_name, + completion_block); +} + +void MongoCollection::delete_many_bson(const bson::BsonDocument& filter_bson, + std::function, util::Optional)> completion_block) +{ + auto base_args = m_base_operation_args; + base_args["query"] = filter_bson; + + m_service->call_function(m_user, "deleteMany", + bson::BsonArray({ base_args }), + m_service_name, + completion_block); +} + +void MongoCollection::update_one_bson(const bson::BsonDocument& filter_bson, + const bson::BsonDocument& update_bson, + bool upsert, + std::function, util::Optional)> completion_block) +{ + auto base_args = m_base_operation_args; + base_args["query"] = filter_bson; + base_args["update"] = update_bson; + base_args["upsert"] = upsert; + + m_service->call_function(m_user, "updateOne", + bson::BsonArray({ base_args }), + m_service_name, + completion_block); +} + +void MongoCollection::update_many_bson(const bson::BsonDocument& filter_bson, + const bson::BsonDocument& update_bson, + bool upsert, + std::function, util::Optional)> completion_block) +{ + auto base_args = m_base_operation_args; + base_args["query"] = filter_bson; + base_args["update"] = update_bson; + base_args["upsert"] = upsert; + + m_service->call_function(m_user, "updateMany", + bson::BsonArray({ base_args }), + m_service_name, + completion_block); +} + +void MongoCollection::find_one_and_update_bson(const bson::BsonDocument& filter_bson, + const bson::BsonDocument& update_bson, + MongoCollection::FindOneAndModifyOptions options, + std::function, util::Optional)> completion_block) +{ + auto base_args = m_base_operation_args; + base_args["filter"] = filter_bson; + base_args["update"] = update_bson; + options.set_bson(base_args); + + m_service->call_function(m_user, "findOneAndUpdate", + bson::BsonArray({ base_args }), + m_service_name, + completion_block); +} + +void MongoCollection::find_one_and_replace_bson(const bson::BsonDocument& filter_bson, + const bson::BsonDocument& replacement_bson, + MongoCollection::FindOneAndModifyOptions options, + std::function, util::Optional)> completion_block) +{ + auto base_args = m_base_operation_args; + base_args["filter"] = filter_bson; + base_args["update"] = replacement_bson; + options.set_bson(base_args); + + m_service->call_function(m_user, "findOneAndReplace", + bson::BsonArray({ base_args }), + m_service_name, + completion_block); +} + +void MongoCollection::find_one_and_delete_bson(const bson::BsonDocument& filter_bson, + MongoCollection::FindOneAndModifyOptions options, + std::function, util::Optional)> completion_block) +{ + auto base_args = m_base_operation_args; + base_args["filter"] = filter_bson; + options.set_bson(base_args); + + m_service->call_function(m_user, "findOneAndDelete", + bson::BsonArray({ base_args }), + m_service_name, + completion_block); +} + +void WatchStream::feed_buffer(std::string_view input) { + REALM_ASSERT(m_state == NEED_DATA); + m_buffer += input; + advance_buffer_state(); +} + +void WatchStream::advance_buffer_state() { + REALM_ASSERT(m_state == NEED_DATA); + while (m_state == NEED_DATA) { + if (m_buffer_offset == m_buffer.size()) { + m_buffer.clear(); + m_buffer_offset = 0; + return; + } + + // NOTE not supporting CR-only newlines, just LF and CRLF. + auto next_newline = m_buffer.find('\n', m_buffer_offset); + if (next_newline == std::string::npos) { + // We have a partial line. + if (m_buffer_offset != 0) { + // Slide the partial line down to the front of the buffer. + m_buffer.assign(m_buffer.data() + m_buffer_offset, m_buffer.size() - m_buffer_offset); + m_buffer_offset = 0; + } + return; + } + + feed_line(std::string_view(m_buffer.data() + m_buffer_offset, next_newline - m_buffer_offset)); + m_buffer_offset = next_newline + 1; // Advance past this line, including its newline. + } +} + +void WatchStream::feed_line(std::string_view line) { + REALM_ASSERT(m_state == NEED_DATA); + // This is an implementation of the algorithm described at + // https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation. + // Currently the server does not use id or retry lines, so that processing isn't implemented. + + // ignore trailing LF if not removed by SDK. + if (!line.empty() && line.back() == '\n') + line = line.substr(0, line.size() - 1); + + // ignore trailing CR from CRLF + if (!line.empty() && line.back() == '\r') + line = line.substr(0, line.size() - 1); + + if (line.empty()) { + // This is the "dispatch the event" portion of the algorithm. + if (m_data_buffer.empty()) { + m_event_type.clear(); + return; + } + + if (m_data_buffer.back() == '\n') + m_data_buffer.pop_back(); + + feed_sse({m_data_buffer, m_event_type}); + m_data_buffer.clear(); + m_event_type.clear(); + } + + if (line[0] == ':') + return; + + const auto colon = line.find(':'); + const auto field = line.substr(0, colon); + auto value = colon == std::string::npos ? std::string_view() : line.substr(colon + 1); + if (!value.empty() && value[0] == ' ') + value = value.substr(1); + + if (field == "event") { + m_event_type = value; + } else if (field == "data") { + m_data_buffer += value; + m_data_buffer += '\n'; + } else { + // line is ignored (even if field is id or retry). + } +} + +void WatchStream::feed_sse(ServerSentEvent sse) { + REALM_ASSERT(m_state == NEED_DATA); + std::string buffer; // must outlast if-block since we bind sse.data to it. + size_t first_percent = sse.data.find('%'); + if (first_percent != std::string::npos) { + // For some reason, the stich server decided to add percent-encoding for '%', '\n', and '\r' to its + // event-stream replies. But it isn't real urlencoding, since most characters pass through, so we can't use + // uri_percent_decode() here. + buffer.reserve(sse.data.size()); + size_t start = 0; + while (true) { + auto percent = start == 0 ? first_percent : sse.data.find('%', start); + if (percent == std::string::npos) { + buffer += sse.data.substr(start); + break; + } + + buffer += sse.data.substr(start, percent - start); + + auto encoded = sse.data.substr(percent, 3); // may be smaller than 3 if string ends with % + if (encoded == "%25") { + buffer += '%'; + } else if (encoded == "%0A") { + buffer += '\x0A'; // '\n' + } else if (encoded == "%0D") { + buffer += '\x0D'; // '\r' + } else { + buffer += encoded; // propagate as-is + } + start = percent + encoded.size(); + } + + sse.data = buffer; + } + + if (sse.eventType.empty() || sse.eventType == "message") { + try { + auto parsed = bson::parse(sse.data); + if (parsed.type() == bson::Bson::Type::Document) { + m_next_event = parsed.operator const bson::BsonDocument&(); + m_state = HAVE_EVENT; + return; + } + } catch (...) { + // fallthrough to same handling as for non-document value. + } + m_state = HAVE_ERROR; + m_error.emplace(app::make_error_code(JSONErrorCode::bad_bson_parse), + "server returned malformed event: " + std::string(sse.data)); + } else if (sse.eventType == "error") { + m_state = HAVE_ERROR; + + // default error message if we have issues parsing the reply. + m_error.emplace(app::make_error_code(ServiceErrorCode::unknown), std::string(sse.data)); + try { + auto parsed = bson::parse(sse.data); + if (parsed.type() != bson::Bson::Type::Document) return; + auto& obj = parsed.operator const bson::BsonDocument&(); + auto& code = obj.at("error_code"); + auto& msg = obj.at("error"); + if (code.type() != bson::Bson::Type::String) return; + if (msg.type() != bson::Bson::Type::String) return; + m_error.emplace(app::make_error_code(app::service_error_code_from_string( + code.operator const std::string&())), + msg.operator const std::string&()); + } catch(...) { + return; // Use the default state. + } + } else { + // Ignore other event types + } +} +} // namespace app +} // namespace realm diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/remote_mongo_database.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/remote_mongo_database.cpp new file mode 100644 index 0000000..bc3c42d --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/remote_mongo_database.cpp @@ -0,0 +1,35 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 utilied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#include "sync/remote_mongo_database.hpp" +#include "sync/remote_mongo_collection.hpp" + +namespace realm { +namespace app { + +MongoCollection MongoDatabase::collection(const std::string& collection_name) +{ + return MongoCollection(collection_name, m_name, m_user, m_service, m_service_name); +} + +MongoCollection MongoDatabase::operator[](const std::string& collection_name) +{ + return MongoCollection(collection_name, m_name, m_user, m_service, m_service_name); +} +} +} diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/sync_manager.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/sync_manager.cpp new file mode 100644 index 0000000..bf90e5e --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/sync_manager.cpp @@ -0,0 +1,645 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// 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 "sync/sync_manager.hpp" + +#include "sync/impl/sync_client.hpp" +#include "sync/impl/sync_file.hpp" +#include "sync/impl/sync_metadata.hpp" +#include "sync/sync_session.hpp" +#include "sync/sync_user.hpp" +#include "sync/app.hpp" +#include "util/uuid.hpp" + +#include +#include + +using namespace realm; +using namespace realm::_impl; + +void SyncManager::configure(std::shared_ptr app, + const std::string& sync_route, + const SyncClientConfig& config) +{ + m_app = app; + m_sync_route = sync_route; + { + std::lock_guard lock(m_mutex); + m_config = std::move(config); + if (m_sync_client) + return; + } + + struct UserCreationData { + std::string identity; + std::string refresh_token; + std::string access_token; + std::string provider_type; + std::vector identities; + SyncUser::State state; + std::string device_id; + }; + + std::vector users_to_add; + { + std::lock_guard lock(m_file_system_mutex); + + // Set up the file manager. + if (m_file_manager) { + // Changing the base path for tests requires calling reset_for_testing() + // first, and otherwise isn't supported + REALM_ASSERT(m_file_manager->base_path() == m_config.base_file_path); + } else { + m_file_manager = std::make_unique(m_config.base_file_path, app->config().app_id); + } + + // Set up the metadata manager, and perform initial loading/purging work. + if (m_metadata_manager || m_config.metadata_mode == MetadataMode::NoMetadata) { + // No metadata means we use a new client uuid each time + if (!m_metadata_manager) + m_client_uuid = util::uuid_string(); + return; + } + + bool encrypt = m_config.metadata_mode == MetadataMode::Encryption; + try { + m_metadata_manager = std::make_unique(m_file_manager->metadata_path(), + encrypt, + m_config.custom_encryption_key); + } catch (RealmFileException const& ex) { + if (m_config.reset_metadata_on_error && m_file_manager->remove_metadata_realm()) { + m_metadata_manager = std::make_unique(m_file_manager->metadata_path(), + encrypt, + std::move(m_config.custom_encryption_key)); + } else { + throw; + } + } + + REALM_ASSERT(m_metadata_manager); + m_client_uuid = m_metadata_manager->client_uuid(); + + // Perform our "on next startup" actions such as deleting Realm files + // which we couldn't delete immediately due to them being in use + std::vector completed_actions; + SyncFileActionMetadataResults file_actions = m_metadata_manager->all_pending_actions(); + for (size_t i = 0; i < file_actions.size(); i++) { + auto file_action = file_actions.get(i); + if (run_file_action(file_action)) { + completed_actions.emplace_back(std::move(file_action)); + } + } + for (auto& action : completed_actions) { + action.remove(); + } + + // Load persisted users into the users map. + SyncUserMetadataResults users = m_metadata_manager->all_unmarked_users(); + for (size_t i = 0; i < users.size(); i++) { + auto user_data = users.get(i); + auto refresh_token = user_data.refresh_token(); + auto access_token = user_data.access_token(); + auto device_id = user_data.device_id(); + if (!refresh_token.empty() && !access_token.empty()) { + users_to_add.push_back(UserCreationData{ + user_data.identity(), + std::move(refresh_token), + std::move(access_token), + user_data.provider_type(), + user_data.identities(), + user_data.state(), + device_id + }); + } + } + + // Delete any users marked for death. + std::vector dead_users; + SyncUserMetadataResults users_to_remove = m_metadata_manager->all_users_marked_for_removal(); + dead_users.reserve(users_to_remove.size()); + for (size_t i = 0; i < users_to_remove.size(); i++) { + auto user = users_to_remove.get(i); + // FIXME: delete user data in a different way? (This deletes a logged-out user's data as soon as the app + // launches again, which might not be how some apps want to treat their data.) + try { + m_file_manager->remove_user_directory(user.identity()); + dead_users.emplace_back(std::move(user)); + } catch (util::File::AccessError const&) { + continue; + } + } + for (auto& user : dead_users) { + user.remove(); + } + } + { + std::lock_guard lock(m_user_mutex); + for (auto& user_data : users_to_add) { + auto& identity = user_data.identity; + auto& provider_type = user_data.provider_type; + auto user = std::make_shared(user_data.refresh_token, + identity, + provider_type, + user_data.access_token, + user_data.state, + user_data.device_id, + shared_from_this()); + user->update_identities(user_data.identities); + m_users.emplace_back(std::move(user)); + } + } +} + +bool SyncManager::immediately_run_file_actions(const std::string& realm_path) +{ + if (!m_metadata_manager) { + return false; + } + if (auto metadata = m_metadata_manager->get_file_action_metadata(realm_path)) { + if (run_file_action(*metadata)) { + metadata->remove(); + return true; + } + } + return false; +} + +// Perform a file action. Returns whether or not the file action can be removed. +bool SyncManager::run_file_action(const SyncFileActionMetadata& md) +{ + switch (md.action()) { + case SyncFileActionMetadata::Action::DeleteRealm: + // Delete all the files for the given Realm. + m_file_manager->remove_realm(md.original_name()); + return true; + case SyncFileActionMetadata::Action::BackUpThenDeleteRealm: + // Copy the primary Realm file to the recovery dir, and then delete the Realm. + auto new_name = md.new_name(); + auto original_name = md.original_name(); + if (!util::File::exists(original_name)) { + // The Realm file doesn't exist anymore. + return true; + } + if (new_name && !util::File::exists(*new_name) && m_file_manager->copy_realm_file(original_name, *new_name)) { + // We successfully copied the Realm file to the recovery directory. + m_file_manager->remove_realm(original_name); + return true; + } + return false; + } + return false; +} + +void SyncManager::reset_for_testing() +{ + std::lock_guard lock(m_file_system_mutex); + if (m_file_manager) + util::try_remove_dir_recursive(m_file_manager->base_path()); + m_file_manager = nullptr; + m_metadata_manager = nullptr; + m_client_uuid = util::none; + + { + // Destroy all the users. + std::lock_guard lock(m_user_mutex); + m_users.clear(); + m_current_user = nullptr; + } + { + std::lock_guard lock(m_mutex); + + // Stop the client. This will abort any uploads that inactive sessions are waiting for. + if (m_sync_client) + m_sync_client->stop(); + + { + std::lock_guard lock(m_session_mutex); + // Callers of `SyncManager::reset_for_testing` should ensure there are no existing sessions + // prior to calling `reset_for_testing`. + bool no_sessions = !do_has_existing_sessions(); + REALM_ASSERT_RELEASE(no_sessions); + + // Destroy any inactive sessions. + // FIXME: We shouldn't have any inactive sessions at this point! Sessions are expected to + // remain inactive until their final upload completes, at which point they are unregistered + // and destroyed. Our call to `sync::Client::stop` above aborts all uploads, so all sessions + // should have already been destroyed. + m_sessions.clear(); + } + + // Destroy the client now that we have no remaining sessions. + m_sync_client = nullptr; + + // Reset even more state. + m_config = {}; + + m_sync_route = ""; + } +} + +void SyncManager::set_log_level(util::Logger::Level level) noexcept +{ + std::lock_guard lock(m_mutex); + m_config.log_level = level; +} + +void SyncManager::set_logger_factory(SyncLoggerFactory& factory) noexcept +{ + std::lock_guard lock(m_mutex); + m_config.logger_factory = &factory; +} + +std::unique_ptr SyncManager::make_logger() const +{ + if (m_config.logger_factory) { + return m_config.logger_factory->make_logger(m_config.log_level); // Throws + } + + auto stderr_logger = std::make_unique(); // Throws + stderr_logger->set_level_threshold(m_config.log_level); + return std::unique_ptr(stderr_logger.release()); +} + +void SyncManager::set_user_agent(std::string user_agent) +{ + std::lock_guard lock(m_mutex); + m_config.user_agent_application_info = std::move(user_agent); +} + +void SyncManager::set_timeouts(SyncClientTimeouts timeouts) +{ + std::lock_guard lock(m_mutex); + m_config.timeouts = timeouts; +} + +void SyncManager::reconnect() const +{ + std::lock_guard lock(m_session_mutex); + for (auto& it : m_sessions) { + it.second->handle_reconnect(); + } +} + +util::Logger::Level SyncManager::log_level() const noexcept +{ + std::lock_guard lock(m_mutex); + return m_config.log_level; +} + +bool SyncManager::perform_metadata_update(std::function update_function) const +{ + std::lock_guard lock(m_file_system_mutex); + if (!m_metadata_manager) { + return false; + } + update_function(*m_metadata_manager); + return true; +} + +std::shared_ptr SyncManager::get_user(const std::string& user_id, + std::string refresh_token, + std::string access_token, + const std::string provider_type, + std::string device_id) +{ + std::lock_guard lock(m_user_mutex); + auto it = std::find_if(m_users.begin(), + m_users.end(), + [user_id, provider_type](const auto& user) { + return user->identity() == user_id && user->provider_type() == provider_type; + }); + if (it == m_users.end()) { + // No existing user. + auto new_user = std::make_shared(std::move(refresh_token), + user_id, + provider_type, + std::move(access_token), + SyncUser::State::LoggedIn, + device_id, + shared_from_this()); + m_users.emplace(m_users.begin(), new_user); + if (!m_metadata_manager) + m_current_user = new_user; + return new_user; + } else { + auto user = *it; + if (user->state() == SyncUser::State::Removed) { + return nullptr; + } + + // It is important that the access token is set before the refresh token + // as once each token is set it attempts to revive any pending sessions + // (e.g. as user logs out and logs back in they would be using an empty access token with the sync client + // if the order of these were flipped). + user->update_access_token(std::move(access_token)); + user->update_refresh_token(std::move(refresh_token)); + + if (user->state() == SyncUser::State::LoggedOut) { + user->set_state(SyncUser::State::LoggedIn); + } + return user; + } +} + +std::vector> SyncManager::all_users() +{ + std::lock_guard lock(m_user_mutex); + m_users.erase(std::remove_if(m_users.begin(), m_users.end(), [](auto& user) { + return user->state() == SyncUser::State::Removed; + }), m_users.end()); + return m_users; +} + +std::shared_ptr SyncManager::get_user_for_identity(std::string const& identity) const noexcept +{ + auto is_active_user = [identity](auto& el) { + return el->identity() == identity; + }; + auto it = std::find_if(m_users.begin(), m_users.end(), is_active_user); + return it == m_users.end() ? nullptr : *it; +} + +std::shared_ptr SyncManager::get_current_user() const +{ + std::lock_guard lock(m_user_mutex); + + if (m_current_user) + return m_current_user; + if (!m_metadata_manager) + return nullptr; + + auto cur_user_ident = m_metadata_manager->get_current_user_identity(); + return cur_user_ident ? get_user_for_identity(*cur_user_ident) : nullptr; +} + +void SyncManager::log_out_user(const std::string& user_id) +{ + std::lock_guard lock(m_user_mutex); + + // Move this user to the end of the vector + if (m_users.size() > 1) { + auto it = std::find_if(m_users.begin(), + m_users.end(), + [user_id](const auto& user) { + return user->identity() == user_id; + }); + + if (it != m_users.end()) + std::rotate(it, it + 1, m_users.end()); + } + + bool was_active = (m_current_user && m_current_user->identity() == user_id) + || (m_metadata_manager && m_metadata_manager->get_current_user_identity() == user_id); + if (!was_active) + return; + + // Set the current active user to the next logged in user, or null if none + for (auto& user : m_users) { + if (user->state() == SyncUser::State::LoggedIn) { + if (m_metadata_manager) + m_metadata_manager->set_current_user_identity(user->identity()); + m_current_user = user; + return; + } + } + + if (m_metadata_manager) + m_metadata_manager->set_current_user_identity(""); + m_current_user = nullptr; +} + +void SyncManager::set_current_user(const std::string& user_id) +{ + std::lock_guard lock(m_user_mutex); + + m_current_user = get_user_for_identity(user_id); + if (m_metadata_manager) + m_metadata_manager->set_current_user_identity(user_id); +} + +void SyncManager::remove_user(const std::string& user_id) +{ + std::lock_guard lock(m_user_mutex); + auto user = get_user_for_identity(user_id); + if (!user) + return; + user->set_state(SyncUser::State::Removed); + + if (!m_metadata_manager) + return; + + for (size_t i = 0; i < m_metadata_manager->all_unmarked_users().size(); i++) { + auto metadata = m_metadata_manager->all_unmarked_users().get(i); + if (user->identity() == metadata.identity()) { + metadata.mark_for_removal(); + } + } +} + +std::shared_ptr SyncManager::get_existing_logged_in_user(const std::string& user_id) const +{ + std::lock_guard lock(m_user_mutex); + auto user = get_user_for_identity(user_id); + return user && user->state() == SyncUser::State::LoggedIn ? user : nullptr; +} + +struct UnsupportedBsonPartition : public std::logic_error { + UnsupportedBsonPartition(std::string msg) : std::logic_error(msg) {} +}; + +static std::string string_from_partition(const std::string& partition) +{ + try { + bson::Bson partition_value = bson::parse(partition); + switch (partition_value.type()) { + case bson::Bson::Type::Int32: + return util::format("i_%1", static_cast(partition_value)); + case bson::Bson::Type::Int64: + return util::format("l_%1", static_cast(partition_value)); + case bson::Bson::Type::String: + return util::format("s_%1", static_cast(partition_value)); + case bson::Bson::Type::ObjectId: + return util::format("o_%1", static_cast(partition_value).to_string()); + case bson::Bson::Type::Null: + return "null"; + default: + throw UnsupportedBsonPartition(util::format("Unsupported partition key value: '%1'. Only int, string and ObjectId types are currently supported.", partition_value.to_string())); + } + } + catch (const UnsupportedBsonPartition&) { + throw; + } + catch (...) { + // FIXME: the partition wasn't a bson formatted string, this can happen when using the + // test sync server which only accepts filesystem type paths, in this case return the raw partition. + // Once we migrate away from using the sync server in tests, this code path should not be necessary. + return partition; + } +} + +std::string SyncManager::path_for_realm(const SyncUser& user, const std::string& realm_file_name) const +{ + std::lock_guard lock(m_file_system_mutex); + REALM_ASSERT(m_file_manager); + return m_file_manager->realm_file_path(user.identity(), user.local_identity(), realm_file_name); +} + +std::string SyncManager::path_for_realm(const SyncConfig& config, util::Optional custom_file_name) const +{ + std::lock_guard lock(m_file_system_mutex); + REALM_ASSERT(m_file_manager); + REALM_ASSERT(config.user); + + // We used to hash the string value of the partition. For compatibility, check that SHA256 + // hash file name exists, and if it does, continue to use it. + std::array hash; + util::sha256(config.partition_value.data(), config.partition_value.size(), hash.data()); + std::string legacy_hashed_file_name = util::hex_dump(hash.data(), hash.size(), ""); + std::string legacy_file_path = m_file_manager->realm_file_path(config.user->identity(), config.user->local_identity(), legacy_hashed_file_name); + if (m_file_manager->try_file_exists(legacy_hashed_file_name)) { + return legacy_file_path; + } + + // Attempt to make a nicer filename which will ease debugging when + // locating files in the filesystem. + std::string file_name = (custom_file_name) ? custom_file_name.value() : string_from_partition(config.partition_value); + return m_file_manager->realm_file_path(config.user->identity(), config.user->local_identity(), file_name); +} + +std::string SyncManager::recovery_directory_path(util::Optional const& custom_dir_name) const +{ + std::lock_guard lock(m_file_system_mutex); + REALM_ASSERT(m_file_manager); + return m_file_manager->recovery_directory_path(custom_dir_name); +} + +std::shared_ptr SyncManager::get_existing_active_session(const std::string& path) const +{ + std::lock_guard lock(m_session_mutex); + if (auto session = get_existing_session_locked(path)) { + if (auto external_reference = session->existing_external_reference()) + return external_reference; + } + return nullptr; +} + +std::shared_ptr SyncManager::get_existing_session_locked(const std::string& path) const +{ + REALM_ASSERT(!m_session_mutex.try_lock()); + auto it = m_sessions.find(path); + return it == m_sessions.end() ? nullptr : it->second; +} + +std::shared_ptr SyncManager::get_existing_session(const std::string& path) const +{ + std::lock_guard lock(m_session_mutex); + if (auto session = get_existing_session_locked(path)) + return session->external_reference(); + + return nullptr; +} + +std::shared_ptr SyncManager::get_session(const std::string& path, const SyncConfig& sync_config, bool force_client_resync) +{ + auto& client = get_sync_client(); // Throws + + std::lock_guard lock(m_session_mutex); + if (auto session = get_existing_session_locked(path)) { + sync_config.user->register_session(session); + return session->external_reference(); + } + + auto shared_session = SyncSession::create(client, path, sync_config, force_client_resync); + m_sessions[path] = shared_session; + + // Create the external reference immediately to ensure that the session will become + // inactive if an exception is thrown in the following code. + auto external_reference = shared_session->external_reference(); + + sync_config.user->register_session(std::move(shared_session)); + + return external_reference; +} + + +bool SyncManager::has_existing_sessions() +{ + std::lock_guard lock(m_session_mutex); + return do_has_existing_sessions(); +} + +bool SyncManager::do_has_existing_sessions(){ + return std::any_of(m_sessions.begin(), m_sessions.end(), [](auto& element){ + return element.second->existing_external_reference(); + }); +} + +void SyncManager::unregister_session(const std::string& path) +{ + std::lock_guard lock(m_session_mutex); + auto it = m_sessions.find(path); + REALM_ASSERT(it != m_sessions.end()); + + // If the session has an active external reference, leave it be. This will happen if the session + // moves to an inactive state while still externally reference, for instance, as a result of + // the session's user being logged out. + if (it->second->existing_external_reference()) + return; + + m_sessions.erase(path); +} + +void SyncManager::enable_session_multiplexing() +{ + std::lock_guard lock(m_mutex); + if (m_config.multiplex_sessions) + return; // Already enabled, we can ignore + + if (m_sync_client) + throw std::logic_error("Cannot enable session multiplexing after creating the sync client"); + + m_config.multiplex_sessions = true; +} + +SyncClient& SyncManager::get_sync_client() const +{ + std::lock_guard lock(m_mutex); + if (!m_sync_client) + m_sync_client = create_sync_client(); // Throws + return *m_sync_client; +} + +std::unique_ptr SyncManager::create_sync_client() const +{ + REALM_ASSERT(!m_mutex.try_lock()); + return std::make_unique(make_logger(), m_config, shared_from_this()); +} + +std::string SyncManager::client_uuid() const +{ + REALM_ASSERT(m_client_uuid); + return *m_client_uuid; +} + +util::Optional SyncManager::app_metadata() const +{ + if (!m_metadata_manager) { + return util::none; + } + return m_metadata_manager->get_app_metadata(); +} diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/sync_session.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/sync_session.cpp new file mode 100644 index 0000000..bdfd820 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/sync_session.cpp @@ -0,0 +1,1031 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// 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 "sync/sync_session.hpp" + +#include "sync/impl/sync_client.hpp" +#include "sync/impl/sync_file.hpp" +#include "sync/impl/sync_metadata.hpp" +#include "sync/sync_manager.hpp" +#include "sync/sync_user.hpp" +#include "sync/app.hpp" + +#include +#include +#include + +#include "impl/realm_coordinator.hpp" + +using namespace realm; +using namespace realm::_impl; +using namespace realm::_impl::sync_session_states; + +using SessionWaiterPointer = void(sync::Session::*)(std::function); + +constexpr const char SyncError::c_original_file_path_key[]; +constexpr const char SyncError::c_recovery_file_path_key[]; + +/// A state which a `SyncSession` can currently be within. State classes handle various actions +/// and state transitions. +/// +/// STATES: +/// +/// ACTIVE: the session is connected to the Sync Server and is actively +/// transferring data. +/// From: INACTIVE, DYING +/// To: +/// * INACTIVE: if asked to log out, or if asked to close and the stop policy +/// is Immediate. +/// * DYING: if asked to close and the stop policy is AfterChangesUploaded +/// +/// DYING: the session is performing clean-up work in preparation to be destroyed. +/// From: ACTIVE +/// To: +/// * INACTIVE: when the clean-up work completes, if the session wasn't +/// revived, or if explicitly asked to log out before the +/// clean-up work begins +/// * ACTIVE: if the session is revived +/// +/// INACTIVE: the user owning this session has logged out, the `sync::Session` +/// owned by this session is destroyed, and the session is quiescent. +/// Note that a session briefly enters this state before being destroyed, but +/// it can also enter this state and stay there if the user has been logged out. +/// From: initial, ACTIVE, DYING +/// To: +/// * ACTIVE: if the session is revived +/// +struct SyncSession::State { + virtual ~State() { } + + // Move the given session into this state. All state transitions MUST be carried out through this method. + virtual void enter_state(std::unique_lock&, SyncSession&) const { } + + virtual void nonsync_transact_notify(std::unique_lock&, SyncSession&, sync::version_type) const { } + + // Perform any work needed to reactivate a session that is not already active. + // Returns true iff the session should ask the binding to get a token for `bind()`. + virtual bool revive_if_needed(std::unique_lock&, SyncSession&) const { return false; } + + // Perform any work needed to respond to the application regaining network connectivity. + virtual void handle_reconnect(std::unique_lock&, SyncSession&) const { }; + + // The user that owns this session has been logged out, and the session should take appropriate action. + virtual void log_out(std::unique_lock&, SyncSession&) const { } + + // The session should be closed and moved to `inactive`, in accordance with its stop policy and other state. + virtual void close(std::unique_lock&, SyncSession&) const { } + + // If the error is fatal advance the state to inactive. + virtual void handle_error(std::unique_lock&, SyncSession&, const SyncError&) const { } + + // Transition immediately to `inactive` state. Calling this function must gurantee that any + // sync::Session object in SyncSession::m_session that existed prior to the time of invocation + // must have been destroyed upon return. This allows the caller to follow up with a call to + // sync::Client::wait_for_session_terminations_or_client_stopped() in order to wait for the + // Realm file to be closed. This works so long as this SyncSession object remains in the + // `inactive` state after the invocation of shutdown_and_wait(). + virtual void shutdown_and_wait(std::unique_lock&, SyncSession&) const { } + + static const State& active; + static const State& dying; + static const State& inactive; +}; + +struct sync_session_states::Active : public SyncSession::State { + //msvc needs this to initialize the class correctly + constexpr Active() {}; + + void enter_state(std::unique_lock& lock, SyncSession& session) const override + { + // when entering from the Dying state the session will still be bound + if (!session.m_session) { + session.create_sync_session(); + session.m_session->bind(); + } + + // Register all the pending wait-for-completion blocks. This can + // potentially add a redundant callback if we're coming from the Dying + // state, but that's okay (we won't call the user callbacks twice). + SyncSession::CompletionCallbacks callbacks_to_register; + std::swap(session.m_completion_callbacks, callbacks_to_register); + + for (auto& [id, callback_tuple] : callbacks_to_register) { + session.add_completion_callback(lock, std::move(callback_tuple.second), callback_tuple.first); + } + } + + void log_out(std::unique_lock& lock, SyncSession& session) const override + { + session.advance_state(lock, inactive); + } + + void nonsync_transact_notify(std::unique_lock&, SyncSession& session, + sync::version_type version) const override + { + // Fully ready sync session, notify immediately. + session.m_session->nonsync_transact_notify(version); + } + + void close(std::unique_lock& lock, SyncSession& session) const override + { + switch (session.m_config.stop_policy) { + case SyncSessionStopPolicy::Immediately: + session.advance_state(lock, inactive); + break; + case SyncSessionStopPolicy::LiveIndefinitely: + // Don't do anything; session lives forever. + break; + case SyncSessionStopPolicy::AfterChangesUploaded: + // Wait for all pending changes to upload. + session.advance_state(lock, dying); + break; + } + } + + void shutdown_and_wait(std::unique_lock& lock, SyncSession& session) const override + { + session.advance_state(lock, inactive); + } + + void handle_reconnect(std::unique_lock&, SyncSession& session) const override + { + session.m_session->cancel_reconnect_delay(); + } +}; + +struct sync_session_states::Dying : public SyncSession::State { + //msvc needs this to initialize the class correctly + constexpr Dying() {}; + + void enter_state(std::unique_lock& lock, SyncSession& session) const override + { + // If we have no session, we cannot possibly upload anything. + if (!session.m_session) { + session.advance_state(lock, inactive); + return; + } + + size_t current_death_count = ++session.m_death_count; + auto weak_session = session.weak_from_this(); + session.m_session->async_wait_for_upload_completion([weak_session, current_death_count](std::error_code) { + if (auto session = weak_session.lock()) { + std::unique_lock lock(session->m_state_mutex); + if (session->m_state == &State::dying && session->m_death_count == current_death_count) { + session->advance_state(lock, inactive); + } + } + }); + } + + void handle_error(std::unique_lock& lock, SyncSession& session, const SyncError& error) const override + { + if (error.is_fatal) { + session.advance_state(lock, inactive); + } + } + + bool revive_if_needed(std::unique_lock& lock, SyncSession& session) const override + { + // Revive. + session.advance_state(lock, active); + return false; + } + + void log_out(std::unique_lock& lock, SyncSession& session) const override + { + session.advance_state(lock, inactive); + } + + void shutdown_and_wait(std::unique_lock& lock, SyncSession& session) const override + { + session.advance_state(lock, inactive); + } +}; + +struct sync_session_states::Inactive : public SyncSession::State { + //msvc needs this to initialize the class correctly + constexpr Inactive() {}; + + void enter_state(std::unique_lock& lock, SyncSession& session) const override + { + // Manually set the disconnected state. Sync would also do this, but + // since the underlying SyncSession object already have been destroyed, + // we are not able to get the callback. + auto old_state = session.m_connection_state; + auto new_state = session.m_connection_state = SyncSession::ConnectionState::Disconnected; + + SyncSession::CompletionCallbacks waits; + std::swap(waits, session.m_completion_callbacks); + + session.m_session = nullptr; + session.unregister(lock); // releases lock + + // Send notifications after releasing the lock to prevent deadlocks in the callback. + if (old_state != new_state) { + session.m_connection_change_notifier.invoke_callbacks(old_state, session.connection_state()); + } + + // Inform any queued-up completion handlers that they were cancelled. + for (auto& [id, callback] : waits) + callback.second(make_error_code(util::error::operation_aborted)); + } + + bool revive_if_needed(std::unique_lock& lock, SyncSession& session) const override + { + session.advance_state(lock, active); + return true; + } + + void close(std::unique_lock& lock, SyncSession& session) const override + { + session.unregister(lock); // releases lock + } +}; + +const SyncSession::State& SyncSession::State::active = Active(); +const SyncSession::State& SyncSession::State::dying = Dying(); +const SyncSession::State& SyncSession::State::inactive = Inactive(); + +std::function)> SyncSession::handle_refresh(std::shared_ptr session) { + return [session](util::Optional error) { + using namespace std::chrono; + + auto session_user = session->user(); + auto is_user_expired = session_user && + session_user->refresh_jwt().expires_at < duration_cast(system_clock::now().time_since_epoch()).count(); + + if (!session_user) { + std::unique_lock lock(session->m_state_mutex); + session->cancel_pending_waits(lock, error ? error->error_code : std::error_code()); + } else if (is_user_expired) { + std::unique_lock lock(session->m_state_mutex); + session->cancel_pending_waits(lock, error ? error->error_code : std::error_code()); + if (session->m_config.error_handler) { + session->m_config.error_handler(session, + SyncError(SyncError::ProtocolError::bad_authentication, "expired refresh token", true)); + } + } else if (error) { + // 10 seconds is arbitrary, but it is to not swamp the server + std::this_thread::sleep_for(milliseconds(10000)); + if (session_user) { + session_user->refresh_custom_data(handle_refresh(session)); + } + } else { + if (!session->m_session) { + std::unique_lock lock(session->m_state_mutex); + session->advance_state(lock, State::active); + } else { + session->m_session->refresh(session_user->access_token()); + } + } + }; +} + +SyncSession::SyncSession(SyncClient& client, std::string realm_path, SyncConfig config, bool force_client_resync) +: m_state(&State::inactive) +, m_config(std::move(config)) +, m_force_client_resync(force_client_resync) +, m_realm_path(std::move(realm_path)) +, m_client(client) +{ +} + +std::string SyncSession::get_recovery_file_path() +{ + return util::reserve_unique_file_name(m_config.user->sync_manager()->recovery_directory_path(m_config.recovery_directory), + util::create_timestamped_template("recovered_realm")); +} + +void SyncSession::update_error_and_mark_file_for_deletion(SyncError& error, ShouldBackup should_backup) +{ + // Add a SyncFileActionMetadata marking the Realm as needing to be deleted. + std::string recovery_path; + auto original_path = path(); + error.user_info[SyncError::c_original_file_path_key] = original_path; + if (should_backup == ShouldBackup::yes) { + recovery_path = get_recovery_file_path(); + error.user_info[SyncError::c_recovery_file_path_key] = recovery_path; + } + using Action = SyncFileActionMetadata::Action; + auto action = should_backup == ShouldBackup::yes ? Action::BackUpThenDeleteRealm : Action::DeleteRealm; + m_config.user->sync_manager()->perform_metadata_update([this, action, + original_path=std::move(original_path), + recovery_path=std::move(recovery_path)](const auto& manager) { + std::string partition_value = m_config.partition_value; + manager.make_file_action_metadata(original_path, + partition_value, + m_config.user->identity(), + action, + recovery_path); + }); +} + +// This method should only be called from within the error handler callback registered upon the underlying `m_session`. +void SyncSession::handle_error(SyncError error) +{ + enum class NextStateAfterError { none, inactive, error }; + auto next_state = error.is_fatal ? NextStateAfterError::error : NextStateAfterError::none; + auto error_code = error.error_code; + + { + // See if the current state wishes to take responsibility for handling the error. + std::unique_lock lock(m_state_mutex); + m_state->handle_error(lock, *this, error); + } + + if (error.is_client_reset_requested()) { + switch (m_config.client_resync_mode) { + case ClientResyncMode::Manual: + break; + case ClientResyncMode::DiscardLocal: + case ClientResyncMode::Recover: { + // Performing a client resync requires tearing down our current + // sync session and creating a new one with a forced client + // reset. This will result in session completion handlers firing + // when the old session is torn down, which we don't want as this + // is supposed to be transparent to the user. + // + // To avoid this, we need to move the completion handlers aside temporarily so + // that moving to the inactive state doesn't clear them - they will be re-registered + // when the session becomes active again. + { + std::unique_lock lock(m_state_mutex); + m_force_client_resync = true; + + CompletionCallbacks callbacks; + std::swap(m_completion_callbacks, callbacks); + advance_state(lock, State::inactive); + + // FIXME This should be done in a scope guard so that we always do this, even if advance_state + // throws. + std::swap(callbacks, m_completion_callbacks); + } + revive_if_needed(); + return; + } + } + } + + if (error_code.category() == realm::sync::protocol_error_category()) { + using ProtocolError = realm::sync::ProtocolError; + switch (static_cast(error_code.value())) { + // Connection level errors + case ProtocolError::connection_closed: + case ProtocolError::other_error: + // Not real errors, don't need to be reported to the binding. + return; + case ProtocolError::unknown_message: + case ProtocolError::bad_syntax: + case ProtocolError::limits_exceeded: + case ProtocolError::wrong_protocol_version: + case ProtocolError::bad_session_ident: + case ProtocolError::reuse_of_session_ident: + case ProtocolError::bound_in_other_session: + case ProtocolError::bad_message_order: + case ProtocolError::bad_client_version: + case ProtocolError::illegal_realm_path: + case ProtocolError::no_such_realm: + case ProtocolError::bad_changeset: + case ProtocolError::bad_changeset_header_syntax: + case ProtocolError::bad_changeset_size: + case ProtocolError::bad_changesets: + case ProtocolError::bad_decompression: + case ProtocolError::unsupported_session_feature: + case ProtocolError::transact_before_upload: + case ProtocolError::partial_sync_disabled: + case ProtocolError::user_mismatch: + case ProtocolError::too_many_sessions: + break; + // Session errors + case ProtocolError::session_closed: + case ProtocolError::other_session_error: + case ProtocolError::disabled_session: + // The binding doesn't need to be aware of these because they are strictly informational, and do not + // represent actual errors. + return; + case ProtocolError::token_expired: { + REALM_ASSERT_RELEASE(false); + } + case ProtocolError::bad_authentication: { + std::shared_ptr user_to_invalidate; + next_state = NextStateAfterError::none; + { + std::unique_lock lock(m_state_mutex); + user_to_invalidate = user(); + cancel_pending_waits(lock, error.error_code); + } + if (user_to_invalidate) + user_to_invalidate->invalidate(); + break; + } + case ProtocolError::permission_denied: { + next_state = NextStateAfterError::inactive; + update_error_and_mark_file_for_deletion(error, ShouldBackup::no); + break; + } + case ProtocolError::bad_client_file: + case ProtocolError::bad_client_file_ident: + case ProtocolError::bad_origin_file_ident: + case ProtocolError::bad_server_file_ident: + case ProtocolError::bad_server_version: + case ProtocolError::client_file_blacklisted: + case ProtocolError::diverging_histories: + case ProtocolError::server_file_deleted: + case ProtocolError::user_blacklisted: + case ProtocolError::client_file_expired: + case ProtocolError::invalid_schema_change: + next_state = NextStateAfterError::inactive; + update_error_and_mark_file_for_deletion(error, ShouldBackup::yes); + break; + } + } else if (error_code.category() == realm::sync::client_error_category()) { + using ClientError = realm::sync::Client::Error; + switch (static_cast(error_code.value())) { + case ClientError::connection_closed: + case ClientError::pong_timeout: + // Not real errors, don't need to be reported to the binding. + return; + case ClientError::bad_changeset: + case ClientError::bad_changeset_header_syntax: + case ClientError::bad_changeset_size: + case ClientError::bad_client_file_ident: + case ClientError::bad_client_file_ident_salt: + case ClientError::bad_client_version: + case ClientError::bad_compression: + case ClientError::bad_error_code: + case ClientError::bad_file_ident: + case ClientError::bad_message_order: + case ClientError::bad_origin_file_ident: + case ClientError::bad_progress: + case ClientError::bad_protocol_from_server: + case ClientError::bad_request_ident: + case ClientError::bad_server_version: + case ClientError::bad_session_ident: + case ClientError::bad_state_message: + case ClientError::bad_syntax: + case ClientError::bad_timestamp: + case ClientError::client_too_new_for_server: + case ClientError::client_too_old_for_server: + case ClientError::connect_timeout: + case ClientError::limits_exceeded: + case ClientError::protocol_mismatch: + case ClientError::ssl_server_cert_rejected: + case ClientError::missing_protocol_feature: + case ClientError::unknown_message: + case ClientError::http_tunnel_failed: + // Don't do anything special for these errors. + // Future functionality may require special-case handling for existing + // errors, or newly introduced error codes. + break; + } + } else { + switch (error_code.value()) { + // FIXME: We need to understand what errors can actually come from the server + // FIXME: and why the sync client is no longer parsing them correctly. */ + case 11: + user()->refresh_custom_data(handle_refresh(shared_from_this())); + return; + default: + // Unrecognized error code. + error.is_unrecognized_by_client = true; + } + } + + // Dont't bother invoking m_config.error_handler if the sync is inactive. + // It does not make sense to call the handler when the session is closed. + if (m_state == &State::inactive) { + return; + } + + switch (next_state) { + case NextStateAfterError::none: + if (m_config.cancel_waits_on_nonfatal_error) { + std::unique_lock lock(m_state_mutex); + cancel_pending_waits(lock, error.error_code); + } + break; + case NextStateAfterError::inactive: { + if (error.is_client_reset_requested()) { + std::unique_lock lock(m_state_mutex); + cancel_pending_waits(lock, error.error_code); + } + + { + std::unique_lock lock(m_state_mutex); + advance_state(lock, State::inactive); + } + break; + } + case NextStateAfterError::error: { + std::unique_lock lock(m_state_mutex); + cancel_pending_waits(lock, error.error_code); + break; + } + } + if (m_config.error_handler) { + m_config.error_handler(shared_from_this(), std::move(error)); + } +} + +void SyncSession::cancel_pending_waits(std::unique_lock& lock, std::error_code error) +{ + + CompletionCallbacks callbacks; + std::swap(callbacks, m_completion_callbacks); + lock.unlock(); + + // Inform any queued-up completion handlers that they were cancelled. + for (auto& [id, callback] : callbacks) + callback.second(error); +} + +void SyncSession::handle_progress_update(uint64_t downloaded, uint64_t downloadable, + uint64_t uploaded, uint64_t uploadable, + uint64_t download_version, uint64_t snapshot_version) +{ + m_progress_notifier.update(downloaded, downloadable, uploaded, uploadable, download_version, snapshot_version); +} + +void SyncSession::create_sync_session() +{ + if (m_session) + return; + + sync::Session::Config session_config; + session_config.signed_user_token = m_config.user->access_token(); + session_config.realm_identifier = m_config.partition_value; + session_config.changeset_cooker = m_config.transformer; + session_config.encryption_key = m_config.realm_encryption_key; + session_config.verify_servers_ssl_certificate = m_config.client_validate_ssl; + session_config.ssl_trust_certificate_path = m_config.ssl_trust_certificate_path; + session_config.ssl_verify_callback = m_config.ssl_verify_callback; + session_config.proxy_config = m_config.proxy_config; + session_config.multiplex_ident = m_multiplex_identity; + { + std::string sync_route = m_config.user->sync_manager()->sync_route(); + + if (!m_client.decompose_server_url(sync_route, + session_config.protocol_envelope, + session_config.server_address, + session_config.server_port, + session_config.service_identifier)) { + throw sync::BadServerUrl(); + } + // FIXME: Java needs the fully resolved URL for proxy support, but we also need it before + // the session is created. How to resolve this? + m_server_url = sync_route; + } + + if (m_config.authorization_header_name) { + session_config.authorization_header_name = *m_config.authorization_header_name; + } + session_config.custom_http_headers = m_config.custom_http_headers; + + if (m_force_client_resync) { + std::string metadata_dir = m_realm_path + ".resync"; + util::try_make_dir(metadata_dir); + + sync::Session::Config::ClientReset config; + config.metadata_dir = metadata_dir; + if (m_config.client_resync_mode != ClientResyncMode::Recover) + config.recover_local_changes = false; + session_config.client_reset_config = config; + } + + m_session = m_client.make_session(m_realm_path, std::move(session_config)); + + std::weak_ptr weak_self = shared_from_this(); + + // Configure the sync transaction callback. + auto wrapped_callback = [this, weak_self](VersionID old_version, VersionID new_version) { + if (auto self = weak_self.lock()) { + if (m_sync_transact_callback) { + m_sync_transact_callback(old_version, new_version); + } + } + }; + m_session->set_sync_transact_callback(std::move(wrapped_callback)); + + // Set up the wrapped progress handler callback + m_session->set_progress_handler([weak_self](uint_fast64_t downloaded, uint_fast64_t downloadable, + uint_fast64_t uploaded, uint_fast64_t uploadable, + uint_fast64_t progress_version, uint_fast64_t snapshot_version) { + if (auto self = weak_self.lock()) { + self->handle_progress_update(downloaded, downloadable, uploaded, + uploadable, progress_version, snapshot_version); + } + }); + + // Sets up the connection state listener. This callback is used for both reporting errors as well as changes to the + // connection state. + m_session->set_connection_state_change_listener([weak_self](sync::Session::ConnectionState state, + const sync::Session::ErrorInfo* error) { + // If the OS SyncSession object is destroyed, we ignore any events from the underlying Session as there is + // nothing useful we can do with them. + if (auto self = weak_self.lock()) { + std::unique_lock lock(self->m_state_mutex); + auto old_state = self->m_connection_state; + using cs = sync::Session::ConnectionState; + switch (state) { + case cs::disconnected: self->m_connection_state = ConnectionState::Disconnected; break; + case cs::connecting: self->m_connection_state = ConnectionState::Connecting; break; + case cs::connected: self->m_connection_state = ConnectionState::Connected; break; + default: REALM_UNREACHABLE(); + } + auto new_state = self->m_connection_state; + lock.unlock(); + self->m_connection_change_notifier.invoke_callbacks(old_state, new_state); + if (error) { + self->handle_error(SyncError{error->error_code, std::move(error->detailed_message), error->is_fatal}); + } + } + }); +} + +void SyncSession::set_sync_transact_callback(std::function callback) +{ + m_sync_transact_callback = std::move(callback); +} + +void SyncSession::advance_state(std::unique_lock& lock, const State& state) +{ + REALM_ASSERT(lock.owns_lock()); + REALM_ASSERT(&state != m_state); + m_state = &state; + m_state->enter_state(lock, *this); +} + +void SyncSession::nonsync_transact_notify(sync::version_type version) +{ + m_progress_notifier.set_local_version(version); + + std::unique_lock lock(m_state_mutex); + m_state->nonsync_transact_notify(lock, *this, version); +} + +void SyncSession::revive_if_needed() +{ + std::unique_lock lock(m_state_mutex); + m_state->revive_if_needed(lock, *this); +} + +void SyncSession::handle_reconnect() +{ + std::unique_lock lock(m_state_mutex); + m_state->handle_reconnect(lock, *this); +} + +void SyncSession::log_out() +{ + std::unique_lock lock(m_state_mutex); + m_state->log_out(lock, *this); +} + +void SyncSession::close() +{ + std::unique_lock lock(m_state_mutex); + m_state->close(lock, *this); +} + +void SyncSession::shutdown_and_wait() +{ + { + std::unique_lock lock(m_state_mutex); + m_state->shutdown_and_wait(lock, *this); + } + m_client.wait_for_session_terminations(); +} + +void SyncSession::unregister(std::unique_lock& lock) +{ + REALM_ASSERT(lock.owns_lock()); + REALM_ASSERT(m_state == &State::inactive); // Must stop an active session before unregistering. + + lock.unlock(); + m_config.user->sync_manager()->unregister_session(m_realm_path); +} + +void SyncSession::add_completion_callback(const std::unique_lock&, + std::function callback, + _impl::SyncProgressNotifier::NotifierType direction) +{ + bool is_download = (direction == _impl::SyncProgressNotifier::NotifierType::download); + + m_completion_request_counter++; + m_completion_callbacks.emplace_hint(m_completion_callbacks.end(), + m_completion_request_counter, + std::make_pair( + direction, + std::move(callback))); + // If the state is inactive then just store the callback and return. The callback will get + // re-registered with the underlying session if/when the session ever becomes active again. + if (get_public_state() == PublicState::Inactive) { + return; + } + + auto waiter = is_download ? &sync::Session::async_wait_for_download_completion + : &sync::Session::async_wait_for_upload_completion; + + (m_session.get()->*waiter)([weak_self = weak_from_this(), + id = m_completion_request_counter + ] (std::error_code ec) { + auto self = weak_self.lock(); + if (!self) + return; + std::unique_lock lock(self->m_state_mutex); + auto callback_node = self->m_completion_callbacks.extract(id); + lock.unlock(); + if (callback_node) + callback_node.mapped().second(ec); + }); +} + +void SyncSession::wait_for_upload_completion(std::function callback) +{ + std::unique_lock lock(m_state_mutex); + add_completion_callback(lock, std::move(callback), _impl::SyncProgressNotifier::NotifierType::upload); +} + +void SyncSession::wait_for_download_completion(std::function callback) +{ + std::unique_lock lock(m_state_mutex); + add_completion_callback(lock, std::move(callback), _impl::SyncProgressNotifier::NotifierType::download); +} + +uint64_t SyncSession::register_progress_notifier(std::function notifier, + NotifierType direction, bool is_streaming) +{ + return m_progress_notifier.register_callback(std::move(notifier), direction, is_streaming); +} + +void SyncSession::unregister_progress_notifier(uint64_t token) +{ + m_progress_notifier.unregister_callback(token); +} + +uint64_t SyncSession::register_connection_change_callback(std::function callback) +{ + return m_connection_change_notifier.add_callback(callback); +} + +void SyncSession::unregister_connection_change_callback(uint64_t token) +{ + m_connection_change_notifier.remove_callback(token); +} + +void SyncSession::set_multiplex_identifier(std::string multiplex_identity) +{ + m_multiplex_identity = std::move(multiplex_identity); +} + +SyncSession::PublicState SyncSession::get_public_state() const +{ + if (m_state == nullptr) { + return PublicState::Inactive; + } else if (m_state == &State::active) { + return PublicState::Active; + } else if (m_state == &State::dying) { + return PublicState::Dying; + } else if (m_state == &State::inactive) { + return PublicState::Inactive; + } + REALM_UNREACHABLE(); +} + +SyncSession::PublicState SyncSession::state() const +{ + std::unique_lock lock(m_state_mutex); + return get_public_state(); +} + +SyncSession::ConnectionState SyncSession::connection_state() const +{ + std::unique_lock lock(m_state_mutex); + return m_connection_state; +} + +void SyncSession::update_configuration(SyncConfig new_config) +{ + while (true) { + std::unique_lock lock(m_state_mutex); + if (m_state != &State::inactive) { + // Changing the state releases the lock, which means that by the + // time we reacquire the lock the state may have changed again + // (either due to one of the callbacks being invoked or another + // thread coincidentally doing something). We just attempt to keep + // switching it to inactive until it stays there. + advance_state(lock, State::inactive); + continue; + } + + REALM_ASSERT(m_state == &State::inactive); + REALM_ASSERT(!m_session); + REALM_ASSERT(m_config.user == new_config.user); + m_config = std::move(new_config); + break; + } + revive_if_needed(); +} + +// Represents a reference to the SyncSession from outside of the sync subsystem. +// We attempt to keep the SyncSession in an active state as long as it has an external reference. +class SyncSession::ExternalReference { +public: + ExternalReference(std::shared_ptr session) : m_session(std::move(session)) + {} + + ~ExternalReference() + { + m_session->did_drop_external_reference(); + } + +private: + std::shared_ptr m_session; +}; + +std::shared_ptr SyncSession::external_reference() +{ + std::unique_lock lock(m_state_mutex); + + if (auto external_reference = m_external_reference.lock()) + return std::shared_ptr(external_reference, this); + + auto external_reference = std::make_shared(shared_from_this()); + m_external_reference = external_reference; + return std::shared_ptr(external_reference, this); +} + +std::shared_ptr SyncSession::existing_external_reference() +{ + std::unique_lock lock(m_state_mutex); + + if (auto external_reference = m_external_reference.lock()) + return std::shared_ptr(external_reference, this); + + return nullptr; +} + +void SyncSession::did_drop_external_reference() +{ + std::unique_lock lock(m_state_mutex); + + // If the session is being resurrected we should not close the session. + if (!m_external_reference.expired()) + return; + + m_state->close(lock, *this); +} + +uint64_t SyncProgressNotifier::register_callback(std::function notifier, + NotifierType direction, bool is_streaming) +{ + std::function invocation; + uint64_t token_value = 0; + { + std::lock_guard lock(m_mutex); + token_value = m_progress_notifier_token++; + NotifierPackage package{std::move(notifier), util::none, m_local_transaction_version, + is_streaming, direction == NotifierType::download}; + if (!m_current_progress) { + // Simply register the package, since we have no data yet. + m_packages.emplace(token_value, std::move(package)); + return token_value; + } + bool skip_registration = false; + invocation = package.create_invocation(*m_current_progress, skip_registration); + if (skip_registration) { + token_value = 0; + } else { + m_packages.emplace(token_value, std::move(package)); + } + } + invocation(); + return token_value; +} + +void SyncProgressNotifier::unregister_callback(uint64_t token) +{ + std::lock_guard lock(m_mutex); + m_packages.erase(token); +} + +void SyncProgressNotifier::update(uint64_t downloaded, uint64_t downloadable, + uint64_t uploaded, uint64_t uploadable, + uint64_t download_version, uint64_t snapshot_version) +{ + // Ignore progress messages from before we first receive a DOWNLOAD message + if (download_version == 0) + return; + + std::vector> invocations; + { + std::lock_guard lock(m_mutex); + m_current_progress = Progress{uploadable, downloadable, uploaded, downloaded, snapshot_version}; + + for (auto it = m_packages.begin(); it != m_packages.end(); ) { + bool should_delete = false; + invocations.emplace_back(it->second.create_invocation(*m_current_progress, should_delete)); + it = should_delete ? m_packages.erase(it) : std::next(it); + } + } + // Run the notifiers only after we've released the lock. + for (auto& invocation : invocations) + invocation(); +} + +void SyncProgressNotifier::set_local_version(uint64_t snapshot_version) +{ + std::lock_guard lock(m_mutex); + m_local_transaction_version = snapshot_version; +} + +std::function SyncProgressNotifier::NotifierPackage::create_invocation(Progress const& current_progress, bool& is_expired) +{ + uint64_t transferrable; + if (is_streaming) { + transferrable = is_download ? current_progress.downloadable : current_progress.uploadable; + } + else if (captured_transferrable) { + transferrable = *captured_transferrable; + } + else { + if (is_download) + captured_transferrable = current_progress.downloadable; + else { + // If the sync client has not yet processed all of the local + // transactions then the uploadable data is incorrect and we should + // not invoke the callback + if (snapshot_version > current_progress.snapshot_version) + return []{}; + captured_transferrable = current_progress.uploadable; + } + transferrable = *captured_transferrable; + } + + uint64_t transferred = is_download ? current_progress.downloaded : current_progress.uploaded; + // A notifier is expired if at least as many bytes have been transferred + // as were originally considered transferrable. + is_expired = !is_streaming && transferred >= transferrable; + return [=, notifier=notifier] { notifier(transferred, transferrable); }; +} + +uint64_t SyncSession::ConnectionChangeNotifier::add_callback(std::function callback) +{ + std::lock_guard lock(m_callback_mutex); + auto token = m_next_token++; + m_callbacks.push_back({std::move(callback), token}); + return token; +} + +void SyncSession::ConnectionChangeNotifier::remove_callback(uint64_t token) +{ + Callback old; + { + std::lock_guard lock(m_callback_mutex); + auto it = find_if(begin(m_callbacks), end(m_callbacks), + [=](const auto& c) { return c.token == token; }); + if (it == end(m_callbacks)) { + return; + } + + size_t idx = distance(begin(m_callbacks), it); + if (m_callback_index != npos) { + if (m_callback_index >= idx) + --m_callback_index; + } + --m_callback_count; + + old = std::move(*it); + m_callbacks.erase(it); + } +} + +void SyncSession::ConnectionChangeNotifier::invoke_callbacks(ConnectionState old_state, ConnectionState new_state) +{ + std::unique_lock lock(m_callback_mutex); + m_callback_count = m_callbacks.size(); + for (++m_callback_index; m_callback_index < m_callback_count; ++m_callback_index) { + // acquire a local reference to the callback so that removing the + // callback from within it can't result in a dangling pointer + auto cb = m_callbacks[m_callback_index].fn; + lock.unlock(); + cb(old_state, new_state); + lock.lock(); + } + m_callback_index = npos; +} diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/sync_user.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/sync_user.cpp new file mode 100644 index 0000000..ad323f5 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/sync/sync_user.cpp @@ -0,0 +1,437 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// 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 "sync/sync_user.hpp" + +#include "sync/app_credentials.hpp" +#include "sync/generic_network_transport.hpp" +#include "sync/impl/sync_metadata.hpp" +#include "sync/remote_mongo_client.hpp" +#include "sync/sync_manager.hpp" +#include "sync/sync_session.hpp" + +#include + +namespace realm { + +static std::string base64_decode(const std::string &in) { + std::string out; + out.resize(util::base64_decoded_size(in.size())); + util::base64_decode(in, &out[0], out.size()); + return out; +} + +static std::vector split_token(const std::string& jwt) { + constexpr static char delimiter = '.'; + + std::vector parts; + size_t pos = 0, start_from = 0; + + while ((pos = jwt.find(delimiter, start_from)) != std::string::npos) { + parts.push_back(jwt.substr(start_from, pos - start_from)); + start_from = pos + 1; + } + + parts.push_back(jwt.substr(start_from)); + + if (parts.size() != 3) { + throw app::AppError(make_error_code(app::JSONErrorCode::bad_token), "jwt missing parts"); + } + + return parts; +} + +RealmJWT::RealmJWT(std::string&& token) +{ + this->token = std::move(token); + + auto parts = split_token(this->token); + + auto json_str = base64_decode(parts[1]); + auto json = static_cast(bson::parse(json_str)); + + this->expires_at = static_cast(json["exp"]); + this->issued_at = static_cast(json["iat"]); + + if (json.find("user_data") != json.end()) { + this->user_data = static_cast(json["user_data"]); + } +} + +SyncUserProfile::SyncUserProfile(util::Optional name, + util::Optional email, + util::Optional picture_url, + util::Optional first_name, + util::Optional last_name, + util::Optional gender, + util::Optional birthday, + util::Optional min_age, + util::Optional max_age) +: name(std::move(name)) +, email(std::move(email)) +, picture_url(std::move(picture_url)) +, first_name(std::move(first_name)) +, last_name(std::move(last_name)) +, gender(std::move(gender)) +, birthday(std::move(birthday)) +, min_age(std::move(min_age)) +, max_age(std::move(max_age)) +{ +} + +SyncUserIdentity::SyncUserIdentity(const std::string& id, const std::string& provider_type) +: id(id) +, provider_type(provider_type) +{ +} + +SyncUserContextFactory SyncUser::s_binding_context_factory; +std::mutex SyncUser::s_binding_context_factory_mutex; + +SyncUser::SyncUser(std::string refresh_token, + const std::string identity, + const std::string provider_type, + std::string access_token, + SyncUser::State state, + const std::string device_id, + std::shared_ptr sync_manager) +: m_state(state) +, m_provider_type(provider_type) +, m_refresh_token(RealmJWT(std::move(refresh_token))) +, m_identity(std::move(identity)) +, m_access_token(RealmJWT(std::move(access_token))) +, m_device_id(device_id) +, m_sync_manager(sync_manager) +{ + { + std::lock_guard lock(s_binding_context_factory_mutex); + if (s_binding_context_factory) { + m_binding_context = s_binding_context_factory(); + } + } + + bool updated = m_sync_manager->perform_metadata_update([=](const auto& manager) { + auto metadata = manager.get_or_make_user_metadata(m_identity, m_provider_type); + metadata->set_refresh_token(m_refresh_token.token); + metadata->set_access_token(m_access_token.token); + metadata->set_device_id(m_device_id); + m_local_identity = metadata->local_uuid(); + }); + if (!updated) + m_local_identity = m_identity; +} + +std::vector> SyncUser::all_sessions() +{ + std::lock_guard lock(m_mutex); + std::vector> sessions; + if (m_state == State::Removed) { + return sessions; + } + for (auto it = m_sessions.begin(); it != m_sessions.end();) { + if (auto ptr_to_session = it->second.lock()) { + sessions.emplace_back(std::move(ptr_to_session)); + it++; + continue; + } + // This session is bad, destroy it. + it = m_sessions.erase(it); + } + return sessions; +} + +std::shared_ptr SyncUser::session_for_on_disk_path(const std::string& path) +{ + std::lock_guard lock(m_mutex); + if (m_state == State::Removed) { + return nullptr; + } + auto it = m_sessions.find(path); + if (it == m_sessions.end()) { + return nullptr; + } + auto locked = it->second.lock(); + if (!locked) { + // Remove the session from the map, because it has fatally errored out or the entry is invalid. + m_sessions.erase(it); + } + return locked; +} + +void SyncUser::update_refresh_token(std::string&& token) +{ + std::vector> sessions_to_revive; + { + std::unique_lock lock(m_mutex); + switch (m_state) { + case State::Removed: + return; + case State::LoggedIn: + m_refresh_token = RealmJWT(std::move(token)); + break; + case State::LoggedOut: { + sessions_to_revive.reserve(m_waiting_sessions.size()); + m_refresh_token = RealmJWT(std::move(token)); + m_state = State::LoggedIn; + for (auto& pair : m_waiting_sessions) { + if (auto ptr = pair.second.lock()) { + m_sessions[pair.first] = ptr; + sessions_to_revive.emplace_back(std::move(ptr)); + } + } + m_waiting_sessions.clear(); + break; + } + } + + m_sync_manager->perform_metadata_update([=](const auto& manager) { + auto metadata = manager.get_or_make_user_metadata(m_identity, m_provider_type); + metadata->set_refresh_token(m_refresh_token.token); + }); + } + // (Re)activate all pending sessions. + // Note that we do this after releasing the lock, since the session may + // need to access protected User state in the process of binding itself. + for (auto& session : sessions_to_revive) { + session->revive_if_needed(); + } +} + +void SyncUser::update_access_token(std::string&& token) +{ + std::vector> sessions_to_revive; + { + std::unique_lock lock(m_mutex); + switch (m_state) { + case State::Removed: + return; + case State::LoggedIn: + m_access_token = RealmJWT(std::move(token)); + break; + case State::LoggedOut: { + sessions_to_revive.reserve(m_waiting_sessions.size()); + m_access_token = RealmJWT(std::move(token)); + m_state = State::LoggedIn; + for (auto& pair : m_waiting_sessions) { + if (auto ptr = pair.second.lock()) { + m_sessions[pair.first] = ptr; + sessions_to_revive.emplace_back(std::move(ptr)); + } + } + m_waiting_sessions.clear(); + break; + } + } + + m_sync_manager->perform_metadata_update([=](const auto& manager) { + auto metadata = manager.get_or_make_user_metadata(m_identity, m_provider_type); + metadata->set_access_token(m_access_token.token); + }); + } + + // (Re)activate all pending sessions. + // Note that we do this after releasing the lock, since the session may + // need to access protected User state in the process of binding itself. + for (auto& session : sessions_to_revive) { + session->revive_if_needed(); + } +} + +std::vector SyncUser::identities() const +{ + std::lock_guard lock(m_mutex); + return m_user_identities; +} + + +void SyncUser::update_identities(std::vector identities) +{ + std::unique_lock lock(m_mutex); + + m_user_identities = identities; + + m_sync_manager->perform_metadata_update([=](const auto& manager) { + auto metadata = manager.get_or_make_user_metadata(m_identity, m_provider_type); + metadata->set_identities(identities); + }); +} + +void SyncUser::log_out() +{ + { + std::lock_guard lock(m_mutex); + if (m_state == State::LoggedOut) { + return; + } + m_state = State::LoggedOut; + m_access_token.token = ""; + m_refresh_token.token = ""; + + m_sync_manager->perform_metadata_update([=](const auto& manager) { + auto metadata = manager.get_or_make_user_metadata(m_identity, m_provider_type); + metadata->set_state(State::LoggedOut); + metadata->set_access_token(""); + metadata->set_refresh_token(""); + }); + // Move all active sessions into the waiting sessions pool. If the user is + // logged back in, they will automatically be reactivated. + for (auto& pair : m_sessions) { + if (auto ptr = pair.second.lock()) { + ptr->log_out(); + m_waiting_sessions[pair.first] = ptr; + } + } + m_sessions.clear(); + } + + m_sync_manager->log_out_user(m_identity); + + // Mark the user as 'dead' in the persisted metadata Realm + // if they were an anonymous user + if (this->m_provider_type == app::IdentityProviderAnonymous) { + invalidate(); + m_sync_manager->perform_metadata_update([=](const auto& manager) { + auto metadata = manager.get_or_make_user_metadata(m_identity, m_provider_type, false); + if (metadata) + metadata->remove(); + }); + } +} + +bool SyncUser::is_logged_in() const +{ + std::lock_guard lock(m_mutex); + return !m_access_token.token.empty() && !m_refresh_token.token.empty() && m_state == State::LoggedIn; +} + +void SyncUser::invalidate() +{ + set_state(SyncUser::State::Removed); +} + +std::string SyncUser::refresh_token() const +{ + std::lock_guard lock(m_mutex); + return m_refresh_token.token; +} + +std::string SyncUser::access_token() const +{ + std::lock_guard lock(m_mutex); + return m_access_token.token; +} + +std::string SyncUser::device_id() const +{ + std::lock_guard lock(m_mutex); + return m_device_id; +} + +bool SyncUser::has_device_id() const +{ + std::lock_guard lock(m_mutex); + return !m_device_id.empty() && m_device_id != "000000000000000000000000"; +} + +SyncUser::State SyncUser::state() const +{ + std::lock_guard lock(m_mutex); + return m_state; +} + +void SyncUser::set_state(SyncUser::State state) +{ + std::lock_guard lock(m_mutex); + m_state = state; + m_sync_manager->perform_metadata_update([=](const auto& manager) { + auto metadata = manager.get_or_make_user_metadata(m_identity, m_provider_type); + metadata->set_state(state); + }); +} + +SyncUserProfile SyncUser::user_profile() const +{ + std::lock_guard lock(m_mutex); + return m_user_profile; +} + +util::Optional SyncUser::custom_data() const +{ + std::lock_guard lock(m_mutex); + return m_access_token.user_data; +} + +void SyncUser::update_user_profile(const SyncUserProfile& profile) +{ + std::unique_lock lock(m_mutex); + + m_user_profile = profile; + + m_sync_manager->perform_metadata_update([=](const auto& manager) { + auto metadata = manager.get_or_make_user_metadata(m_identity, m_provider_type); + metadata->set_user_profile(profile); + }); +} + +void SyncUser::register_session(std::shared_ptr session) +{ + const std::string& path = session->path(); + std::unique_lock lock(m_mutex); + switch (m_state) { + case State::LoggedIn: + // Immediately ask the session to come online. + m_sessions[path] = session; + lock.unlock(); + session->revive_if_needed(); + break; + case State::LoggedOut: + m_waiting_sessions[path] = session; + break; + case State::Removed: + break; + } +} + +app::MongoClient SyncUser::mongo_client(const std::string& service_name) +{ + return app::MongoClient(shared_from_this(), m_sync_manager->app().lock(), service_name); +} + +void SyncUser::set_binding_context_factory(SyncUserContextFactory factory) +{ + std::lock_guard lock(s_binding_context_factory_mutex); + s_binding_context_factory = std::move(factory); +} + +void SyncUser::refresh_custom_data(std::function)> completion_block) +{ + if (auto app = m_sync_manager->app().lock()) { + app->refresh_custom_data(shared_from_this(), completion_block); + } else { + completion_block(app::AppError(app::make_client_error_code(app::ClientErrorCode::app_deallocated), + "App has been deallocated")); + } +} +} // namespace realm + +namespace std { +size_t hash::operator()(const realm::SyncUserIdentity& k) const +{ + return ((hash()(k.id) ^ (hash()(k.provider_type) << 1)) >> 1); +} +} diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/thread_safe_reference.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/thread_safe_reference.cpp new file mode 100644 index 0000000..5a02753 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/thread_safe_reference.cpp @@ -0,0 +1,243 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// 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 "thread_safe_reference.hpp" + +#include "list.hpp" +#include "object.hpp" +#include "object_schema.hpp" +#include "results.hpp" +#include "shared_realm.hpp" + +#include "impl/realm_coordinator.hpp" + +#include +#include + +namespace realm { +class ThreadSafeReference::Payload { +public: + virtual ~Payload() = default; + Payload(Realm& realm) + : m_transaction(realm.is_in_read_transaction() ? realm.duplicate() : nullptr) + , m_coordinator(Realm::Internal::get_coordinator(realm).shared_from_this()) + , m_created_in_write_transaction(realm.is_in_transaction()) + { + } + + void refresh_target_realm(Realm&); + +protected: + const TransactionRef m_transaction; + +private: + const std::shared_ptr<_impl::RealmCoordinator> m_coordinator; + const bool m_created_in_write_transaction; +}; + +void ThreadSafeReference::Payload::refresh_target_realm(Realm& realm) +{ + if (!realm.is_in_read_transaction()) { + if (m_created_in_write_transaction) + realm.read_group(); + else + Realm::Internal::begin_read(realm, m_transaction->get_version_of_current_transaction()); + } + else { + auto version = realm.read_transaction_version(); + auto target_version = m_transaction->get_version_of_current_transaction(); + if (version < target_version || (version == target_version && m_created_in_write_transaction)) + realm.refresh(); + } +} + +template<> +class ThreadSafeReference::PayloadImpl : public ThreadSafeReference::Payload { +public: + PayloadImpl(List const& list) + : Payload(*list.get_realm()) + , m_key(list.get_parent_object_key()) + , m_table_key(list.get_parent_table_key()) + , m_col_key(list.get_parent_column_key()) + { + } + + List import_into(std::shared_ptr const& r) + { + Obj obj = r->read_group().get_table(m_table_key)->get_object(m_key); + return List(r, obj, m_col_key); + } + +private: + ObjKey m_key; + TableKey m_table_key; + ColKey m_col_key; +}; + +template<> +class ThreadSafeReference::PayloadImpl : public ThreadSafeReference::Payload { +public: + PayloadImpl(Object const& object) + : Payload(*object.get_realm()) + , m_key(object.obj().get_key()) + , m_object_schema_name(object.get_object_schema().name) + { + } + + Object import_into(std::shared_ptr const& r) + { + return Object(r, m_object_schema_name, m_key); + } + +private: + ObjKey m_key; + std::string m_object_schema_name; +}; + +template<> +class ThreadSafeReference::PayloadImpl : public ThreadSafeReference::Payload { +public: + PayloadImpl(Results const& r) + : Payload(*r.get_realm()) + , m_ordering(r.get_descriptor_ordering()) + { + if (auto list = r.get_list()) { + m_key = list->get_key(); + m_table_key = list->get_table()->get_key(); + m_col_key = list->get_col_key(); + } + else { + Query q(r.get_query()); + if (!q.produces_results_in_table_order() && r.get_realm()->is_in_transaction()) { + // FIXME: This is overly restrictive. It's only a problem if + // the parent of the List or LinkingObjects was created in this + // write transaction, but Query doesn't expose a way to check + // if the source view is valid so we have to forbid it always. + throw std::logic_error("Cannot create a ThreadSafeReference to Results backed by a List of objects or LinkingObjects inside a write transaction"); + } + m_query = m_transaction->import_copy_of(q, PayloadPolicy::Stay); + } + } + + Results import_into(std::shared_ptr const& r) + { + if (m_key) { + LstBasePtr list; + auto table = r->read_group().get_table(m_table_key); + try { + list = table->get_object(m_key).get_listbase_ptr(m_col_key); + } + catch (KeyNotFound const&) { + // Create a detached list of the appropriate type so that we + // return an invalid Results rather than an Empty Results, to + // match what happens for other types of handover where the + // object doesn't exist. + switch_on_type(ObjectSchema::from_core_type(m_col_key), [&](auto* t) -> void { + list = std::make_unique>>(); + }); + } + return Results(r, std::move(list), m_ordering); + } + auto q = r->import_copy_of(*m_query, PayloadPolicy::Stay); + return Results(std::move(r), std::move(*q), m_ordering); + } + +private: + DescriptorOrdering m_ordering; + std::unique_ptr m_query; + ObjKey m_key; + TableKey m_table_key; + ColKey m_col_key; +}; + +template<> +class ThreadSafeReference::PayloadImpl> : public ThreadSafeReference::Payload { +public: + PayloadImpl(std::shared_ptr const& realm) + : Payload(*realm) + , m_realm(realm) + { + } + + std::shared_ptr get_realm() + { + return std::move(m_realm); + } + +private: + std::shared_ptr m_realm; +}; + +ThreadSafeReference::ThreadSafeReference() noexcept = default; +ThreadSafeReference::~ThreadSafeReference() = default; +ThreadSafeReference::ThreadSafeReference(ThreadSafeReference&&) noexcept = default; +ThreadSafeReference& ThreadSafeReference::operator=(ThreadSafeReference&&) noexcept = default; + +template +ThreadSafeReference::ThreadSafeReference(T const& value) +{ + auto realm = value.get_realm(); + realm->verify_thread(); + m_payload.reset(new PayloadImpl(value)); +} + +template<> +ThreadSafeReference::ThreadSafeReference(std::shared_ptr const& value) +{ + m_payload.reset(new PayloadImpl>(value)); +} + +template ThreadSafeReference::ThreadSafeReference(List const&); +template ThreadSafeReference::ThreadSafeReference(Results const&); +template ThreadSafeReference::ThreadSafeReference(Object const&); + +template +T ThreadSafeReference::resolve(std::shared_ptr const& realm) +{ + REALM_ASSERT(realm); + realm->verify_thread(); + + REALM_ASSERT(m_payload); + auto& payload = static_cast&>(*m_payload); + REALM_ASSERT(typeid(payload) == typeid(PayloadImpl)); + + m_payload->refresh_target_realm(*realm); + try { + return payload.import_into(realm); + } + catch (KeyNotFound const&) { + // Object was deleted in a version after when the TSR was created + return {}; + } +} + +template<> +std::shared_ptr ThreadSafeReference::resolve>(std::shared_ptr const&) +{ + REALM_ASSERT(m_payload); + auto& payload = static_cast>&>(*m_payload); + REALM_ASSERT(typeid(payload) == typeid(PayloadImpl>)); + + return payload.get_realm(); +} + +template Results ThreadSafeReference::resolve(std::shared_ptr const&); +template List ThreadSafeReference::resolve(std::shared_ptr const&); +template Object ThreadSafeReference::resolve(std::shared_ptr const&); + +} // namespace realm diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/util/bson/bson.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/util/bson/bson.cpp new file mode 100644 index 0000000..c57647b --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/util/bson/bson.cpp @@ -0,0 +1,672 @@ +/************************************************************************* + * + * Copyright 2020 Realm Inc. + * + * 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 expreout or implied. + * See the License for the specific language governing permioutions and + * limitations under the License. + * + **************************************************************************/ + +#include "util/bson/bson.hpp" +#include +#include +#include +#include +#include + +namespace realm { +namespace bson { + +Bson::~Bson() noexcept +{ + switch (m_type) { + case Type::String: + string_val.~basic_string(); + break; + case Type::Binary: + binary_val.~vector(); + break; + case Type::RegularExpression: + regex_val.~RegularExpression(); + break; + case Type::Document: + document_val.reset(); + break; + case Type::Array: + array_val.reset(); + break; + default: + break; + } +} + +Bson::Bson(const Bson& v) { + m_type = Type::Null; + *this = v; +} + +Bson::Bson(Bson&& v) noexcept { + m_type = Type::Null; + *this = std::move(v); +} + +Bson& Bson::operator=(Bson&& v) noexcept { + if (this == &v) + return *this; + + this->~Bson(); + + m_type = v.m_type; + + switch (v.m_type) { + case Type::Null: + break; + case Type::Int32: + int32_val = v.int32_val; + break; + case Type::Int64: + int64_val = v.int64_val; + break; + case Type::Bool: + bool_val = v.bool_val; + break; + case Type::Double: + double_val = v.double_val; + break; + case Type::Timestamp: + time_val = v.time_val; + break; + case Type::Datetime: + date_val = v.date_val; + break; + case Type::ObjectId: + oid_val = v.oid_val; + break; + case Type::Decimal128: + decimal_val = v.decimal_val; + break; + case Type::MaxKey: + max_key_val = v.max_key_val; + break; + case Type::MinKey: + min_key_val = v.min_key_val; + break; + case Type::Binary: + new (&binary_val) std::vector(std::move(v.binary_val)); + break; + case Type::RegularExpression: + new (®ex_val) RegularExpression(std::move(v.regex_val)); + break; + case Type::String: + new (&string_val) std::string(std::move(v.string_val)); + break; + case Type::Document: + new (&document_val) std::unique_ptr{std::move(v.document_val)}; + break; + case Type::Array: + new (&array_val) std::unique_ptr{std::move(v.array_val)}; + break; + } + + return *this; +} + +Bson& Bson::operator=(const Bson& v) { + if (&v == this) + return *this; + + this->~Bson(); + + m_type = v.m_type; + + switch (v.m_type) { + case Type::Null: + break; + case Type::Int32: + int32_val = v.int32_val; + break; + case Type::Int64: + int64_val = v.int64_val; + break; + case Type::Bool: + bool_val = v.bool_val; + break; + case Type::Double: + double_val = v.double_val; + break; + case Type::Timestamp: + time_val = v.time_val; + break; + case Type::Datetime: + date_val = v.date_val; + break; + case Type::ObjectId: + oid_val = v.oid_val; + break; + case Type::Decimal128: + decimal_val = v.decimal_val; + break; + case Type::MaxKey: + max_key_val = v.max_key_val; + break; + case Type::MinKey: + min_key_val = v.min_key_val; + break; + case Type::Binary: + new (&binary_val) std::vector(v.binary_val); + break; + case Type::RegularExpression: + new (®ex_val) RegularExpression(v.regex_val); + break; + case Type::String: + new (&string_val) std::string(v.string_val); + break; + case Type::Document: + new (&document_val) std::unique_ptr(new BsonDocument(*v.document_val)); + break; + case Type::Array: { + new (&array_val) std::unique_ptr(new BsonArray(*v.array_val)); + break; + } + } + + return *this; +} + +Bson::Type Bson::type() const noexcept +{ + return m_type; +} + +std::string Bson::to_string() const +{ + std::stringstream ss; + ss << *this; + return ss.str(); +} + +bool Bson::operator==(const Bson& other) const +{ + if (m_type != other.m_type) { + return false; + } + + switch (m_type) { + case Type::Null: + return true; + case Type::Int32: + return int32_val == other.int32_val; + case Type::Int64: + return int64_val == other.int64_val; + case Type::Bool: + return bool_val == other.bool_val; + case Type::Double: + return double_val == other.double_val; + case Type::Datetime: + return date_val == other.date_val; + case Type::Timestamp: + return time_val == other.time_val; + case Type::ObjectId: + return oid_val == other.oid_val; + case Type::Decimal128: + return decimal_val == other.decimal_val; + case Type::MaxKey: + return max_key_val == other.max_key_val; + case Type::MinKey: + return min_key_val == other.min_key_val; + case Type::String: + return string_val == other.string_val; + case Type::RegularExpression: + return regex_val == other.regex_val; + case Type::Binary: + return binary_val == other.binary_val; + case Type::Document: + return *document_val == *other.document_val; + case Type::Array: + return *array_val == *other.array_val; + } + + return false; +} + +bool Bson::operator!=(const Bson& other) const +{ + return !(*this == other); +} + +template<> +bool holds_alternative(const Bson& bson) +{ + return bson.m_type == Bson::Type::Null; +} + +template<> +bool holds_alternative(const Bson& bson) +{ + return bson.m_type == Bson::Type::Int32; +} + +template<> +bool holds_alternative(const Bson& bson) +{ + return bson.m_type == Bson::Type::Int64; +} + +template<> +bool holds_alternative(const Bson& bson) +{ + return bson.m_type == Bson::Type::Bool; +} + +template<> +bool holds_alternative(const Bson& bson) +{ + return bson.m_type == Bson::Type::Double; +} + +template<> +bool holds_alternative(const Bson& bson) +{ + return bson.m_type == Bson::Type::String; +} + +template<> +bool holds_alternative>(const Bson& bson) +{ + return bson.m_type == Bson::Type::Binary; +} + +template<> +bool holds_alternative(const Bson& bson) +{ + return bson.m_type == Bson::Type::Datetime; +} + +template<> +bool holds_alternative(const Bson& bson) +{ + return bson.m_type == Bson::Type::ObjectId; +} + +template<> +bool holds_alternative(const Bson& bson) +{ + return bson.m_type == Bson::Type::Decimal128; +} + +template<> +bool holds_alternative(const Bson& bson) +{ + return bson.m_type == Bson::Type::RegularExpression; +} + +template<> +bool holds_alternative(const Bson& bson) +{ + return bson.m_type == Bson::Type::MinKey; +} + +template<> +bool holds_alternative(const Bson& bson) +{ + return bson.m_type == Bson::Type::MaxKey; +} + +template<> +bool holds_alternative>(const Bson& bson) +{ + return bson.m_type == Bson::Type::Document; +} + +template<> +bool holds_alternative>(const Bson& bson) +{ + return bson.m_type == Bson::Type::Array; +} + +template<> +bool holds_alternative(const Bson& bson) +{ + return bson.m_type == Bson::Type::Timestamp; +} + +struct PrecisionGuard { + PrecisionGuard(std::ostream& stream, std::streamsize new_precision) + : stream(stream) + , old_precision(stream.precision(new_precision)) + {} + + ~PrecisionGuard() { + stream.precision(old_precision); + } + + std::ostream& stream; + std::streamsize old_precision; +}; + +std::ostream& operator<<(std::ostream& out, const Bson& b) +{ + switch (b.type()) { + case Bson::Type::Null: + out << "null"; + break; + case Bson::Type::Int32: + out << "{" << "\"$numberInt\"" << ":" << '"' << static_cast(b) << '"' << "}"; + break; + case Bson::Type::Int64: + out << "{" << "\"$numberLong\"" << ":" << '"' << static_cast(b) << '"' << "}"; + break; + case Bson::Type::Bool: + out << (b ? "true" : "false"); + break; + case Bson::Type::Double: { + double d = static_cast(b); + out << "{" << "\"$numberDouble\"" << ":" << '"'; + if (std::isnan(d)) { + out << "NaN"; + } else if (d == std::numeric_limits::infinity()) { + out << "Infinity"; + } else if (d == (-1 * std::numeric_limits::infinity())) { + out << "-Infinity"; + } else { + PrecisionGuard precision_guard(out, std::numeric_limits::max_digits10); + out << d; + } + out << '"' << "}"; + break; + } + case Bson::Type::String: + out << nlohmann::json(b.operator const std::string&()).dump(); + break; + case Bson::Type::Binary: { + const std::vector& vec = static_cast>(b); + out << "{\"$binary\":{\"base64\":\"" << + std::string(vec.begin(), vec.end()) << "\",\"subType\":\"00\"}}"; + break; + } + case Bson::Type::Timestamp: { + const MongoTimestamp& t = static_cast(b); + out << "{\"$timestamp\":{\"t\":" << t.seconds << ",\"i\":" << t.increment << "}}"; + break; + } + case Bson::Type::Datetime: { + auto d = static_cast(b); + + out << "{\"$date\":{\"$numberLong\":\"" + << ((d.get_seconds() * 1000) + d.get_nanoseconds()/1000000) + << "\"}}"; + break; + } + case Bson::Type::ObjectId: { + const ObjectId& oid = static_cast(b); + out << "{" << "\"$oid\"" << ":" << '"' << oid << '"' << "}"; + break; + } + case Bson::Type::Decimal128: { + const Decimal128& d = static_cast(b); + out << "{" << "\"$numberDecimal\"" << ":" << '"'; + if (d.is_nan()) { + out << "NaN"; + } else if (d == Decimal128("Infinity")) { + out << "Infinity"; + } else if (d == Decimal128("-Infinity")) { + out << "-Infinity"; + } else { + out << d; + } + out << '"' << "}"; + break; + } + case Bson::Type::RegularExpression: { + const RegularExpression& regex = static_cast(b); + out << "{\"$regularExpression\":{\"pattern\":\"" << regex.pattern() + << "\",\"options\":\"" << regex.options() << "\"}}"; + break; + } + case Bson::Type::MaxKey: + out << "{\"$maxKey\":1}"; + break; + case Bson::Type::MinKey: + out << "{\"$minKey\":1}"; + break; + case Bson::Type::Document: { + const BsonDocument& doc = static_cast(b); + out << "{"; + bool first = true; + for (auto const& pair : doc) { + if (!first) + out << ','; + first = false; + out << nlohmann::json(pair.first).dump() << ':' << pair.second; + } + out << "}"; + break; + } + case Bson::Type::Array: { + const BsonArray& arr = static_cast(b); + out << "["; + bool first = true; + for (auto const& b : arr) { + if (!first) + out << ','; + first = false; + out << b; + } + out << "]"; + break; + } + } + return out; +} + +std::string Bson::toJson() const { + std::stringstream s; + s << *this; + return s.str(); +} + +namespace { + +struct BsonError : public std::runtime_error { + BsonError(std::string message) : std::runtime_error(std::move(message)) + { + } +}; + +namespace { +// This implements just enough of the map API to support nlohmann's DOM apis that we use. +template +struct LinearMap { + using key_type = K; + using mapped_type = V; + using value_type = std::pair; + using storage_type = std::vector; + using iterator = typename storage_type::iterator; + using const_iterator = typename storage_type::const_iterator; + + auto begin() { return _elems.begin(); } + auto begin() const { return _elems.begin(); } + auto end() { return _elems.end(); } + auto end() const { return _elems.end(); } + auto size() const { return _elems.size(); } + auto max_size() const { return _elems.max_size(); } + auto clear() { return _elems.clear(); } + V& operator[](const K& k) { + // assume this is only used for adding a new element. + return _elems.emplace_back(k, V()).second; + } + + template + std::pair emplace(Args&&... args) { + // assume this is only used for adding a new element. + _elems.emplace_back(std::forward(args)...); + return {--_elems.end(), true}; + } + + iterator erase(iterator) { + // This is only used when mutating the DOM which we don't do. + REALM_TERMINATE("LinearMap::erase() should never be called"); + } + + storage_type _elems; +}; + +using Json = nlohmann::basic_json; + +Bson dom_obj_to_bson(const Json& json); + +Bson dom_elem_to_bson(const Json& json) { + switch (json.type()) { + case Json::value_t::null: + return Bson(); + case Json::value_t::string: + return Bson(json.get()); + case Json::value_t::boolean: + return Bson(json.get()); + case Json::value_t::number_integer: + return Bson(json.get()); + case Json::value_t::number_unsigned: { + uint64_t val = json.get(); + if (val <= uint64_t(std::numeric_limits::max())) + return Bson(int64_t(val)); + return Bson(double(val)); + } + case Json::value_t::number_float: + return Bson(json.get()); + case Json::value_t::object: + return dom_obj_to_bson(json); + case Json::value_t::array: { + std::vector out; + for (auto&& elem : json) { + out.push_back(dom_elem_to_bson(elem)); + } + return Bson(std::move(out)); + } + case Json::value_t::discarded: + REALM_TERMINATE("should never see discarded"); + } + REALM_TERMINATE("unknown json value type"); +} + +// This works around the deleted rvalue constructor in StringData +inline StringData tosd(const std::string& s) { return s; } + +// Keep these sorted by key. This is checked so you can't forget. +using FancyParser = Bson(*)(const Json& json); +static constexpr std::pair bson_fancy_parsers[] = { + {"$binary", +[](const Json& json) { + util::Optional> base64; + util::Optional subType; + if (json.size() != 2) + throw BsonError("invalid extended json $binary"); + for (auto&& [k, v] : json.items()) { + if (k == "base64") { + const std::string& str = v.get(); + base64.emplace(str.begin(), str.end()); + } else if (k == "subType") { + subType = std::stoul(v.get(), nullptr, 16); + } + } + if (!base64 || !subType) + throw BsonError("invalid extended json $binary"); + return Bson(std::move(*base64)); // TODO don't throw away the subType. + }}, + {"$date", +[](const Json& json) { + int64_t millis_since_epoch = dom_elem_to_bson(json).operator int64_t(); + return Bson(realm::Timestamp(millis_since_epoch / 1000, + (millis_since_epoch % 1000) * 1'000'000)); // ms -> ns + }}, + {"$maxKey", +[](const Json&) { return Bson(MaxKey()); }}, + {"$minKey", +[](const Json&) { return Bson(MinKey()); }}, + {"$numberDecimal", +[](const Json& json) { return Bson(Decimal128(tosd(json.get()))); }}, + {"$numberDouble", +[](const Json& json) { return Bson(std::stod(json.get())); }}, + {"$numberInt", +[](const Json& json) { return Bson(int32_t(std::stoi(json.get()))); }}, + {"$numberLong", +[](const Json& json) { return Bson(int64_t(std::stoll(json.get()))); }}, + {"$oid", +[](const Json& json) { return Bson(ObjectId(json.get().c_str())); }}, + {"$regularExpression", +[](const Json& json) { + util::Optional pattern; + util::Optional options; + if (json.size() != 2) + throw BsonError("invalid extended json $binary"); + for (auto&& [k, v] : json.items()) { + if (k == "pattern") { + pattern = v.get(); + } else if (k == "options") { + options = v.get(); + } + } + if (!pattern || !options) + throw BsonError("invalid extended json $binary"); + return Bson(RegularExpression(std::move(*pattern), std::move(*options))); + }}, + {"$timestamp", +[](const Json& json) { + util::Optional t; + util::Optional i; + if (json.size() != 2) + throw BsonError("invalid extended json $timestamp"); + for (auto&& [k, v] : json.items()) { + if (k == "t") { + t = v.get(); + } else if (k == "i") { + i = v.get(); + } + } + if (!t || !i) + throw BsonError("invalid extended json $timestamp"); + return Bson(MongoTimestamp(*t, *i)); + }}, +}; + +constexpr auto parser_comp = [](const std::pair& lhs, + const std::pair& rhs) { + return lhs.first < rhs.first; +}; + +// TODO do this instead in C++20 +// static_assert(std::ranges::is_sorted(bson_fancy_parsers, parser_comp)); +#if REALM_DEBUG +[[maybe_unused]] bool check_sort_on_startup = [] { + REALM_ASSERT(std::is_sorted(std::begin(bson_fancy_parsers), std::end(bson_fancy_parsers), parser_comp)); + return false; +}(); +#endif + +Bson dom_obj_to_bson(const Json& json) { + if (json.size() == 1) { + const auto& [key, value] = json.items().begin(); + if (key[0] == '$') { + auto it = std::lower_bound(std::begin(bson_fancy_parsers), + std::end(bson_fancy_parsers), + std::pair(key, nullptr), + parser_comp); + if (it != std::end(bson_fancy_parsers) && it->first == key) { + return it->second(value); + } + } + } + + BsonDocument out; + for (auto&& [k, v] : json.items()) { + out[k] = dom_elem_to_bson(v); + } + return out; +} +} + +} // anonymous namespace + +Bson parse(const std::string_view& json) { + return dom_elem_to_bson(Json::parse(json)); +} + +} // namespace bson +} // namespace realm diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/util/bson/regular_expression.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/util/bson/regular_expression.cpp new file mode 100644 index 0000000..811d611 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/util/bson/regular_expression.cpp @@ -0,0 +1,80 @@ +/************************************************************************* + * + * Copyright 2020 Realm Inc. + * + * 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 "util/bson/regular_expression.hpp" +#include + +namespace realm { +namespace bson { + +RegularExpression::RegularExpression(const std::string pattern, + const std::string& options) : +m_pattern(pattern) +, m_options( + std::accumulate(options.begin(), + options.end(), + RegularExpression::Option::None, + [](RegularExpression::Option a, char b) { return a | option_char_to_option(b); })) +{ +} + +RegularExpression::RegularExpression(const std::string pattern, + Option options) : +m_pattern(pattern), +m_options(options) {} + +const std::string RegularExpression::pattern() const +{ + return m_pattern; +} + +RegularExpression::Option RegularExpression::options() const +{ + return m_options; +} + +constexpr RegularExpression::Option RegularExpression::option_char_to_option(const char option) +{ + switch (option) { + case 'i': + return Option::IgnoreCase; + case 'm': + return Option::Multiline; + case 's': + return Option::Dotall; + case 'x': + return Option::Extended; + default: + throw std::runtime_error("invalid regex option type"); + } +}; + +std::ostream& operator<<(std::ostream& out, const RegularExpression::Option& option) +{ + using Option = RegularExpression::Option; + + if ((option & Option::IgnoreCase) != Option::None) out << 'i'; + if ((option & Option::Multiline) != Option::None) out << 'm'; + if ((option & Option::Dotall) != Option::None) out << 's'; + if ((option & Option::Extended) != Option::None) out << 'x'; + + return out; +} + +} // namespace bson +} // namespace realm diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/util/scheduler.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/util/scheduler.cpp new file mode 100644 index 0000000..daab5c7 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/util/scheduler.cpp @@ -0,0 +1,66 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 "util/scheduler.hpp" +#include + +#if REALM_USE_UV +#include "util/uv/scheduler.hpp" +#elif REALM_USE_CF +#include "util/apple/scheduler.hpp" +#elif REALM_USE_ALOOPER +#include "util/android/scheduler.hpp" +#else +#include "util/generic/scheduler.hpp" +#endif + +namespace { +using namespace realm; + +class FrozenScheduler : public util::Scheduler { +public: + FrozenScheduler(VersionID version) + : m_version(version) + { } + + void notify() override {} + void set_notify_callback(std::function) override {} + bool is_on_thread() const noexcept override { return true; } + bool is_same_as(const Scheduler* other) const noexcept override + { + auto o = dynamic_cast(other); + return (o && (o->m_version == m_version)); + } + bool can_deliver_notifications() const noexcept override { return false; } + +private: + VersionID m_version; +}; +} // anonymous namespace + +namespace realm { +namespace util { + +Scheduler::~Scheduler() = default; + +std::shared_ptr Scheduler::get_frozen(VersionID version) +{ + return std::make_shared(version); +} +} // namespace util +} // namespace realm diff --git a/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/util/uuid.cpp b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/util/uuid.cpp new file mode 100644 index 0000000..0110002 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/ObjectStore/src/util/uuid.cpp @@ -0,0 +1,80 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2017 Realm Inc. +// +// 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 "util/uuid.hpp" + +#include +#include +#include +#include +#include + +namespace { + +// Seed `engine` with as much random state as it requires, based on the approach outlined in P0205R0. +// +template +T create_and_seed_engine() +{ + constexpr auto bytes_needed = T::state_size * sizeof(typename T::result_type); + + constexpr auto numbers_needed = sizeof(std::random_device::result_type) < sizeof(std::seed_seq::result_type) + ? (bytes_needed / sizeof(std::random_device::result_type)) + : (bytes_needed / sizeof(std::seed_seq::result_type)); + + std::array state; + std::random_device rd; + std::generate(begin(state), end(state), std::ref(rd)); + std::seed_seq seeds(begin(state), end(state)); + + T engine; + engine.seed(seeds); + return engine; +} + +} // unnamed namespace + +namespace realm { +namespace util { + +std::string uuid_string() +{ + static auto engine = create_and_seed_engine(); + + std::array uuid_bytes; + std::uniform_int_distribution distribution(0, std::numeric_limits::max()); + std::generate(begin(uuid_bytes), end(uuid_bytes), [&] { return distribution(engine); }); + + // Version 4 UUID. + uuid_bytes[6] = (uuid_bytes[6] & 0x0f) | 0x40; + // IETF variant. + uuid_bytes[8] = (uuid_bytes[8] & 0x3f) | 0x80; + + std::array uuid_formatted; + snprintf(uuid_formatted.data(), uuid_formatted.size(), + "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + uuid_bytes[0], uuid_bytes[1], uuid_bytes[2], uuid_bytes[3], + uuid_bytes[4], uuid_bytes[5], uuid_bytes[6], uuid_bytes[7], + uuid_bytes[8], uuid_bytes[9], uuid_bytes[10], uuid_bytes[11], + uuid_bytes[12], uuid_bytes[13], uuid_bytes[14], uuid_bytes[15]); + + return std::string(uuid_formatted.data(), uuid_formatted.size() - 1); +} + +} // namespace util +} // namespace realm diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMAPIKeyAuth.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMAPIKeyAuth.mm new file mode 100644 index 0000000..cb3a881 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMAPIKeyAuth.mm @@ -0,0 +1,116 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 "RLMAPIKeyAuth.h" +#import "RLMProviderClient_Private.hpp" + +#import "RLMApp_Private.hpp" +#import "RLMUserAPIKey_Private.hpp" +#import "RLMObjectId_Private.hpp" + +@implementation RLMAPIKeyAuth + +- (realm::app::App::UserAPIKeyProviderClient)client { + return self.app._realmApp->provider_client(); +} + +- (std::shared_ptr)currentUser { + return self.app._realmApp->current_user(); +} + +- (void)createAPIKeyWithName:(NSString *)name + completion:(RLMOptionalUserAPIKeyBlock)completion { + + self.client.create_api_key(name.UTF8String, self.currentUser, + ^(realm::util::Optional userAPIKey, + realm::util::Optional error) { + if (error && error->error_code) { + return completion(nil, RLMAppErrorToNSError(*error)); + } + + if (userAPIKey) { + return completion([[RLMUserAPIKey alloc] initWithUserAPIKey:userAPIKey.value()], nil); + } + + return completion(nil, nil); + }); +} + +- (void)fetchAPIKey:(RLMObjectId *)objectId + completion:(RLMOptionalUserAPIKeyBlock)completion { + self.client.fetch_api_key(objectId.value, + self.currentUser, + ^(realm::util::Optional userAPIKey, + realm::util::Optional error) { + if (error && error->error_code) { + return completion(nil, RLMAppErrorToNSError(*error)); + } + + if (userAPIKey) { + return completion([[RLMUserAPIKey alloc] initWithUserAPIKey:userAPIKey.value()], nil); + } + + return completion(nil, nil); + }); +} + +- (void)fetchAPIKeysWithCompletion:(RLMUserAPIKeysBlock)completion { + self.client.fetch_api_keys(self.currentUser, + ^(const std::vector& userAPIKeys, + realm::util::Optional error) { + if (error && error->error_code) { + return completion(nil, RLMAppErrorToNSError(*error)); + } + + NSMutableArray *apiKeys = [[NSMutableArray alloc] init]; + for(auto &userAPIKey : userAPIKeys) { + [apiKeys addObject:[[RLMUserAPIKey alloc] initWithUserAPIKey:userAPIKey]]; + } + + return completion(apiKeys, nil); + }); +} + +- (void)deleteAPIKey:(RLMObjectId *)objectId + completion:(RLMAPIKeyAuthOptionalErrorBlock)completion { + self.client.delete_api_key(objectId.value, + self.currentUser, + ^(realm::util::Optional error) { + [self handleResponse:error completion:completion]; + }); +} + +- (void)enableAPIKey:(RLMObjectId *)objectId + completion:(RLMAPIKeyAuthOptionalErrorBlock)completion { + self.client.enable_api_key(objectId.value, + self.currentUser, + ^(realm::util::Optional error) { + [self handleResponse:error completion:completion]; + }); +} + +- (void)disableAPIKey:(RLMObjectId *)objectId + completion:(RLMAPIKeyAuthOptionalErrorBlock)completion { + self.client.disable_api_key(objectId.value, + self.currentUser, + ^(realm::util::Optional error) { + [self handleResponse:error completion:completion]; + }); +} + +@end diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMAccessor.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMAccessor.mm new file mode 100644 index 0000000..30e3fe1 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMAccessor.mm @@ -0,0 +1,943 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// 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 "RLMAccessor.hpp" + +#import "RLMArray_Private.hpp" +#import "RLMListBase.h" +#import "RLMObjectId_Private.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObjectStore.h" +#import "RLMObject_Private.hpp" +#import "RLMObservation.hpp" +#import "RLMProperty_Private.h" +#import "RLMRealm_Private.hpp" +#import "RLMResults_Private.hpp" +#import "RLMSchema_Private.h" +#import "RLMUtil.hpp" + +#import "results.hpp" +#import "property.hpp" + +#import +#import + +#pragma mark - Helper functions + +namespace realm { +template<> +Obj ConstObj::get(ColKey col) const { + ObjKey key = get(col); + return key ? get_target_table(col)->get_object(key) : Obj(); +} +} + +namespace { +using realm::ColKey; + +realm::Property const& get_property(__unsafe_unretained RLMObjectBase *const obj, NSUInteger index) { + return obj->_info->objectSchema->persisted_properties[index]; +} + +realm::Property const& get_property(__unsafe_unretained RLMObjectBase *const obj, + __unsafe_unretained RLMProperty *const prop) { + if (prop.linkOriginPropertyName) { + return obj->_info->objectSchema->computed_properties[prop.index]; + } + return obj->_info->objectSchema->persisted_properties[prop.index]; +} + +template +bool is_null(T const& v) { + return !v; +} +template<> +bool is_null(realm::Timestamp const& v) { + return v.is_null(); +} +template<> +bool is_null(realm::ObjectId const&) { + return false; +} +template<> +bool is_null(realm::Decimal128 const& v) { + return v.is_null(); +} + +template +T get(__unsafe_unretained RLMObjectBase *const obj, NSUInteger index) { + RLMVerifyAttached(obj); + return obj->_row.get(get_property(obj, index).column_key); +} + +template +id getBoxed(__unsafe_unretained RLMObjectBase *const obj, NSUInteger index) { + RLMVerifyAttached(obj); + auto& prop = get_property(obj, index); + RLMAccessorContext ctx(obj, &prop); + auto value = obj->_row.get(prop.column_key); + return is_null(value) ? nil : ctx.box(std::move(value)); +} + +template +void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key, T val) { + obj->_row.set(key, val); +} + +void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key, + __unsafe_unretained NSString *const val) { + RLMTranslateError([&] { + obj->_row.set(key, RLMStringDataWithNSString(val)); + }); +} + +[[gnu::noinline]] +void setNull(realm::Obj& row, ColKey key) { + RLMTranslateError([&] { row.set_null(key); }); +} + +void setValue(__unsafe_unretained RLMObjectBase *const obj, + ColKey key, __unsafe_unretained NSDate *const date) { + if (date) { + obj->_row.set(key, RLMTimestampForNSDate(date)); + } + else { + setNull(obj->_row, key); + } +} + +void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key, + __unsafe_unretained NSData *const data) { + RLMTranslateError([&] { + obj->_row.set(key, RLMBinaryDataForNSData(data)); + }); +} + +void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key, + __unsafe_unretained RLMObjectBase *const val) { + if (!val) { + obj->_row.set(key, realm::null()); + return; + } + + if (!val->_row) { + RLMAccessorContext{obj, key}.createObject(val, {.create = true}, false, {}); + } + + // make sure it is the correct type + auto table = val->_row.get_table(); + if (table != obj->_row.get_table()->get_link_target(key)) { + @throw RLMException(@"Can't set object of type '%@' to property of type '%@'", + val->_objectSchema.className, + obj->_info->propertyForTableColumn(key).objectClassName); + } + if (!table->is_embedded()) { + obj->_row.set(key, val->_row.get_key()); + } + else if (obj->_row.get_linked_object(key).get_key() != val->_row.get_key()) { + @throw RLMException(@"Can't set link to existing managed embedded object"); + } +} + +// array getter/setter +RLMArray *getArray(__unsafe_unretained RLMObjectBase *const obj, NSUInteger propIndex) { + RLMVerifyAttached(obj); + auto prop = obj->_info->rlmObjectSchema.properties[propIndex]; + return [[RLMManagedArray alloc] initWithParent:obj property:prop]; +} + +void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key, + __unsafe_unretained id const value) { + auto prop = obj->_info->propertyForTableColumn(key); + RLMValidateValueForProperty(value, obj->_info->rlmObjectSchema, prop, true); + + realm::List list(obj->_realm->_realm, obj->_row, key); + RLMClassInfo *info = obj->_info; + if (list.get_type() == realm::PropertyType::Object) { + info = &obj->_info->linkTargetType(prop.index); + } + RLMAccessorContext ctx(*info); + RLMTranslateError([&] { + list.assign(ctx, value, realm::CreatePolicy::ForceCreate); + }); +} + +void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key, + __unsafe_unretained NSNumber *const intObject) { + if (intObject) { + obj->_row.set(key, intObject.longLongValue); + } + else { + setNull(obj->_row, key); + } +} + +void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key, + __unsafe_unretained NSNumber *const floatObject) { + if (floatObject) { + obj->_row.set(key, floatObject.floatValue); + } + else { + setNull(obj->_row, key); + } +} + +void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key, + __unsafe_unretained NSNumber *const doubleObject) { + if (doubleObject) { + obj->_row.set(key, doubleObject.doubleValue); + } + else { + setNull(obj->_row, key); + } +} + +void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key, + __unsafe_unretained NSNumber *const boolObject) { + if (boolObject) { + obj->_row.set(key, (bool)boolObject.boolValue); + } + else { + setNull(obj->_row, key); + } +} + +void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key, + __unsafe_unretained RLMDecimal128 *const value) { + if (value) { + obj->_row.set(key, value.decimal128Value); + } + else { + setNull(obj->_row, key); + } +} + +void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key, + __unsafe_unretained RLMObjectId *const value) { + if (value) { + obj->_row.set(key, value.value); + } + else { + setNull(obj->_row, key); + } +} + +RLMLinkingObjects *getLinkingObjects(__unsafe_unretained RLMObjectBase *const obj, + __unsafe_unretained RLMProperty *const property) { + RLMVerifyAttached(obj); + auto& objectInfo = obj->_realm->_info[property.objectClassName]; + auto& linkOrigin = obj->_info->objectSchema->computed_properties[property.index].link_origin_property_name; + auto linkingProperty = objectInfo.objectSchema->property_for_name(linkOrigin); + auto backlinkView = obj->_row.get_backlink_view(objectInfo.table(), linkingProperty->column_key); + realm::Results results(obj->_realm->_realm, std::move(backlinkView)); + return [RLMLinkingObjects resultsWithObjectInfo:objectInfo results:std::move(results)]; +} + +// any getter/setter +template +id makeGetter(NSUInteger index) { + return ^(__unsafe_unretained RLMObjectBase *const obj) { + return static_cast(get(obj, index)); + }; +} + +template +id makeBoxedGetter(NSUInteger index) { + return ^(__unsafe_unretained RLMObjectBase *const obj) { + return getBoxed(obj, index); + }; +} +template +id makeOptionalGetter(NSUInteger index) { + return ^(__unsafe_unretained RLMObjectBase *const obj) { + return getBoxed>(obj, index); + }; +} +template +id makeNumberGetter(NSUInteger index, bool boxed, bool optional) { + if (optional) { + return makeOptionalGetter(index); + } + if (boxed) { + return makeBoxedGetter(index); + } + return makeGetter(index); +} +template +id makeWrapperGetter(NSUInteger index, bool optional) { + if (optional) { + return makeOptionalGetter(index); + } + return makeBoxedGetter(index); +} + +// dynamic getter with column closure +id managedGetter(RLMProperty *prop, const char *type) { + NSUInteger index = prop.index; + if (prop.array && prop.type != RLMPropertyTypeLinkingObjects) { + return ^id(__unsafe_unretained RLMObjectBase *const obj) { + return getArray(obj, index); + }; + } + + bool boxed = *type == '@'; + switch (prop.type) { + case RLMPropertyTypeInt: + if (prop.optional || boxed) { + return makeNumberGetter(index, boxed, prop.optional); + } + switch (*type) { + case 'c': return makeGetter(index); + case 's': return makeGetter(index); + case 'i': return makeGetter(index); + case 'l': return makeGetter(index); + case 'q': return makeGetter(index); + default: + @throw RLMException(@"Unexpected property type for Objective-C type code"); + } + case RLMPropertyTypeFloat: + return makeNumberGetter(index, boxed, prop.optional); + case RLMPropertyTypeDouble: + return makeNumberGetter(index, boxed, prop.optional); + case RLMPropertyTypeBool: + return makeNumberGetter(index, boxed, prop.optional); + case RLMPropertyTypeString: + return makeBoxedGetter(index); + case RLMPropertyTypeDate: + return makeBoxedGetter(index); + case RLMPropertyTypeData: + return makeBoxedGetter(index); + case RLMPropertyTypeObject: + return makeBoxedGetter(index); + case RLMPropertyTypeDecimal128: + return makeBoxedGetter(index); + case RLMPropertyTypeObjectId: + return makeWrapperGetter(index, prop.optional); + case RLMPropertyTypeAny: + @throw RLMException(@"Cannot create accessor class for schema with Mixed properties"); + case RLMPropertyTypeLinkingObjects: + return ^(__unsafe_unretained RLMObjectBase *const obj) { + return getLinkingObjects(obj, prop); + }; + } +} + +template +id makeSetter(__unsafe_unretained RLMProperty *const prop) { + NSUInteger index = prop.index; + NSString *name = prop.name; + if (prop.isPrimary) { + return ^(__unused RLMObjectBase *obj, __unused ArgType val) { + @throw RLMException(@"Primary key can't be changed after an object is inserted."); + }; + } + + return ^(__unsafe_unretained RLMObjectBase *const obj, ArgType val) { + RLMVerifyInWriteTransaction(obj); + RLMObservationTracker tracker(obj->_realm); + tracker.willChange(RLMGetObservationInfo(obj->_observationInfo, obj->_row.get_key(), *obj->_info), name); + if constexpr (std::is_same_v) { + tracker.trackDeletions(); + } + setValue(obj, get_property(obj, index).column_key, static_cast(val)); + }; +} + +// dynamic setter with column closure +id managedSetter(RLMProperty *prop, const char *type) { + if (prop.array && prop.type != RLMPropertyTypeLinkingObjects) { + return makeSetter>(prop); + } + + bool boxed = prop.optional || *type == '@'; + switch (prop.type) { + case RLMPropertyTypeInt: + if (boxed) { + return makeSetter *>(prop); + } + switch (*type) { + case 'c': return makeSetter(prop); + case 's': return makeSetter(prop); + case 'i': return makeSetter(prop); + case 'l': return makeSetter(prop); + case 'q': return makeSetter(prop); + default: + @throw RLMException(@"Unexpected property type for Objective-C type code"); + } + case RLMPropertyTypeFloat: + return boxed ? makeSetter *>(prop) : makeSetter(prop); + case RLMPropertyTypeDouble: + return boxed ? makeSetter *>(prop) : makeSetter(prop); + case RLMPropertyTypeBool: + return boxed ? makeSetter *>(prop) : makeSetter(prop); + case RLMPropertyTypeString: return makeSetter(prop); + case RLMPropertyTypeDate: return makeSetter(prop); + case RLMPropertyTypeData: return makeSetter(prop); + case RLMPropertyTypeAny: return nil; + case RLMPropertyTypeLinkingObjects: return nil; + case RLMPropertyTypeObject: return makeSetter(prop); + case RLMPropertyTypeObjectId: return makeSetter(prop); + case RLMPropertyTypeDecimal128: return makeSetter(prop); + } +} + +// call getter for superclass for property at key +id superGet(RLMObjectBase *obj, NSString *propName) { + typedef id (*getter_type)(RLMObjectBase *, SEL); + RLMProperty *prop = obj->_objectSchema[propName]; + Class superClass = class_getSuperclass(obj.class); + getter_type superGetter = (getter_type)[superClass instanceMethodForSelector:prop.getterSel]; + return superGetter(obj, prop.getterSel); +} + +// call setter for superclass for property at key +void superSet(RLMObjectBase *obj, NSString *propName, id val) { + typedef void (*setter_type)(RLMObjectBase *, SEL, RLMArray *ar); + RLMProperty *prop = obj->_objectSchema[propName]; + Class superClass = class_getSuperclass(obj.class); + setter_type superSetter = (setter_type)[superClass instanceMethodForSelector:prop.setterSel]; + superSetter(obj, prop.setterSel, val); +} + +// getter/setter for unmanaged object +id unmanagedGetter(RLMProperty *prop, const char *) { + // only override getters for RLMArray and linking objects properties + if (prop.type == RLMPropertyTypeLinkingObjects) { + return ^(RLMObjectBase *) { return [RLMResults emptyDetachedResults]; }; + } + if (prop.array) { + NSString *propName = prop.name; + if (prop.type == RLMPropertyTypeObject) { + NSString *objectClassName = prop.objectClassName; + return ^(RLMObjectBase *obj) { + id val = superGet(obj, propName); + if (!val) { + val = [[RLMArray alloc] initWithObjectClassName:objectClassName]; + superSet(obj, propName, val); + } + return val; + }; + } + auto type = prop.type; + auto optional = prop.optional; + return ^(RLMObjectBase *obj) { + id val = superGet(obj, propName); + if (!val) { + val = [[RLMArray alloc] initWithObjectType:type optional:optional]; + superSet(obj, propName, val); + } + return val; + }; + } + return nil; +} + +id unmanagedSetter(RLMProperty *prop, const char *) { + // Only RLMArray needs special handling for the unmanaged setter + if (!prop.array) { + return nil; + } + + NSString *propName = prop.name; + return ^(RLMObjectBase *obj, id values) { + auto prop = obj->_objectSchema[propName]; + RLMValidateValueForProperty(values, obj->_objectSchema, prop, true); + + // make copy when setting (as is the case for all other variants) + RLMArray *ar; + if (prop.type == RLMPropertyTypeObject) + ar = [[RLMArray alloc] initWithObjectClassName:prop.objectClassName]; + else + ar = [[RLMArray alloc] initWithObjectType:prop.type optional:prop.optional]; + [ar addObjects:values]; + superSet(obj, propName, ar); + }; +} + +void addMethod(Class cls, __unsafe_unretained RLMProperty *const prop, + id (*getter)(RLMProperty *, const char *), + id (*setter)(RLMProperty *, const char *)) { + SEL sel = prop.getterSel; + auto getterMethod = class_getInstanceMethod(cls, sel); + if (!getterMethod) { + return; + } + + const char *getterType = method_getTypeEncoding(getterMethod); + if (id block = getter(prop, getterType)) { + class_addMethod(cls, sel, imp_implementationWithBlock(block), getterType); + } + + if (!(sel = prop.setterSel)) { + return; + } + auto setterMethod = class_getInstanceMethod(cls, sel); + if (!setterMethod) { + return; + } + if (id block = setter(prop, getterType)) { // note: deliberately getterType as it's easier to grab the relevant type from + class_addMethod(cls, sel, imp_implementationWithBlock(block), method_getTypeEncoding(setterMethod)); + } +} + +Class createAccessorClass(Class objectClass, + RLMObjectSchema *schema, + const char *accessorClassName, + id (*getterGetter)(RLMProperty *, const char *), + id (*setterGetter)(RLMProperty *, const char *)) { + REALM_ASSERT_DEBUG(RLMIsObjectOrSubclass(objectClass)); + + // create and register proxy class which derives from object class + Class accClass = objc_allocateClassPair(objectClass, accessorClassName, 0); + if (!accClass) { + // Class with that name already exists, so just return the pre-existing one + // This should only happen for our standalone "accessors" + return objc_lookUpClass(accessorClassName); + } + + // override getters/setters for each propery + for (RLMProperty *prop in schema.properties) { + addMethod(accClass, prop, getterGetter, setterGetter); + } + for (RLMProperty *prop in schema.computedProperties) { + addMethod(accClass, prop, getterGetter, setterGetter); + } + + objc_registerClassPair(accClass); + + return accClass; +} +} // anonymous namespace + +#pragma mark - Public Interface + +Class RLMManagedAccessorClassForObjectClass(Class objectClass, RLMObjectSchema *schema, const char *name) { + return createAccessorClass(objectClass, schema, name, managedGetter, managedSetter); +} + +Class RLMUnmanagedAccessorClassForObjectClass(Class objectClass, RLMObjectSchema *schema) { + return createAccessorClass(objectClass, schema, + [@"RLM:Unmanaged " stringByAppendingString:schema.className].UTF8String, + unmanagedGetter, unmanagedSetter); +} + +// implement the class method className on accessors to return the className of the +// base object +void RLMReplaceClassNameMethod(Class accessorClass, NSString *className) { + Class metaClass = object_getClass(accessorClass); + IMP imp = imp_implementationWithBlock(^(Class){ return className; }); + class_addMethod(metaClass, @selector(className), imp, "@@:"); +} + +// implement the shared schema method +void RLMReplaceSharedSchemaMethod(Class accessorClass, RLMObjectSchema *schema) { + Class metaClass = object_getClass(accessorClass); + IMP imp = imp_implementationWithBlock(^(Class cls) { + if (cls == accessorClass) { + return schema; + } + + // If we aren't being called directly on the class this was overriden + // for, the class is either a subclass which we haven't initialized yet, + // or it's a runtime-generated class which should use the parent's + // schema. We check for the latter by checking if the immediate + // descendent of the desired class is a class generated by us (there + // may be further subclasses not generated by us for things like KVO). + Class parent = class_getSuperclass(cls); + while (parent != accessorClass) { + cls = parent; + parent = class_getSuperclass(cls); + } + + static const char accessorClassPrefix[] = "RLM:"; + if (!strncmp(class_getName(cls), accessorClassPrefix, sizeof(accessorClassPrefix) - 1)) { + return schema; + } + + return [RLMSchema sharedSchemaForClass:cls]; + }); + class_addMethod(metaClass, @selector(sharedSchema), imp, "@@:"); +} + +void RLMDynamicValidatedSet(RLMObjectBase *obj, NSString *propName, id val) { + RLMVerifyAttached(obj); + RLMObjectSchema *schema = obj->_objectSchema; + RLMProperty *prop = schema[propName]; + if (!prop) { + @throw RLMException(@"Invalid property name '%@' for class '%@'.", + propName, obj->_objectSchema.className); + } + if (prop.isPrimary) { + @throw RLMException(@"Primary key can't be changed to '%@' after an object is inserted.", val); + } + + // Because embedded objects cannot be created directly, we accept anything + // that can be converted to an embedded object for dynamic link set operations. + bool is_embedded = prop.type == RLMPropertyTypeObject && obj->_info->linkTargetType(prop.index).objectSchema->is_embedded; + RLMValidateValueForProperty(val, schema, prop, !is_embedded); + RLMDynamicSet(obj, prop, RLMCoerceToNil(val)); +} + +// Precondition: the property is not a primary key +void RLMDynamicSet(__unsafe_unretained RLMObjectBase *const obj, + __unsafe_unretained RLMProperty *const prop, + __unsafe_unretained id const val) { + REALM_ASSERT_DEBUG(!prop.isPrimary); + realm::Object o(obj->_info->realm->_realm, *obj->_info->objectSchema, obj->_row); + RLMAccessorContext c(obj); + RLMTranslateError([&] { + o.set_property_value(c, get_property(obj, prop).name, val ?: NSNull.null); + }); +} + +id RLMDynamicGet(__unsafe_unretained RLMObjectBase *const obj, __unsafe_unretained RLMProperty *const prop) { + realm::Object o(obj->_realm->_realm, *obj->_info->objectSchema, obj->_row); + RLMAccessorContext c(obj); + c.currentProperty = prop; + return RLMTranslateError([&] { + return RLMCoerceToNil(o.get_property_value(c, get_property(obj, prop))); + }); +} + +id RLMDynamicGetByName(__unsafe_unretained RLMObjectBase *const obj, + __unsafe_unretained NSString *const propName) { + RLMProperty *prop = obj->_objectSchema[propName]; + if (!prop) { + @throw RLMException(@"Invalid property name '%@' for class '%@'.", + propName, obj->_objectSchema.className); + } + return RLMDynamicGet(obj, prop); +} + +RLMAccessorContext::~RLMAccessorContext() = default; + +RLMAccessorContext::RLMAccessorContext(RLMAccessorContext& parent, realm::Obj const& obj, + realm::Property const& property) +: _realm(parent._realm) +, _info(property.type == realm::PropertyType::Object ? parent._info.linkTargetType(property) : parent._info) +, _parentObject(obj) +, _parentObjectInfo(&parent._info) +, _colKey(property.column_key) +{ +} + +RLMAccessorContext::RLMAccessorContext(RLMClassInfo& info) +: _realm(info.realm), _info(info) +{ +} + +RLMAccessorContext::RLMAccessorContext(__unsafe_unretained RLMObjectBase *const parent, + const realm::Property *prop) +: _realm(parent->_realm) +, _info(prop && prop->type == realm::PropertyType::Object ? parent->_info->linkTargetType(*prop) + : *parent->_info) +, _parentObjectInfo(parent->_info) +{ +} + +RLMAccessorContext::RLMAccessorContext(__unsafe_unretained RLMObjectBase *const parent, + realm::ColKey col) +: _realm(parent->_realm) +, _info(_realm->_info[parent->_info->propertyForTableColumn(col).objectClassName]) +, _parentObject(parent->_row) +, _parentObjectInfo(parent->_info) +, _colKey(col) +{ +} + +id RLMAccessorContext::defaultValue(__unsafe_unretained NSString *const key) { + if (!_defaultValues) { + _defaultValues = RLMDefaultValuesForObjectSchema(_info.rlmObjectSchema); + } + return _defaultValues[key]; +} + +id RLMAccessorContext::propertyValue(__unsafe_unretained id const obj, size_t propIndex, + __unsafe_unretained RLMProperty *const prop) { + // Property value from an NSArray + if ([obj respondsToSelector:@selector(objectAtIndex:)]) { + return propIndex < [obj count] ? [obj objectAtIndex:propIndex] : nil; + } + + // Property value from an NSDictionary + if ([obj respondsToSelector:@selector(objectForKey:)]) { + return [obj objectForKey:prop.name]; + } + + // Property value from an instance of this object type + id value; + if ([obj isKindOfClass:_info.rlmObjectSchema.objectClass] && prop.swiftIvar) { + if (prop.array) { + return static_cast(object_getIvar(obj, prop.swiftIvar))._rlmArray; + } + else { // optional + value = RLMGetOptional(static_cast(object_getIvar(obj, prop.swiftIvar))); + } + } + else { + // Property value from some object that's KVC-compatible + value = RLMValidatedValueForProperty(obj, [obj respondsToSelector:prop.getterSel] ? prop.getterName : prop.name, + _info.rlmObjectSchema.className); + } + return value ?: NSNull.null; +} + +realm::Obj RLMAccessorContext::create_embedded_object() { + if (!_parentObject) { + @throw RLMException(@"Embedded objects cannot be created directly"); + } + return _parentObject.create_and_set_linked_object(_colKey); +} + +id RLMAccessorContext::box(realm::List&& l) { + REALM_ASSERT(_parentObjectInfo); + REALM_ASSERT(currentProperty); + return [[RLMManagedArray alloc] initWithList:std::move(l) + parentInfo:_parentObjectInfo + property:currentProperty]; +} + +id RLMAccessorContext::box(realm::Object&& o) { + REALM_ASSERT(currentProperty); + return RLMCreateObjectAccessor(_info.linkTargetType(currentProperty.index), o.obj()); +} + +id RLMAccessorContext::box(realm::Obj&& r) { + return RLMCreateObjectAccessor(_info, std::move(r)); +} + +id RLMAccessorContext::box(realm::Results&& r) { + REALM_ASSERT(currentProperty); + return [RLMResults resultsWithObjectInfo:_realm->_info[currentProperty.objectClassName] + results:std::move(r)]; +} + +using realm::ObjKey; +using realm::CreatePolicy; + +template<> +realm::Timestamp RLMAccessorContext::unbox(__unsafe_unretained id const value, CreatePolicy, ObjKey) { + id v = RLMCoerceToNil(value); + return RLMTimestampForNSDate(v); +} + +template<> +bool RLMAccessorContext::unbox(__unsafe_unretained id const v, CreatePolicy, ObjKey) { + return [v boolValue]; +} +template<> +double RLMAccessorContext::unbox(__unsafe_unretained id const v, CreatePolicy, ObjKey) { + return [v doubleValue]; +} +template<> +float RLMAccessorContext::unbox(__unsafe_unretained id const v, CreatePolicy, ObjKey) { + return [v floatValue]; +} +template<> +long long RLMAccessorContext::unbox(__unsafe_unretained id const v, CreatePolicy, ObjKey) { + return [v longLongValue]; +} +template<> +realm::BinaryData RLMAccessorContext::unbox(id v, CreatePolicy, ObjKey) { + v = RLMCoerceToNil(v); + return RLMBinaryDataForNSData(v); +} +template<> +realm::StringData RLMAccessorContext::unbox(id v, CreatePolicy, ObjKey) { + v = RLMCoerceToNil(v); + return RLMStringDataWithNSString(v); +} +template<> +realm::Decimal128 RLMAccessorContext::unbox(id v, CreatePolicy, ObjKey) { + return RLMObjcToDecimal128(v); +} +template<> +realm::ObjectId RLMAccessorContext::unbox(id v, CreatePolicy, ObjKey) { + return static_cast(v).value; +} + +template +static auto to_optional(__unsafe_unretained id const value, Fn&& fn) { + id v = RLMCoerceToNil(value); + return v && v != NSNull.null ? realm::util::make_optional(fn(v)) : realm::util::none; +} + +template<> +realm::util::Optional RLMAccessorContext::unbox(__unsafe_unretained id const v, CreatePolicy, ObjKey) { + return to_optional(v, [&](__unsafe_unretained id v) { return (bool)[v boolValue]; }); +} +template<> +realm::util::Optional RLMAccessorContext::unbox(__unsafe_unretained id const v, CreatePolicy, ObjKey) { + return to_optional(v, [&](__unsafe_unretained id v) { return [v doubleValue]; }); +} +template<> +realm::util::Optional RLMAccessorContext::unbox(__unsafe_unretained id const v, CreatePolicy, ObjKey) { + return to_optional(v, [&](__unsafe_unretained id v) { return [v floatValue]; }); +} +template<> +realm::util::Optional RLMAccessorContext::unbox(__unsafe_unretained id const v, CreatePolicy, ObjKey) { + return to_optional(v, [&](__unsafe_unretained id v) { return [v longLongValue]; }); +} +template<> +realm::util::Optional RLMAccessorContext::unbox(__unsafe_unretained id const v, CreatePolicy, ObjKey) { + return to_optional(v, [&](__unsafe_unretained RLMObjectId *v) { return v.value; }); +} + +std::pair +RLMAccessorContext::createObject(id value, realm::CreatePolicy policy, + bool forceCreate, ObjKey existingKey) { + if (!value || value == NSNull.null) { + @throw RLMException(@"Must provide a non-nil value."); + } + + if ([value isKindOfClass:[NSArray class]] && [value count] > _info.objectSchema->persisted_properties.size()) { + @throw RLMException(@"Invalid array input: more values (%llu) than properties (%llu).", + (unsigned long long)[value count], + (unsigned long long)_info.objectSchema->persisted_properties.size()); + } + + RLMObjectBase *objBase = RLMDynamicCast(value); + realm::Obj obj, *outObj = nullptr; + if (objBase) { + if (objBase.isInvalidated) { + if (policy.create && !policy.copy) { + @throw RLMException(@"Adding a deleted or invalidated object to a Realm is not permitted"); + } + else { + @throw RLMException(@"Object has been deleted or invalidated."); + } + } + if (policy.copy) { + if (policy.update || !forceCreate) { + // create(update: true) is a no-op when given an object already in + // the Realm which is of the correct type + if (objBase->_realm == _realm && objBase->_row.get_table() == _info.table() && !_info.table()->is_embedded()) { + return {objBase->_row, true}; + } + } + // Otherwise we copy the object + objBase = nil; + } + else { + outObj = &objBase->_row; + // add() on an object already managed by this Realm is a no-op + if (objBase->_realm == _realm) { + return {objBase->_row, true}; + } + if (!policy.create) { + return {realm::Obj(), false}; + } + if (objBase->_realm) { + @throw RLMException(@"Object is already managed by another Realm. Use create instead to copy it into this Realm."); + } + if (objBase->_observationInfo && objBase->_observationInfo->hasObservers()) { + @throw RLMException(@"Cannot add an object with observers to a Realm"); + } + + REALM_ASSERT([objBase->_objectSchema.className isEqualToString:_info.rlmObjectSchema.className]); + REALM_ASSERT([objBase isKindOfClass:_info.rlmObjectSchema.unmanagedClass]); + + objBase->_info = &_info; + objBase->_realm = _realm; + } + } + if (!policy.create) { + return {realm::Obj(), false}; + } + if (!outObj) { + outObj = &obj; + } + + try { + realm::Object::create(*this, _realm->_realm, *_info.objectSchema, + (id)value, policy, existingKey, outObj).obj(); + } + catch (std::exception const& e) { + @throw RLMException(e); + } + + if (objBase) { + for (RLMProperty *prop in _info.rlmObjectSchema.properties) { + // set the ivars for object and array properties to nil as otherwise the + // accessors retain objects that are no longer accessible via the properties + // this is mainly an issue when the object graph being added has cycles, + // as it's not obvious that the user has to set the *ivars* to nil to + // avoid leaking memory + if (prop.type == RLMPropertyTypeObject && !prop.swiftIvar) { + ((void(*)(id, SEL, id))objc_msgSend)(objBase, prop.setterSel, nil); + } + } + + object_setClass(objBase, _info.rlmObjectSchema.accessorClass); + RLMInitializeSwiftAccessorGenerics(objBase); + } + return {*outObj, false}; +} + +template<> +realm::Obj RLMAccessorContext::unbox(__unsafe_unretained id const v, CreatePolicy policy, ObjKey key) { + return createObject(v, policy, false, key).first; +} + +void RLMAccessorContext::will_change(realm::Obj const& row, realm::Property const& prop) { + auto obsInfo = RLMGetObservationInfo(nullptr, row.get_key(), _info); + if (!_observationHelper) { + if (obsInfo || prop.type == realm::PropertyType::Object) { + _observationHelper = std::make_unique(_info.realm); + } + } + if (_observationHelper) { + _observationHelper->willChange(obsInfo, _info.propertyForTableColumn(prop.column_key).name); + if (prop.type == realm::PropertyType::Object) { + _observationHelper->trackDeletions(); + } + } +} + +void RLMAccessorContext::did_change() { + if (_observationHelper) { + _observationHelper->didChange(); + } +} + +RLMOptionalId RLMAccessorContext::value_for_property(__unsafe_unretained id const obj, + realm::Property const&, size_t propIndex) { + auto prop = _info.rlmObjectSchema.properties[propIndex]; + id value = propertyValue(obj, propIndex, prop); + if (value) { + RLMValidateValueForProperty(value, _info.rlmObjectSchema, prop); + } + + return RLMOptionalId{value}; +} + +RLMOptionalId RLMAccessorContext::default_value_for_property(realm::ObjectSchema const&, + realm::Property const& prop) +{ + return RLMOptionalId{defaultValue(@(prop.name.c_str()))}; +} + +bool RLMAccessorContext::is_same_list(realm::List const& list, __unsafe_unretained id const v) const noexcept { + return [v respondsToSelector:@selector(isBackedByList:)] && [v isBackedByList:list]; +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wincomplete-implementation" +@implementation RLMManagedPropertyAccessor +@end +#pragma clang diagnostic pop diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMAnalytics.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMAnalytics.mm new file mode 100644 index 0000000..b778bfc --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMAnalytics.mm @@ -0,0 +1,259 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// 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. +// +//////////////////////////////////////////////////////////////////////////// + +// Asynchronously submits build information to Realm if running in an iOS +// simulator or on OS X if a debugger is attached. Does nothing if running on an +// iOS / watchOS device or if a debugger is *not* attached. +// +// To be clear: this does *not* run when your app is in production or on +// your end-user’s devices; it will only run in the simulator or when a debugger +// is attached. +// +// Why are we doing this? In short, because it helps us build a better product +// for you. None of the data personally identifies you, your employer or your +// app, but it *will* help us understand what language you use, what iOS +// versions you target, etc. Having this info will help prioritizing our time, +// adding new features and deprecating old features. Collecting an anonymized +// bundle & anonymized MAC is the only way for us to count actual usage of the +// other metrics accurately. If we don’t have a way to deduplicate the info +// reported, it will be useless, as a single developer building their Swift app +// 10 times would report 10 times more than a single Objective-C developer that +// only builds once, making the data all but useless. +// No one likes sharing data unless it’s necessary, we get it, and we’ve +// debated adding this for a long long time. Since Realm is a free product +// without an email signup, we feel this is a necessary step so we can collect +// relevant data to build a better product for you. If you truly, absolutely +// feel compelled to not send this data back to Realm, then you can set an env +// variable named REALM_DISABLE_ANALYTICS. Since Realm is free we believe +// letting these analytics run is a small price to pay for the product & support +// we give you. +// +// Currently the following information is reported: +// - What version of Realm is being used, and from which language (obj-c or Swift). +// - What version of OS X it's running on (in case Xcode aggressively drops +// support for older versions again, we need to know what we need to support). +// - The minimum iOS/OS X version that the application is targeting (again, to +// help us decide what versions we need to support). +// - An anonymous MAC address and bundle ID to aggregate the other information on. +// - What version of Swift is being used (if applicable). + +#import "RLMAnalytics.hpp" + +#import + +#if TARGET_IPHONE_SIMULATOR || TARGET_OS_MAC || (TARGET_OS_WATCH && TARGET_OS_SIMULATOR) || (TARGET_OS_TV && TARGET_OS_SIMULATOR) +#import "RLMRealm.h" +#import "RLMUtil.hpp" + +#import +#import +#import +#import +#import + +#import + +#ifndef REALM_COCOA_VERSION +#import "RLMVersion.h" +#endif + +#if REALM_ENABLE_SYNC +#import +#endif + +// Declared for RealmSwiftObjectUtil +@interface NSObject (SwiftVersion) ++ (NSString *)swiftVersion; +@end + +// Wrapper for sysctl() that handles the memory management stuff +static auto RLMSysCtl(int *mib, u_int mibSize, size_t *bufferSize) { + std::unique_ptr buffer(nullptr, &free); + + int ret = sysctl(mib, mibSize, nullptr, bufferSize, nullptr, 0); + if (ret != 0) { + return buffer; + } + + buffer.reset(malloc(*bufferSize)); + if (!buffer) { + return buffer; + } + + ret = sysctl(mib, mibSize, buffer.get(), bufferSize, nullptr, 0); + if (ret != 0) { + buffer.reset(); + } + + return buffer; +} + +// Get the version of OS X we're running on (even in the simulator this gives +// the OS X version and not the simulated iOS version) +static NSString *RLMOSVersion() { + std::array mib = {{CTL_KERN, KERN_OSRELEASE}}; + size_t bufferSize; + auto buffer = RLMSysCtl(&mib[0], mib.size(), &bufferSize); + if (!buffer) { + return nil; + } + + return [[NSString alloc] initWithBytesNoCopy:buffer.release() + length:bufferSize - 1 + encoding:NSUTF8StringEncoding + freeWhenDone:YES]; +} + +// Hash the data in the given buffer and convert it to a hex-format string +static NSString *RLMHashData(const void *bytes, size_t length) { + unsigned char buffer[CC_SHA256_DIGEST_LENGTH]; + CC_SHA256(bytes, static_cast(length), buffer); + + char formatted[CC_SHA256_DIGEST_LENGTH * 2 + 1]; + for (int i = 0; i < CC_SHA256_DIGEST_LENGTH; ++i) { + sprintf(formatted + i * 2, "%02x", buffer[i]); + } + + return [[NSString alloc] initWithBytes:formatted + length:CC_SHA256_DIGEST_LENGTH * 2 + encoding:NSUTF8StringEncoding]; +} + +// Returns the hash of the MAC address of the first network adaptor since the +// vendorIdentifier isn't constant between iOS simulators. +static NSString *RLMMACAddress() { + int en0 = static_cast(if_nametoindex("en0")); + if (!en0) { + return nil; + } + + std::array mib = {{CTL_NET, PF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, en0}}; + size_t bufferSize; + auto buffer = RLMSysCtl(&mib[0], mib.size(), &bufferSize); + if (!buffer) { + return nil; + } + + // sockaddr_dl struct is immediately after the if_msghdr struct in the buffer + auto sockaddr = reinterpret_cast(static_cast(buffer.get()) + 1); + auto mac = reinterpret_cast(sockaddr->sdl_data + sockaddr->sdl_nlen); + + return RLMHashData(mac, 6); +} + +static NSDictionary *RLMAnalyticsPayload() { + NSBundle *appBundle = NSBundle.mainBundle; + NSString *hashedBundleID = appBundle.bundleIdentifier; + + // Main bundle isn't always the one of interest (e.g. when running tests + // it's xctest rather than the app's bundle), so look for one with a bundle ID + if (!hashedBundleID) { + for (NSBundle *bundle in NSBundle.allBundles) { + if ((hashedBundleID = bundle.bundleIdentifier)) { + appBundle = bundle; + break; + } + } + } + + // If we found a bundle ID anywhere, hash it as it could contain sensitive + // information (e.g. the name of an unnanounced product) + if (hashedBundleID) { + NSData *data = [hashedBundleID dataUsingEncoding:NSUTF8StringEncoding]; + hashedBundleID = RLMHashData(data.bytes, data.length); + } + + NSString *osVersionString = [[NSProcessInfo processInfo] operatingSystemVersionString]; + Class swiftObjectUtilClass = NSClassFromString(@"RealmSwiftObjectUtil"); + BOOL isSwift = swiftObjectUtilClass != nil; + NSString *swiftVersion = isSwift ? [swiftObjectUtilClass swiftVersion] : @"N/A"; + + static NSString *kUnknownString = @"unknown"; + NSString *hashedMACAddress = RLMMACAddress() ?: kUnknownString; + + return @{ + @"event": @"Run", + @"properties": @{ + // MixPanel properties + @"token": @"ce0fac19508f6c8f20066d345d360fd0", + + // Anonymous identifiers to deduplicate events + @"distinct_id": hashedMACAddress, + @"Anonymized MAC Address": hashedMACAddress, + @"Anonymized Bundle ID": hashedBundleID ?: kUnknownString, + + // Which version of Realm is being used + @"Binding": @"cocoa", + @"Language": isSwift ? @"swift" : @"objc", + @"Realm Version": REALM_COCOA_VERSION, +#if REALM_ENABLE_SYNC + @"Sync Version": @(REALM_SYNC_VER_STRING), +#endif +#if TARGET_OS_WATCH + @"Target OS Type": @"watchos", +#elif TARGET_OS_TV + @"Target OS Type": @"tvos", +#elif TARGET_OS_IPHONE + @"Target OS Type": @"ios", +#else + @"Target OS Type": @"osx", +#endif + @"Swift Version": swiftVersion, + // Current OS version the app is targetting + @"Target OS Version": osVersionString, + // Minimum OS version the app is targetting + @"Target OS Minimum Version": appBundle.infoDictionary[@"MinimumOSVersion"] ?: kUnknownString, + + // Host OS version being built on + @"Host OS Type": @"osx", + @"Host OS Version": RLMOSVersion() ?: kUnknownString, + +#ifdef SWIFT_PACKAGE + @"Installation Method": @"Swift Package Manager", +#elif defined(COCOAPODS) + @"Installation Method": @"CocoaPods", +#elif defined(CARTHAGE) + @"Installation Method": @"Carthage", +#elif defined(REALM_IOS_STATIC) + @"Installation Method": @"Static Framework", +#else + @"Installation Method": @"Other", +#endif + } + }; +} + +void RLMSendAnalytics() { + if (getenv("REALM_DISABLE_ANALYTICS") || !RLMIsDebuggerAttached() || RLMIsRunningInPlayground()) { + return; + } + + + NSData *payload = [NSJSONSerialization dataWithJSONObject:RLMAnalyticsPayload() options:0 error:nil]; + NSString *url = [NSString stringWithFormat:@"https://api.mixpanel.com/track/?data=%@&ip=1", [payload base64EncodedStringWithOptions:0]]; + + // No error handling or anything because logging errors annoyed people for no + // real benefit, and it's not clear what else we could do + [[NSURLSession.sharedSession dataTaskWithURL:[NSURL URLWithString:url]] resume]; +} + +#else + +void RLMSendAnalytics() {} + +#endif diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMApp.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMApp.mm new file mode 100644 index 0000000..2ba3ac9 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMApp.mm @@ -0,0 +1,375 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 "RLMApp_Private.hpp" + +#import "RLMCredentials_Private.hpp" +#import "RLMBSON_Private.hpp" +#import "RLMPushClient_Private.hpp" +#import "RLMUser_Private.hpp" +#import "RLMSyncManager_Private.hpp" +#import "RLMUtil.hpp" +#import "RLMEmailPasswordAuth.h" + +#include "sync/sync_config.hpp" +#include "sync/sync_manager.hpp" + +#if !defined(REALM_COCOA_VERSION) +#import "RLMVersion.h" +#endif + +using namespace realm; + +namespace { + /// Internal transport struct to bridge RLMNetworkingTransporting to the GenericNetworkTransport. + class CocoaNetworkTransport : public realm::app::GenericNetworkTransport { + public: + CocoaNetworkTransport(id transport) : m_transport(transport) {}; + + void send_request_to_server(const app::Request request, + std::function completion) override { + // Convert the app::Request to an RLMRequest + auto rlmRequest = [RLMRequest new]; + rlmRequest.url = @(request.url.data()); + rlmRequest.body = @(request.body.data()); + NSMutableDictionary *headers = [NSMutableDictionary new]; + for (auto header : request.headers) { + headers[@(header.first.data())] = @(header.second.data()); + } + rlmRequest.headers = headers; + rlmRequest.method = static_cast(request.method); + rlmRequest.timeout = request.timeout_ms / 1000; + + // Send the request through to the Cocoa level transport + [m_transport sendRequestToServer:rlmRequest completion:^(RLMResponse * response) { + __block std::map bridgingHeaders; + [response.headers enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, BOOL *) { + bridgingHeaders[key.UTF8String] = value.UTF8String; + }]; + + // Convert the RLMResponse to an app:Response and pass downstream to + // the object store + completion({ + .body = response.body.UTF8String, + .headers = bridgingHeaders, + .http_status_code = static_cast(response.httpStatusCode), + .custom_status_code = static_cast(response.customStatusCode) + }); + }]; + } + + id transport() const { + return m_transport; + } + private: + id m_transport; + }; +} + +@implementation RLMAppConfiguration { + realm::app::App::Config _config; +} + +- (instancetype)initWithConfig:(const realm::app::App::Config &)config { + if (self = [super init]) { + _config = config; + return self; + } + + return nil; +} + +- (instancetype)initWithBaseURL:(nullable NSString *)baseURL + transport:(nullable id)transport + localAppName:(nullable NSString *)localAppName + localAppVersion:(nullable NSString *)localAppVersion { + return [self initWithBaseURL:baseURL + transport:transport + localAppName:localAppName + localAppVersion:localAppVersion + defaultRequestTimeoutMS:6000]; +} + +- (instancetype)initWithBaseURL:(nullable NSString *)baseURL + transport:(nullable id)transport + localAppName:(NSString *)localAppName + localAppVersion:(nullable NSString *)localAppVersion + defaultRequestTimeoutMS:(NSUInteger)defaultRequestTimeoutMS { + if (self = [super init]) { + self.baseURL = baseURL; + self.transport = transport; + self.localAppName = localAppName; + self.localAppVersion = localAppVersion; + self.defaultRequestTimeoutMS = defaultRequestTimeoutMS; + + _config.platform = "Realm Cocoa"; + + RLMNSStringToStdString(_config.platform_version, [[NSProcessInfo processInfo] operatingSystemVersionString]); + RLMNSStringToStdString(_config.sdk_version, REALM_COCOA_VERSION); + return self; + } + return nil; +} + +- (realm::app::App::Config&)config { + return _config; +} + +- (void)setAppId:(NSString *)appId { + RLMNSStringToStdString(_config.app_id, appId); +} + +- (NSString *)baseURL { + if (_config.base_url) { + return @(_config.base_url->c_str()); + } + + return nil; +} + +- (void)setBaseURL:(nullable NSString *)baseURL { + std::string base_url; + RLMNSStringToStdString(base_url, baseURL); + _config.base_url = base_url.empty() ? util::none : util::Optional(base_url); + return; +} + +- (id)transport { + return static_cast(_config.transport_generator().get())->transport(); +} + +- (void)setTransport:(id)transport { + if (transport) { + _config.transport_generator = [transport]{ + return std::make_unique(transport); + }; + } else { + _config.transport_generator = []{ + return std::make_unique([RLMNetworkTransport new]); + }; + } +} + +- (NSString *)localAppName { + if (_config.local_app_name) { + return @((_config.base_url)->c_str()); + } + + return nil; +} + +- (void)setLocalAppName:(nullable NSString *)localAppName { + std::string local_app_name; + RLMNSStringToStdString(local_app_name, localAppName); + _config.local_app_name = local_app_name.empty() ? util::none : util::Optional(local_app_name); + return; +} + +- (NSString *)localAppVersion { + if (_config.local_app_version) { + return @(_config.base_url->c_str()); + } + + return nil; +} + +- (void)setLocalAppVersion:(nullable NSString *)localAppVersion { + std::string local_app_version; + RLMNSStringToStdString(local_app_version, localAppVersion); + _config.local_app_version = local_app_version.empty() ? util::none : util::Optional(local_app_version); + return; +} + +- (NSUInteger)defaultRequestTimeoutMS { + return _config.default_request_timeout_ms.value_or(6000U); +} + +- (void)setDefaultRequestTimeoutMS:(NSUInteger)defaultRequestTimeoutMS { + _config.default_request_timeout_ms = (uint64_t)defaultRequestTimeoutMS; +} + +@end + +NSError *RLMAppErrorToNSError(realm::app::AppError const& appError) { + return [[NSError alloc] initWithDomain:@(appError.error_code.category().name()) + code:appError.error_code.value() + userInfo:@{ + @(appError.error_code.category().name()) : @(appError.error_code.message().data()), + NSLocalizedDescriptionKey : @(appError.message.c_str()) + }]; +} + +@interface RLMApp() { + std::shared_ptr _app; + __weak id _authorizationDelegate API_AVAILABLE(ios(13.0), macos(10.15), tvos(13.0), watchos(6.0)); +} + +@end + +@implementation RLMApp : NSObject + +- (instancetype)initWithApp:(std::shared_ptr)app { + if (self = [super init]) { + _configuration = [[RLMAppConfiguration alloc] initWithConfig:app->config()]; + _app = app; + _syncManager = [[RLMSyncManager alloc] initWithSyncManager:_app->sync_manager()]; + return self; + } + + return nil; +} + +- (instancetype)initWithId:(NSString *)appId + configuration:(RLMAppConfiguration *)configuration + rootDirectory:(NSURL *)rootDirectory { + if ([appId length] == 0) { + @throw RLMException(@"AppId cannot be an empty string"); + } + + if (self = [super init]) { + if (!configuration) { + configuration = [[RLMAppConfiguration alloc] initWithBaseURL:nil + transport:nil + localAppName:nil + localAppVersion:nil]; + } + _configuration = configuration; + [_configuration setAppId:appId]; + + _app = RLMTranslateError([&] { + return app::App::get_shared_app(configuration.config, + [RLMSyncManager configurationWithRootDirectory:rootDirectory appId:appId]); + }); + + _syncManager = [[RLMSyncManager alloc] initWithSyncManager:_app->sync_manager()]; + return self; + } + return nil; +} + ++ (instancetype)appWithId:(NSString *)appId + configuration:(RLMAppConfiguration *)configuration + rootDirectory:(NSURL *)rootDirectory { + static NSMutableDictionary *s_apps = [NSMutableDictionary new]; + // protects the app cache + static std::mutex& initLock = *new std::mutex(); + std::lock_guard lock(initLock); + + if (RLMApp *app = s_apps[appId]) { + return app; + } + + RLMApp *app = [[RLMApp alloc] initWithId:appId configuration:configuration rootDirectory:rootDirectory]; + s_apps[appId] = app; + return app; +} + ++ (instancetype)appWithId:(NSString *)appId configuration:(RLMAppConfiguration *)configuration { + return [self appWithId:appId configuration:configuration rootDirectory:nil]; +} + ++ (instancetype)appWithId:(NSString *)appId { + return [self appWithId:appId configuration:nil]; +} + +- (std::shared_ptr)_realmApp { + return _app; +} + +- (NSDictionary *)allUsers { + NSMutableDictionary *buffer = [NSMutableDictionary new]; + for (auto&& user : _app->sync_manager()->all_users()) { + NSString *identity = @(user->identity().c_str()); + buffer[identity] = [[RLMUser alloc] initWithUser:std::move(user) app:self]; + } + return buffer; +} + +- (RLMUser *)currentUser { + if (auto user = _app->sync_manager()->get_current_user()) { + return [[RLMUser alloc] initWithUser:user app:self]; + } + return nil; +} + +- (RLMEmailPasswordAuth *)emailPasswordAuth { + return [[RLMEmailPasswordAuth alloc] initWithApp: self]; +} + +- (void)loginWithCredential:(RLMCredentials *)credentials + completion:(RLMUserCompletionBlock)completionHandler { + auto completion = ^(std::shared_ptr user, util::Optional error) { + if (error && error->error_code) { + return completionHandler(nil, RLMAppErrorToNSError(*error)); + } + + completionHandler([[RLMUser alloc] initWithUser:user app:self], nil); + }; + return RLMTranslateError([&] { + return _app->log_in_with_credentials(credentials.appCredentials, completion); + }); +} + +- (RLMUser *)switchToUser:(RLMUser *)syncUser { + return RLMTranslateError([&] { + return [[RLMUser alloc] initWithUser:_app->switch_user(syncUser._syncUser) app:self]; + }); +} + +- (RLMPushClient *)pushClientWithServiceName:(NSString *)serviceName { + return RLMTranslateError([&] { + return [[RLMPushClient alloc] initWithPushClient:_app->push_notification_client(serviceName.UTF8String)]; + }); +} + +#pragma mark - Sign In With Apple Extension + +- (void)setAuthorizationDelegate:(id)authorizationDelegate API_AVAILABLE(ios(13.0), macos(10.15), tvos(13.0), watchos(6.0)) { + _authorizationDelegate = authorizationDelegate; +} + +- (id)authorizationDelegate API_AVAILABLE(ios(13.0), macos(10.15), tvos(13.0), watchos(6.0)) { + return _authorizationDelegate; +} + +- (void)setASAuthorizationControllerDelegateForController:(ASAuthorizationController *)controller API_AVAILABLE(ios(13.0), macos(10.15), tvos(13.0), watchos(6.0)) { + controller.delegate = self; +} + +- (void)authorizationController:(__unused ASAuthorizationController *)controller + didCompleteWithAuthorization:(ASAuthorization *)authorization API_AVAILABLE(ios(13.0), macos(10.15), tvos(13.0), watchos(6.0)) { + NSString *jwt = [[NSString alloc] initWithData:((ASAuthorizationAppleIDCredential *)authorization.credential).identityToken + encoding:NSUTF8StringEncoding]; + [self loginWithCredential:[RLMCredentials credentialsWithAppleToken:jwt] + completion:^(RLMUser *user, NSError *error) { + if (user) { + [self.authorizationDelegate authenticationDidCompleteWithUser:user]; + } else { + [self.authorizationDelegate authenticationDidCompleteWithError:error]; + } + }]; +} + +- (void)authorizationController:(__unused ASAuthorizationController *)controller + didCompleteWithError:(NSError *)error API_AVAILABLE(ios(13.0), macos(10.15), tvos(13.0), watchos(6.0)) { + [self.authorizationDelegate authenticationDidCompleteWithError:error]; +} + +@end + + diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMArray.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMArray.mm new file mode 100644 index 0000000..9ea8a24 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMArray.mm @@ -0,0 +1,609 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// 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 "RLMArray_Private.hpp" + +#import "RLMObjectSchema.h" +#import "RLMObjectStore.h" +#import "RLMObject_Private.h" +#import "RLMProperty_Private.h" +#import "RLMQueryUtil.hpp" +#import "RLMSchema_Private.h" +#import "RLMSwiftSupport.h" +#import "RLMThreadSafeReference_Private.hpp" +#import "RLMUtil.hpp" + +// See -countByEnumeratingWithState:objects:count +@interface RLMArrayHolder : NSObject { +@public + std::unique_ptr items; +} +@end +@implementation RLMArrayHolder +@end + +@interface RLMArray () +@end + +@implementation RLMArray { +@public + // Backing array when this instance is unmanaged + NSMutableArray *_backingArray; +} + +#pragma mark - Initializers + +- (instancetype)initWithObjectClassName:(__unsafe_unretained NSString *const)objectClassName { + REALM_ASSERT([objectClassName length] > 0); + self = [super init]; + if (self) { + _objectClassName = objectClassName; + _type = RLMPropertyTypeObject; + } + return self; +} + +- (instancetype)initWithObjectType:(RLMPropertyType)type optional:(BOOL)optional { + self = [super init]; + if (self) { + _type = type; + _optional = optional; + } + return self; +} + +#pragma mark - Convenience wrappers used for all RLMArray types + +- (void)addObjects:(id)objects { + for (id obj in objects) { + [self addObject:obj]; + } +} + +- (void)addObject:(id)object { + [self insertObject:object atIndex:self.count]; +} + +- (void)removeLastObject { + NSUInteger count = self.count; + if (count) { + [self removeObjectAtIndex:count-1]; + } +} + +- (id)objectAtIndexedSubscript:(NSUInteger)index { + return [self objectAtIndex:index]; +} + +- (void)setObject:(id)newValue atIndexedSubscript:(NSUInteger)index { + [self replaceObjectAtIndex:index withObject:newValue]; +} + +- (RLMResults *)sortedResultsUsingKeyPath:(NSString *)keyPath ascending:(BOOL)ascending { + return [self sortedResultsUsingDescriptors:@[[RLMSortDescriptor sortDescriptorWithKeyPath:keyPath ascending:ascending]]]; +} + +- (NSUInteger)indexOfObjectWhere:(NSString *)predicateFormat, ... { + va_list args; + va_start(args, predicateFormat); + NSUInteger index = [self indexOfObjectWhere:predicateFormat args:args]; + va_end(args); + return index; +} + +- (NSUInteger)indexOfObjectWhere:(NSString *)predicateFormat args:(va_list)args { + return [self indexOfObjectWithPredicate:[NSPredicate predicateWithFormat:predicateFormat + arguments:args]]; +} + +#pragma mark - Unmanaged RLMArray implementation + +- (RLMRealm *)realm { + return nil; +} + +- (id)firstObject { + if (self.count) { + return [self objectAtIndex:0]; + } + return nil; +} + +- (id)lastObject { + NSUInteger count = self.count; + if (count) { + return [self objectAtIndex:count-1]; + } + return nil; +} + +- (id)objectAtIndex:(NSUInteger)index { + validateArrayBounds(self, index); + return [_backingArray objectAtIndex:index]; +} + +- (NSUInteger)count { + return _backingArray.count; +} + +- (BOOL)isInvalidated { + return NO; +} + +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state + objects:(__unused __unsafe_unretained id [])buffer + count:(__unused NSUInteger)len { + if (state->state != 0) { + return 0; + } + + // We need to enumerate a copy of the backing array so that it doesn't + // reflect changes made during enumeration. This copy has to be autoreleased + // (since there's nowhere for us to store a strong reference), and uses + // RLMArrayHolder rather than an NSArray because NSArray doesn't guarantee + // that it'll use a single contiguous block of memory, and if it doesn't + // we'd need to forward multiple calls to this method to the same NSArray, + // which would require holding a reference to it somewhere. + __autoreleasing RLMArrayHolder *copy = [[RLMArrayHolder alloc] init]; + copy->items = std::make_unique(self.count); + + NSUInteger i = 0; + for (id object in _backingArray) { + copy->items[i++] = object; + } + + state->itemsPtr = (__unsafe_unretained id *)(void *)copy->items.get(); + // needs to point to something valid, but the whole point of this is so + // that it can't be changed + state->mutationsPtr = state->extra; + state->state = i; + + return i; +} + + +template +static void changeArray(__unsafe_unretained RLMArray *const ar, + NSKeyValueChange kind, dispatch_block_t f, IndexSetFactory&& is) { + if (!ar->_backingArray) { + ar->_backingArray = [NSMutableArray new]; + } + + if (RLMObjectBase *parent = ar->_parentObject) { + NSIndexSet *indexes = is(); + [parent willChange:kind valuesAtIndexes:indexes forKey:ar->_key]; + f(); + [parent didChange:kind valuesAtIndexes:indexes forKey:ar->_key]; + } + else { + f(); + } +} + +static void changeArray(__unsafe_unretained RLMArray *const ar, NSKeyValueChange kind, + NSUInteger index, dispatch_block_t f) { + changeArray(ar, kind, f, [=] { return [NSIndexSet indexSetWithIndex:index]; }); +} + +static void changeArray(__unsafe_unretained RLMArray *const ar, NSKeyValueChange kind, + NSRange range, dispatch_block_t f) { + changeArray(ar, kind, f, [=] { return [NSIndexSet indexSetWithIndexesInRange:range]; }); +} + +static void changeArray(__unsafe_unretained RLMArray *const ar, NSKeyValueChange kind, + NSIndexSet *is, dispatch_block_t f) { + changeArray(ar, kind, f, [=] { return is; }); +} + +void RLMArrayValidateMatchingObjectType(__unsafe_unretained RLMArray *const array, + __unsafe_unretained id const value) { + if (!value && !array->_optional) { + @throw RLMException(@"Invalid nil value for array of '%@'.", + array->_objectClassName ?: RLMTypeToString(array->_type)); + } + if (array->_type != RLMPropertyTypeObject) { + if (!RLMValidateValue(value, array->_type, array->_optional, false, nil)) { + @throw RLMException(@"Invalid value '%@' of type '%@' for expected type '%@%s'.", + value, [value class], RLMTypeToString(array->_type), + array->_optional ? "?" : ""); + } + return; + } + + auto object = RLMDynamicCast(value); + if (!object) { + return; + } + if (!object->_objectSchema) { + @throw RLMException(@"Object cannot be inserted unless the schema is initialized. " + "This can happen if you try to insert objects into a RLMArray / List from a default value or from an overriden unmanaged initializer (`init()`)."); + } + if (![array->_objectClassName isEqualToString:object->_objectSchema.className]) { + @throw RLMException(@"Object of type '%@' does not match RLMArray type '%@'.", + object->_objectSchema.className, array->_objectClassName); + } +} + +static void validateArrayBounds(__unsafe_unretained RLMArray *const ar, + NSUInteger index, bool allowOnePastEnd=false) { + NSUInteger max = ar->_backingArray.count + allowOnePastEnd; + if (index >= max) { + @throw RLMException(@"Index %llu is out of bounds (must be less than %llu).", + (unsigned long long)index, (unsigned long long)max); + } +} + +- (void)addObjectsFromArray:(NSArray *)array { + for (id obj in array) { + RLMArrayValidateMatchingObjectType(self, obj); + } + changeArray(self, NSKeyValueChangeInsertion, NSMakeRange(_backingArray.count, array.count), ^{ + [_backingArray addObjectsFromArray:array]; + }); +} + +- (void)insertObject:(id)anObject atIndex:(NSUInteger)index { + RLMArrayValidateMatchingObjectType(self, anObject); + validateArrayBounds(self, index, true); + changeArray(self, NSKeyValueChangeInsertion, index, ^{ + [_backingArray insertObject:anObject atIndex:index]; + }); +} + +- (void)insertObjects:(id)objects atIndexes:(NSIndexSet *)indexes { + changeArray(self, NSKeyValueChangeInsertion, indexes, ^{ + NSUInteger currentIndex = [indexes firstIndex]; + for (RLMObject *obj in objects) { + RLMArrayValidateMatchingObjectType(self, obj); + [_backingArray insertObject:obj atIndex:currentIndex]; + currentIndex = [indexes indexGreaterThanIndex:currentIndex]; + } + }); +} + +- (void)removeObjectAtIndex:(NSUInteger)index { + validateArrayBounds(self, index); + changeArray(self, NSKeyValueChangeRemoval, index, ^{ + [_backingArray removeObjectAtIndex:index]; + }); +} + +- (void)removeObjectsAtIndexes:(NSIndexSet *)indexes { + changeArray(self, NSKeyValueChangeRemoval, indexes, ^{ + [_backingArray removeObjectsAtIndexes:indexes]; + }); +} + +- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject { + RLMArrayValidateMatchingObjectType(self, anObject); + validateArrayBounds(self, index); + changeArray(self, NSKeyValueChangeReplacement, index, ^{ + [_backingArray replaceObjectAtIndex:index withObject:anObject]; + }); +} + +- (void)moveObjectAtIndex:(NSUInteger)sourceIndex toIndex:(NSUInteger)destinationIndex { + validateArrayBounds(self, sourceIndex); + validateArrayBounds(self, destinationIndex); + id original = _backingArray[sourceIndex]; + + auto start = std::min(sourceIndex, destinationIndex); + auto len = std::max(sourceIndex, destinationIndex) - start + 1; + changeArray(self, NSKeyValueChangeReplacement, {start, len}, ^{ + [_backingArray removeObjectAtIndex:sourceIndex]; + [_backingArray insertObject:original atIndex:destinationIndex]; + }); +} + +- (void)exchangeObjectAtIndex:(NSUInteger)index1 withObjectAtIndex:(NSUInteger)index2 { + validateArrayBounds(self, index1); + validateArrayBounds(self, index2); + + changeArray(self, NSKeyValueChangeReplacement, ^{ + [_backingArray exchangeObjectAtIndex:index1 withObjectAtIndex:index2]; + }, [=] { + NSMutableIndexSet *set = [[NSMutableIndexSet alloc] initWithIndex:index1]; + [set addIndex:index2]; + return set; + }); +} + +- (NSUInteger)indexOfObject:(id)object { + RLMArrayValidateMatchingObjectType(self, object); + if (!_backingArray) { + return NSNotFound; + } + if (_type != RLMPropertyTypeObject) { + return [_backingArray indexOfObject:object]; + } + + NSUInteger index = 0; + for (RLMObjectBase *cmp in _backingArray) { + if (RLMObjectBaseAreEqual(object, cmp)) { + return index; + } + index++; + } + return NSNotFound; +} + +- (void)removeAllObjects { + changeArray(self, NSKeyValueChangeRemoval, NSMakeRange(0, _backingArray.count), ^{ + [_backingArray removeAllObjects]; + }); +} + +- (RLMResults *)objectsWhere:(NSString *)predicateFormat, ... { + va_list args; + va_start(args, predicateFormat); + RLMResults *results = [self objectsWhere:predicateFormat args:args]; + va_end(args); + return results; +} + +- (RLMResults *)objectsWhere:(NSString *)predicateFormat args:(va_list)args { + return [self objectsWithPredicate:[NSPredicate predicateWithFormat:predicateFormat arguments:args]]; +} + +static bool canAggregate(RLMPropertyType type, bool allowDate) { + switch (type) { + case RLMPropertyTypeInt: + case RLMPropertyTypeFloat: + case RLMPropertyTypeDouble: + case RLMPropertyTypeDecimal128: + return true; + case RLMPropertyTypeDate: + return allowDate; + default: + return false; + } +} + +- (RLMPropertyType)typeForProperty:(NSString *)propertyName { + if ([propertyName isEqualToString:@"self"]) { + return _type; + } + + RLMObjectSchema *objectSchema; + if (_backingArray.count) { + objectSchema = [_backingArray[0] objectSchema]; + } + else { + objectSchema = [RLMSchema.partialPrivateSharedSchema schemaForClassName:_objectClassName]; + } + + return RLMValidatedProperty(objectSchema, propertyName).type; +} + +- (id)aggregateProperty:(NSString *)key operation:(NSString *)op method:(SEL)sel { + // Although delegating to valueForKeyPath: here would allow to support + // nested key paths as well, limiting functionality gives consistency + // between unmanaged and managed arrays. + if ([key rangeOfString:@"."].location != NSNotFound) { + @throw RLMException(@"Nested key paths are not supported yet for KVC collection operators."); + } + + bool allowDate = false; + bool sum = false; + if ([op isEqualToString:@"@min"] || [op isEqualToString:@"@max"]) { + allowDate = true; + } + else if ([op isEqualToString:@"@sum"]) { + sum = true; + } + else if (![op isEqualToString:@"@avg"]) { + // Just delegate to NSArray for all other operators + return [_backingArray valueForKeyPath:[op stringByAppendingPathExtension:key]]; + } + + RLMPropertyType type = [self typeForProperty:key]; + if (!canAggregate(type, allowDate)) { + NSString *method = sel ? NSStringFromSelector(sel) : op; + if (_type == RLMPropertyTypeObject) { + @throw RLMException(@"%@: is not supported for %@ property '%@.%@'", + method, RLMTypeToString(type), _objectClassName, key); + } + else { + @throw RLMException(@"%@ is not supported for %@%s array", + method, RLMTypeToString(_type), _optional ? "?" : ""); + } + } + + NSArray *values = [key isEqualToString:@"self"] ? _backingArray : [_backingArray valueForKey:key]; + if (_optional) { + // Filter out NSNull values to match our behavior on managed arrays + NSIndexSet *nonnull = [values indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger, BOOL *) { + return obj != NSNull.null; + }]; + if (nonnull.count < values.count) { + values = [values objectsAtIndexes:nonnull]; + } + } + id result = [values valueForKeyPath:[op stringByAppendingString:@".self"]]; + return sum && !result ? @0 : result; +} + +- (id)valueForKeyPath:(NSString *)keyPath { + if ([keyPath characterAtIndex:0] != '@') { + return _backingArray ? [_backingArray valueForKeyPath:keyPath] : [super valueForKeyPath:keyPath]; + } + + if (!_backingArray) { + _backingArray = [NSMutableArray new]; + } + + NSUInteger dot = [keyPath rangeOfString:@"."].location; + if (dot == NSNotFound) { + return [_backingArray valueForKeyPath:keyPath]; + } + + NSString *op = [keyPath substringToIndex:dot]; + NSString *key = [keyPath substringFromIndex:dot + 1]; + return [self aggregateProperty:key operation:op method:nil]; +} + +- (id)valueForKey:(NSString *)key { + if ([key isEqualToString:RLMInvalidatedKey]) { + return @NO; // Unmanaged arrays are never invalidated + } + if (!_backingArray) { + _backingArray = [NSMutableArray new]; + } + return [_backingArray valueForKey:key]; +} + +- (void)setValue:(id)value forKey:(NSString *)key { + if ([key isEqualToString:@"self"]) { + RLMArrayValidateMatchingObjectType(self, value); + for (NSUInteger i = 0, count = _backingArray.count; i < count; ++i) { + _backingArray[i] = value; + } + return; + } + else if (_type == RLMPropertyTypeObject) { + [_backingArray setValue:value forKey:key]; + } + else { + [self setValue:value forUndefinedKey:key]; + } +} + +- (id)minOfProperty:(NSString *)property { + return [self aggregateProperty:property operation:@"@min" method:_cmd]; +} + +- (id)maxOfProperty:(NSString *)property { + return [self aggregateProperty:property operation:@"@max" method:_cmd]; +} + +- (id)sumOfProperty:(NSString *)property { + return [self aggregateProperty:property operation:@"@sum" method:_cmd]; +} + +- (id)averageOfProperty:(NSString *)property { + return [self aggregateProperty:property operation:@"@avg" method:_cmd]; +} + +- (NSUInteger)indexOfObjectWithPredicate:(NSPredicate *)predicate { + if (!_backingArray) { + return NSNotFound; + } + return [_backingArray indexOfObjectPassingTest:^BOOL(id obj, NSUInteger, BOOL *) { + return [predicate evaluateWithObject:obj]; + }]; +} + +- (NSArray *)objectsAtIndexes:(NSIndexSet *)indexes { + if (!_backingArray) { + _backingArray = [NSMutableArray new]; + } + return [_backingArray objectsAtIndexes:indexes]; +} + +- (BOOL)isEqual:(id)object { + if (auto array = RLMDynamicCast(object)) { + return !array.realm + && ((_backingArray.count == 0 && array->_backingArray.count == 0) + || [_backingArray isEqual:array->_backingArray]); + } + return NO; +} + +- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath + options:(NSKeyValueObservingOptions)options context:(void *)context { + RLMValidateArrayObservationKey(keyPath, self); + [super addObserver:observer forKeyPath:keyPath options:options context:context]; +} + +#pragma mark - Methods unsupported on unmanaged RLMArray instances + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-parameter" + +- (RLMResults *)objectsWithPredicate:(NSPredicate *)predicate { + @throw RLMException(@"This method may only be called on RLMArray instances retrieved from an RLMRealm"); +} + +- (RLMResults *)sortedResultsUsingDescriptors:(NSArray *)properties { + @throw RLMException(@"This method may only be called on RLMArray instances retrieved from an RLMRealm"); +} + +- (RLMResults *)distinctResultsUsingKeyPaths:(NSArray *)keyPaths { + @throw RLMException(@"This method may only be called on RLMArray instances retrieved from an RLMRealm"); +} + +// The compiler complains about the method's argument type not matching due to +// it not having the generic type attached, but it doesn't seem to be possible +// to actually include the generic type +// http://www.openradar.me/radar?id=6135653276319744 +#pragma clang diagnostic ignored "-Wmismatched-parameter-types" +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMArray *, RLMCollectionChange *, NSError *))block { + return [self addNotificationBlock:block queue:nil]; +} +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMArray *, RLMCollectionChange *, NSError *))block + queue:(nullable dispatch_queue_t)queue { + @throw RLMException(@"This method may only be called on RLMArray instances retrieved from an RLMRealm"); +} + +- (instancetype)freeze { + @throw RLMException(@"This method may only be called on RLMArray instances retrieved from an RLMRealm"); +} + +#pragma mark - Thread Confined Protocol Conformance + +- (realm::ThreadSafeReference)makeThreadSafeReference { + REALM_TERMINATE("Unexpected handover of unmanaged `RLMArray`"); +} + +- (id)objectiveCMetadata { + REALM_TERMINATE("Unexpected handover of unmanaged `RLMArray`"); +} + ++ (instancetype)objectWithThreadSafeReference:(realm::ThreadSafeReference)reference + metadata:(id)metadata + realm:(RLMRealm *)realm { + REALM_TERMINATE("Unexpected handover of unmanaged `RLMArray`"); +} + +#pragma clang diagnostic pop // unused parameter warning + +#pragma mark - Superclass Overrides + +- (NSString *)description { + return [self descriptionWithMaxDepth:RLMDescriptionMaxDepth]; +} + +- (NSString *)descriptionWithMaxDepth:(NSUInteger)depth { + return RLMDescriptionWithMaxDepth(@"RLMArray", self, depth); +} +@end + +@implementation RLMSortDescriptor + ++ (instancetype)sortDescriptorWithKeyPath:(NSString *)keyPath ascending:(BOOL)ascending { + RLMSortDescriptor *desc = [[RLMSortDescriptor alloc] init]; + desc->_keyPath = keyPath; + desc->_ascending = ascending; + return desc; +} + +- (instancetype)reversedSortDescriptor { + return [self.class sortDescriptorWithKeyPath:_keyPath ascending:!_ascending]; +} + +@end diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMBSON.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMBSON.mm new file mode 100644 index 0000000..52358a7 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMBSON.mm @@ -0,0 +1,386 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 +#import + +#import "RLMUtil.hpp" +#import "RLMDecimal128_Private.hpp" +#import "RLMObjectId_Private.hpp" +#import "RLMBSON_Private.hpp" +#import "util/bson/bson.hpp" + +using namespace realm; +using namespace bson; + +#pragma mark NSNull + +@implementation NSNull (RLMBSON) + +- (RLMBSONType)bsonType { + return RLMBSONTypeNull; +} + +@end + +#pragma mark RLMObjectId + +@implementation RLMObjectId (RLMBSON) + +- (RLMBSONType)bsonType { + return RLMBSONTypeObjectId; +} + +@end + +#pragma mark RLMDecimal128 + +@implementation RLMDecimal128 (RLMBSON) + +- (RLMBSONType)bsonType { + return RLMBSONTypeDecimal128; +} + +@end + +#pragma mark NSString + +@implementation NSString (RLMBSON) + +- (RLMBSONType)bsonType { + return RLMBSONTypeString; +} + +@end + +#pragma mark NSNumber + +@implementation NSNumber (RLMBSON) + +- (RLMBSONType)bsonType { + char numberType = [self objCType][0]; + + if (numberType == *@encode(bool) || + numberType == *@encode(char)) { + return RLMBSONTypeBool; + } else if (numberType == *@encode(int) || + numberType == *@encode(short) || + numberType == *@encode(unsigned short) || + numberType == *@encode(unsigned int)) { + return RLMBSONTypeInt32; + } else if (numberType == *@encode(long) || + numberType == *@encode(long long) || + numberType == *@encode(unsigned long) || + numberType == *@encode(unsigned long long)) { + return RLMBSONTypeInt64; + } else { + return RLMBSONTypeDouble; + } +} + +@end + +#pragma mark NSMutableArray + +@implementation NSMutableArray (RLMBSON) + +- (RLMBSONType)bsonType { + return RLMBSONTypeArray; +} + +- (instancetype)initWithBsonArray:(BsonArray)bsonArray { + + if ((self = [self init])) { + for (auto& entry : bsonArray) { + [self addObject:RLMConvertBsonToRLMBSON(entry)]; + } + + return self; + } + + return nil; +} + +@end + +@implementation NSArray (RLMBSON) + +- (BsonArray)bsonArrayValue { + BsonArray bsonArray; + for (id value in self) { + bsonArray.push_back(RLMConvertRLMBSONToBson(value)); + } + return bsonArray; +} + +- (RLMBSONType)bsonType { + return RLMBSONTypeArray; +} + +@end + +#pragma mark NSDictionary + +@implementation NSMutableDictionary (RLMBSON) + +- (RLMBSONType)bsonType { + return RLMBSONTypeDocument; +} + +- (BsonDocument)bsonDocumentValue { + BsonDocument bsonDocument; + for (NSString *value in self) { + bsonDocument[value.UTF8String] = RLMConvertRLMBSONToBson(self[value]); + } + return bsonDocument; +} + +- (instancetype)initWithBsonDocument:(BsonDocument)bsonDocument { + if ((self = [self init])) { + for (auto it = bsonDocument.begin(); it != bsonDocument.end(); ++it) { + const auto& entry = (*it); + [self setObject:RLMConvertBsonToRLMBSON(entry.second) forKey:@(entry.first.data())]; + } + + return self; + } + + return nil; +} + +@end + +@implementation NSDictionary (RLMBSON) + +- (RLMBSONType)bsonType { + return RLMBSONTypeDocument; +} + +- (BsonDocument)bsonDocumentValue { + BsonDocument bsonDocument; + for (NSString *value in self) { + bsonDocument[value.UTF8String] = RLMConvertRLMBSONToBson(self[value]); + } + return bsonDocument; +} + +@end + +#pragma mark NSData + +@implementation NSData (RLMBSON) + +- (RLMBSONType)bsonType { + return RLMBSONTypeBinary; +} + +- (instancetype)initWithBsonBinary:(std::vector)bsonBinary { + if ((self = [NSData dataWithBytes:bsonBinary.data() length:bsonBinary.size()])) { + return self; + } + + return nil; +} + +@end + +#pragma mark NSDate + +@implementation NSDate (RLMBSON) + +- (RLMBSONType)bsonType { + return RLMBSONTypeDatetime; +} + +@end + +#pragma mark NSRegularExpression + +@implementation NSRegularExpression (RLMBSON) + +- (RLMBSONType)bsonType { + return RLMBSONTypeRegularExpression; +} + +- (RegularExpression)regularExpressionValue { + using Option = RegularExpression::Option; + std::string s; + + if ((_options & NSRegularExpressionCaseInsensitive) != 0) s += 'i'; + if ((_options & NSRegularExpressionUseUnixLineSeparators) != 0) s += 'm'; + if ((_options & NSRegularExpressionDotMatchesLineSeparators) != 0) s += 's'; + if ((_options & NSRegularExpressionUseUnicodeWordBoundaries) != 0) s += 'x'; + + return RegularExpression(_pattern.UTF8String, s); +} + +- (instancetype)initWithRegularExpression:(RegularExpression)regularExpression { + if ((self = [self init])) { + _pattern = @(regularExpression.pattern().data()); + switch (regularExpression.options()) { + case realm::bson::RegularExpression::Option::None: + _options = 0; + break; + case realm::bson::RegularExpression::Option::IgnoreCase: + _options = NSRegularExpressionCaseInsensitive; + break; + case realm::bson::RegularExpression::Option::Multiline: + _options = NSRegularExpressionUseUnixLineSeparators; + break; + case realm::bson::RegularExpression::Option::Dotall: + _options = NSRegularExpressionDotMatchesLineSeparators; + break; + case realm::bson::RegularExpression::Option::Extended: + _options = NSRegularExpressionUseUnicodeWordBoundaries; + break; + } + return self; + } + + return nil; +} + +@end + +#pragma mark RLMMaxKey + +@implementation RLMMaxKey + +- (BOOL)isEqual:(id)other { + return other == self || ([other class] == [self class]); +} + +- (NSUInteger)hash { + return 0; +} + +@end + +#pragma mark RLMMaxKey + +@implementation RLMMinKey + +- (BOOL)isEqual:(id)other { + return other == self || ([other class] == [self class]); +} + +- (NSUInteger)hash { + return 0; +} + +@end + +@implementation RLMMaxKey (RLMBSON) + +- (RLMBSONType)bsonType { + return RLMBSONTypeMaxKey; +} + +@end + +@implementation RLMMinKey (RLMBSON) + +- (RLMBSONType)bsonType { + return RLMBSONTypeMinKey; +} + +@end + +#pragma mark RLMBSONToBson + +Bson RLMConvertRLMBSONToBson(id b) { + switch ([b bsonType]) { + case RLMBSONTypeString: + return ((NSString *)b).UTF8String; + case RLMBSONTypeInt32: + return ((NSNumber *)b).intValue; + case RLMBSONTypeInt64: + return ((NSNumber *)b).longLongValue; + case RLMBSONTypeObjectId: + return [((RLMObjectId *)b) value]; + case RLMBSONTypeNull: + return util::none; + case RLMBSONTypeBool: + return (bool)((NSNumber *)b).boolValue; + case RLMBSONTypeDouble: + return ((NSNumber *)b).doubleValue; + case RLMBSONTypeBinary: + return std::vector((char*)((NSData *)b).bytes, + ((char*)((NSData *)b).bytes) + (int)((NSData *)b).length); + case RLMBSONTypeTimestamp: + return RLMTimestampForNSDate((NSDate *)b); + case RLMBSONTypeDatetime: + return MongoTimestamp(((NSDate *)b).timeIntervalSince1970, 0); + case RLMBSONTypeDecimal128: + return [((RLMDecimal128 *)b) decimal128Value]; + case RLMBSONTypeRegularExpression: + return [((NSRegularExpression *)b) regularExpressionValue]; + case RLMBSONTypeMaxKey: + return max_key; + case RLMBSONTypeMinKey: + return min_key; + case RLMBSONTypeDocument: + return [((NSDictionary *)b) bsonDocumentValue]; + case RLMBSONTypeArray: + return [((NSArray *)b) bsonArrayValue]; + } +} + +#pragma mark BsonToRLMBSON + +id RLMConvertBsonToRLMBSON(const Bson& b) { + switch (b.type()) { + case realm::bson::Bson::Type::Null: + return [NSNull null]; + case realm::bson::Bson::Type::Int32: + return @(static_cast(b)); + case realm::bson::Bson::Type::Int64: + return @(static_cast(b)); + case realm::bson::Bson::Type::Bool: + return @(static_cast(b)); + case realm::bson::Bson::Type::Double: + return @(static_cast(b)); + case realm::bson::Bson::Type::String: + return RLMStringDataToNSString(static_cast(b).c_str()); + case realm::bson::Bson::Type::Binary: + return [[NSData alloc] initWithBsonBinary:static_cast>(b)]; + case realm::bson::Bson::Type::Timestamp: + return [[NSDate alloc] initWithTimeIntervalSince1970:static_cast(b).seconds]; + case realm::bson::Bson::Type::Datetime: + return [[NSDate alloc] initWithTimeIntervalSince1970:static_cast(b).get_seconds()]; + case realm::bson::Bson::Type::ObjectId: + return [[RLMObjectId alloc] initWithValue:static_cast(b)]; + case realm::bson::Bson::Type::Decimal128: + return [[RLMDecimal128 alloc] initWithDecimal128:static_cast(b)]; + case realm::bson::Bson::Type::RegularExpression: + return [[NSRegularExpression alloc] initWithRegularExpression:static_cast(b)]; + case realm::bson::Bson::Type::MaxKey: + return [RLMMaxKey new]; + case realm::bson::Bson::Type::MinKey: + return [RLMMinKey new]; + case realm::bson::Bson::Type::Document: + return [[NSMutableDictionary alloc] initWithBsonDocument:static_cast(b)]; + case realm::bson::Bson::Type::Array: + return [[NSMutableArray alloc] initWithBsonArray:static_cast(b)]; + } + return nil; +} + +id RLMConvertBsonDocumentToRLMBSON(realm::util::Optional b) { + return b ? RLMConvertBsonToRLMBSON(*b) : nil; +} diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMClassInfo.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMClassInfo.mm new file mode 100644 index 0000000..4e3a250 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMClassInfo.mm @@ -0,0 +1,130 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// 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 "RLMClassInfo.hpp" + +#import "RLMRealm_Private.hpp" +#import "RLMObjectSchema_Private.h" +#import "RLMSchema.h" +#import "RLMProperty_Private.h" +#import "RLMQueryUtil.hpp" +#import "RLMUtil.hpp" + +#import "object_schema.hpp" +#import "object_store.hpp" +#import "schema.hpp" +#import "shared_realm.hpp" + +#import + +using namespace realm; + +RLMClassInfo::RLMClassInfo(RLMRealm *realm, RLMObjectSchema *rlmObjectSchema, + const realm::ObjectSchema *objectSchema) +: realm(realm), rlmObjectSchema(rlmObjectSchema), objectSchema(objectSchema) { } + +realm::TableRef RLMClassInfo::table() const { + if (auto key = objectSchema->table_key) { + return realm.group.get_table(objectSchema->table_key); + } + return nullptr; +} + +RLMProperty *RLMClassInfo::propertyForTableColumn(ColKey col) const noexcept { + auto const& props = objectSchema->persisted_properties; + for (size_t i = 0; i < props.size(); ++i) { + if (props[i].column_key == col) { + return rlmObjectSchema.properties[i]; + } + } + return nil; +} + +RLMProperty *RLMClassInfo::propertyForPrimaryKey() const noexcept { + return rlmObjectSchema.primaryKeyProperty; +} + +realm::ColKey RLMClassInfo::tableColumn(NSString *propertyName) const { + return tableColumn(RLMValidatedProperty(rlmObjectSchema, propertyName)); +} + +realm::ColKey RLMClassInfo::tableColumn(RLMProperty *property) const { + return objectSchema->persisted_properties[property.index].column_key; +} + +RLMClassInfo &RLMClassInfo::linkTargetType(size_t propertyIndex) { + return realm->_info[rlmObjectSchema.properties[propertyIndex].objectClassName]; +} + +RLMClassInfo &RLMClassInfo::linkTargetType(realm::Property const& property) { + REALM_ASSERT(property.type == PropertyType::Object); + return linkTargetType(&property - &objectSchema->persisted_properties[0]); +} + +RLMClassInfo &RLMClassInfo::freeze(__unsafe_unretained RLMRealm *const frozenRealm) { + REALM_ASSERT(frozenRealm.frozen); + // FIXME + return frozenRealm->_info[rlmObjectSchema.className]; +} + +RLMSchemaInfo::impl::iterator RLMSchemaInfo::begin() noexcept { return m_objects.begin(); } +RLMSchemaInfo::impl::iterator RLMSchemaInfo::end() noexcept { return m_objects.end(); } +RLMSchemaInfo::impl::const_iterator RLMSchemaInfo::begin() const noexcept { return m_objects.begin(); } +RLMSchemaInfo::impl::const_iterator RLMSchemaInfo::end() const noexcept { return m_objects.end(); } + +RLMClassInfo& RLMSchemaInfo::operator[](NSString *name) { + auto it = m_objects.find(name); + if (it == m_objects.end()) { + @throw RLMException(@"Object type '%@' is not managed by the Realm. " + @"If using a custom `objectClasses` / `objectTypes` array in your configuration, " + @"add `%@` to the list of `objectClasses` / `objectTypes`.", + name, name); + } + return *&it->second; +} + +RLMSchemaInfo::RLMSchemaInfo(RLMRealm *realm) { + RLMSchema *rlmSchema = realm.schema; + realm::Schema const& schema = realm->_realm->schema(); + // rlmSchema can be larger due to multiple classes backed by one table + REALM_ASSERT(rlmSchema.objectSchema.count >= schema.size()); + + m_objects.reserve(schema.size()); + for (RLMObjectSchema *rlmObjectSchema in rlmSchema.objectSchema) { + m_objects.emplace(std::piecewise_construct, + std::forward_as_tuple(rlmObjectSchema.className), + std::forward_as_tuple(realm, rlmObjectSchema, + &*schema.find(rlmObjectSchema.objectName.UTF8String))); + } +} + +RLMSchemaInfo RLMSchemaInfo::clone(realm::Schema const& source_schema, + __unsafe_unretained RLMRealm *const target_realm) { + RLMSchemaInfo info; + info.m_objects.reserve(m_objects.size()); + + auto& schema = target_realm->_realm->schema(); + for (auto& pair : m_objects) { + size_t idx = pair.second.objectSchema - &*source_schema.begin(); + info.m_objects.emplace(std::piecewise_construct, + std::forward_as_tuple(pair.first), + std::forward_as_tuple(target_realm, pair.second.rlmObjectSchema, + &*schema.begin() + idx)); + } + return info; +} diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMCollection.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMCollection.mm new file mode 100644 index 0000000..934c022 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMCollection.mm @@ -0,0 +1,460 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// 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 "RLMCollection_Private.hpp" + +#import "RLMAccessor.hpp" +#import "RLMArray_Private.hpp" +#import "RLMListBase.h" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObjectStore.h" +#import "RLMObject_Private.hpp" +#import "RLMProperty_Private.h" + +#import "collection_notifications.hpp" +#import "list.hpp" +#import "results.hpp" + +static const int RLMEnumerationBufferSize = 16; + +@implementation RLMFastEnumerator { + // The buffer supplied by fast enumeration does not retain the objects given + // to it, but because we create objects on-demand and don't want them + // autoreleased (a table can have more rows than the device has memory for + // accessor objects) we need a thing to retain them. + id _strongBuffer[RLMEnumerationBufferSize]; + + RLMRealm *_realm; + RLMClassInfo *_info; + + // A pointer to either _snapshot or a Results from the source collection, + // to avoid having to copy the Results when not in a write transaction + realm::Results *_results; + realm::Results _snapshot; + + // A strong reference to the collection being enumerated to ensure it stays + // alive when we're holding a pointer to a member in it + id _collection; +} + +- (instancetype)initWithList:(realm::List&)list + collection:(id)collection + classInfo:(RLMClassInfo&)info +{ + self = [super init]; + if (self) { + _info = &info; + _realm = _info->realm; + if (_realm.inWriteTransaction) { + _snapshot = list.snapshot(); + } + else { + _snapshot = list.as_results(); + _collection = collection; + [_realm registerEnumerator:self]; + } + _results = &_snapshot; + } + return self; +} + +- (instancetype)initWithResults:(realm::Results&)results + collection:(id)collection + classInfo:(RLMClassInfo&)info +{ + self = [super init]; + if (self) { + _info = &info; + _realm = _info->realm; + if (_realm.inWriteTransaction) { + _snapshot = results.snapshot(); + _results = &_snapshot; + } + else { + _results = &results; + _collection = collection; + [_realm registerEnumerator:self]; + } + } + return self; +} + +- (void)dealloc { + if (_collection) { + [_realm unregisterEnumerator:self]; + } +} + +- (void)detach { + _snapshot = _results->snapshot(); + _results = &_snapshot; + _collection = nil; +} + +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state + count:(NSUInteger)len { + [_realm verifyThread]; + if (!_results->is_valid()) { + @throw RLMException(@"Collection is no longer valid"); + } + // The fast enumeration buffer size is currently a hardcoded number in the + // compiler so this can't actually happen, but just in case it changes in + // the future... + if (len > RLMEnumerationBufferSize) { + len = RLMEnumerationBufferSize; + } + + NSUInteger batchCount = 0, count = state->extra[1]; + + @autoreleasepool { + RLMAccessorContext ctx(*_info); + for (NSUInteger index = state->state; index < count && batchCount < len; ++index) { + _strongBuffer[batchCount] = _results->get(ctx, index); + batchCount++; + } + } + + for (NSUInteger i = batchCount; i < len; ++i) { + _strongBuffer[i] = nil; + } + + if (batchCount == 0) { + // Release our data if we're done, as we're autoreleased and so may + // stick around for a while + if (_collection) { + _collection = nil; + [_realm unregisterEnumerator:self]; + } + _snapshot = {}; + } + + state->itemsPtr = (__unsafe_unretained id *)(void *)_strongBuffer; + state->state += batchCount; + state->mutationsPtr = state->extra+1; + + return batchCount; +} +@end + +NSUInteger RLMFastEnumerate(NSFastEnumerationState *state, NSUInteger len, id collection) { + __autoreleasing RLMFastEnumerator *enumerator; + if (state->state == 0) { + enumerator = collection.fastEnumerator; + state->extra[0] = (long)enumerator; + state->extra[1] = collection.count; + } + else { + enumerator = (__bridge id)(void *)state->extra[0]; + } + + return [enumerator countByEnumeratingWithState:state count:len]; +} + +template +NSArray *RLMCollectionValueForKey(Collection& collection, NSString *key, RLMClassInfo& info) { + size_t count = collection.size(); + if (count == 0) { + return @[]; + } + + NSMutableArray *array = [NSMutableArray arrayWithCapacity:count]; + if ([key isEqualToString:@"self"]) { + RLMAccessorContext context(info); + for (size_t i = 0; i < count; ++i) { + [array addObject:collection.get(context, i) ?: NSNull.null]; + } + return array; + } + + if (collection.get_type() != realm::PropertyType::Object) { + RLMAccessorContext context(info); + for (size_t i = 0; i < count; ++i) { + [array addObject:[collection.get(context, i) valueForKey:key] ?: NSNull.null]; + } + return array; + } + + RLMObject *accessor = RLMCreateManagedAccessor(info.rlmObjectSchema.accessorClass, &info); + + // List properties need to be handled specially since we need to create a + // new List each time + if (info.rlmObjectSchema.isSwiftClass) { + auto prop = info.rlmObjectSchema[key]; + if (prop && prop.array && prop.swiftIvar) { + // Grab the actual class for the generic List from an instance of it + // so that we can make instances of the List without creating a new + // object accessor each time + Class cls = [object_getIvar(accessor, prop.swiftIvar) class]; + RLMAccessorContext context(info); + for (size_t i = 0; i < count; ++i) { + RLMListBase *list = [[cls alloc] init]; + list._rlmArray = [[RLMManagedArray alloc] initWithList:realm::List(info.realm->_realm, + collection.get(i), + info.tableColumn(prop)) + parentInfo:&info + property:prop]; + [array addObject:list]; + } + return array; + } + } + + for (size_t i = 0; i < count; i++) { + accessor->_row = collection.get(i); + RLMInitializeSwiftAccessorGenerics(accessor); + [array addObject:[accessor valueForKey:key] ?: NSNull.null]; + } + return array; +} + +template NSArray *RLMCollectionValueForKey(realm::Results&, NSString *, RLMClassInfo&); +template NSArray *RLMCollectionValueForKey(realm::List&, NSString *, RLMClassInfo&); + +void RLMCollectionSetValueForKey(id collection, NSString *key, id value) { + realm::TableView tv = [collection tableView]; + if (tv.size() == 0) { + return; + } + + RLMClassInfo *info = collection.objectInfo; + RLMObject *accessor = RLMCreateManagedAccessor(info->rlmObjectSchema.accessorClass, info); + for (size_t i = 0; i < tv.size(); i++) { + accessor->_row = tv[i]; + RLMInitializeSwiftAccessorGenerics(accessor); + [accessor setValue:value forKey:key]; + } +} + +NSString *RLMDescriptionWithMaxDepth(NSString *name, + id collection, + NSUInteger depth) { + if (depth == 0) { + return @""; + } + + const NSUInteger maxObjects = 100; + auto str = [NSMutableString stringWithFormat:@"%@<%@> <%p> (\n", name, + [collection objectClassName] ?: RLMTypeToString([collection type]), + (void *)collection]; + size_t index = 0, skipped = 0; + for (id obj in collection) { + NSString *sub; + if ([obj respondsToSelector:@selector(descriptionWithMaxDepth:)]) { + sub = [obj descriptionWithMaxDepth:depth - 1]; + } + else { + sub = [obj description]; + } + + // Indent child objects + NSString *objDescription = [sub stringByReplacingOccurrencesOfString:@"\n" + withString:@"\n\t"]; + [str appendFormat:@"\t[%zu] %@,\n", index++, objDescription]; + if (index >= maxObjects) { + skipped = collection.count - maxObjects; + break; + } + } + + // Remove last comma and newline characters + if (collection.count > 0) { + [str deleteCharactersInRange:NSMakeRange(str.length-2, 2)]; + } + if (skipped) { + [str appendFormat:@"\n\t... %zu objects skipped.", skipped]; + } + [str appendFormat:@"\n)"]; + return str; +} + +std::vector> RLMSortDescriptorsToKeypathArray(NSArray *properties) { + std::vector> keypaths; + keypaths.reserve(properties.count); + for (RLMSortDescriptor *desc in properties) { + if ([desc.keyPath rangeOfString:@"@"].location != NSNotFound) { + @throw RLMException(@"Cannot sort on key path '%@': KVC collection operators are not supported.", desc.keyPath); + } + keypaths.push_back({desc.keyPath.UTF8String, desc.ascending}); + } + return keypaths; +} + +@implementation RLMCollectionChange { + realm::CollectionChangeSet _indices; +} + +- (instancetype)initWithChanges:(realm::CollectionChangeSet)indices { + self = [super init]; + if (self) { + _indices = std::move(indices); + } + return self; +} + +static NSArray *toArray(realm::IndexSet const& set) { + NSMutableArray *ret = [NSMutableArray new]; + for (auto index : set.as_indexes()) { + [ret addObject:@(index)]; + } + return ret; +} + +- (NSArray *)insertions { + return toArray(_indices.insertions); +} + +- (NSArray *)deletions { + return toArray(_indices.deletions); +} + +- (NSArray *)modifications { + return toArray(_indices.modifications); +} + +static NSArray *toIndexPathArray(realm::IndexSet const& set, NSUInteger section) { + NSMutableArray *ret = [NSMutableArray new]; + NSUInteger path[2] = {section, 0}; + for (auto index : set.as_indexes()) { + path[1] = index; + [ret addObject:[NSIndexPath indexPathWithIndexes:path length:2]]; + } + return ret; +} + +- (NSArray *)deletionsInSection:(NSUInteger)section { + return toIndexPathArray(_indices.deletions, section); +} + +- (NSArray *)insertionsInSection:(NSUInteger)section { + return toIndexPathArray(_indices.insertions, section); +} + +- (NSArray *)modificationsInSection:(NSUInteger)section { + return toIndexPathArray(_indices.modifications, section); +} + +- (NSString *)description { + return [NSString stringWithFormat:@" insertions: %@, deletions: %@, modifications: %@", + (__bridge void *)self, self.insertions, self.deletions, self.modifications]; +} + +@end + +namespace { +struct CollectionCallbackWrapper { + void (^block)(id, RLMCollectionChange *, NSError *); + id collection; + bool ignoreChangesInInitialNotification; + + void operator()(realm::CollectionChangeSet const& changes, std::exception_ptr err) { + if (err) { + try { + rethrow_exception(err); + } + catch (...) { + NSError *error = nil; + RLMRealmTranslateException(&error); + block(nil, nil, error); + return; + } + } + + if (ignoreChangesInInitialNotification) { + ignoreChangesInInitialNotification = false; + block(collection, nil, nil); + } + else if (changes.empty()) { + block(collection, nil, nil); + } + else { + block(collection, [[RLMCollectionChange alloc] initWithChanges:changes], nil); + } + } +}; +} // anonymous namespace + +@interface RLMCancellationToken : RLMNotificationToken +@end + +@implementation RLMCancellationToken { +@public + __unsafe_unretained RLMRealm *_realm; + realm::NotificationToken _token; + std::mutex _mutex; +} + +- (RLMRealm *)realm { + std::lock_guard lock(_mutex); + return _realm; +} + +- (void)suppressNextNotification { + std::lock_guard lock(_mutex); + if (_realm) { + _token.suppress_next(); + } +} + +- (void)invalidate { + std::lock_guard lock(_mutex); + _token = {}; + _realm = nil; +} + +template +RLMNotificationToken *RLMAddNotificationBlock(RLMCollection *collection, + void (^block)(id, RLMCollectionChange *, NSError *), + dispatch_queue_t queue) { + RLMRealm *realm = collection.realm; + if (!realm) { + @throw RLMException(@"Linking objects notifications are only supported on managed objects."); + } + bool skipFirst = std::is_same_v; + auto token = [[RLMCancellationToken alloc] init]; + + if (!queue) { + [realm verifyNotificationsAreSupported:true]; + token->_realm = realm; + token->_token = RLMGetBackingCollection(collection).add_notification_callback(CollectionCallbackWrapper{block, collection, skipFirst}); + return token; + } + + RLMThreadSafeReference *tsr = [RLMThreadSafeReference referenceWithThreadConfined:collection]; + token->_realm = realm; + RLMRealmConfiguration *config = realm.configuration; + dispatch_async(queue, ^{ + std::lock_guard lock(token->_mutex); + if (!token->_realm) { + return; + } + NSError *error; + RLMRealm *realm = token->_realm = [RLMRealm realmWithConfiguration:config queue:queue error:&error]; + if (!realm) { + block(nil, nil, error); + return; + } + RLMCollection *collection = [realm resolveThreadSafeReference:tsr]; + token->_token = RLMGetBackingCollection(collection).add_notification_callback(CollectionCallbackWrapper{block, collection, skipFirst}); + }); + return token; +} +@end + +// Explicitly instantiate the templated function for the two types we'll use it on +template RLMNotificationToken *RLMAddNotificationBlock<>(RLMManagedArray *, void (^)(id, RLMCollectionChange *, NSError *), dispatch_queue_t); +template RLMNotificationToken *RLMAddNotificationBlock<>(RLMResults *, void (^)(id, RLMCollectionChange *, NSError *), dispatch_queue_t); diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMConstants.m b/Darner-dan-uh/Pods/Realm/Realm/RLMConstants.m new file mode 100644 index 0000000..b45638f --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMConstants.m @@ -0,0 +1,36 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// 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 + +RLMNotification const RLMRealmRefreshRequiredNotification = @"RLMRealmRefreshRequiredNotification"; +RLMNotification const RLMRealmDidChangeNotification = @"RLMRealmDidChangeNotification"; + +NSString * const RLMErrorDomain = @"io.realm"; + +NSString * const RLMUnknownSystemErrorDomain = @"io.realm.unknown"; + +NSString * const RLMExceptionName = @"RLMException"; + +NSString * const RLMRealmVersionKey = @"RLMRealmVersion"; + +NSString * const RLMRealmCoreVersionKey = @"RLMRealmCoreVersion"; + +NSString * const RLMInvalidatedKey = @"invalidated"; + +NSString * const RLMBackupRealmConfigurationErrorKey = @"RLMBackupRealmConfiguration"; diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMCredentials.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMCredentials.mm new file mode 100644 index 0000000..dd313cd --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMCredentials.mm @@ -0,0 +1,83 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// 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 "RLMCredentials_Private.hpp" + +#import "RLMBSON_Private.hpp" +#import "RLMSyncUtil_Private.h" +#import "RLMUtil.hpp" +#import "util/bson/bson.hpp" + +using namespace realm; + +@implementation RLMCredentials +- (instancetype)initWithAppCredentials:(app::AppCredentials&&)credentials { + if (self = [super init]) { + _appCredentials = std::move(credentials); + self.provider = @(_appCredentials.provider_as_string().data()); + return self; + } + return nil; +} + ++ (instancetype)credentialsWithFacebookToken:(RLMCredentialsToken)token { + return [[self alloc] initWithAppCredentials:app::AppCredentials::facebook(token.UTF8String)]; +} + ++ (instancetype)credentialsWithGoogleAuthCode:(RLMCredentialsToken)token { + return [[self alloc] initWithAppCredentials:app::AppCredentials::google(token.UTF8String)]; +} + ++ (instancetype)credentialsWithAppleToken:(RLMCredentialsToken)token { + return [[self alloc] initWithAppCredentials:app::AppCredentials::apple(token.UTF8String)]; +} + ++ (instancetype)credentialsWithEmail:(NSString *)username + password:(NSString *)password { + return [[self alloc] initWithAppCredentials:app::AppCredentials::username_password(username.UTF8String, + password.UTF8String)]; +} + ++ (instancetype)credentialsWithJWT:(NSString *)token { + return [[self alloc] initWithAppCredentials:app::AppCredentials::custom(token.UTF8String)]; +} + ++ (instancetype)credentialsWithFunctionPayload:(NSDictionary> *)payload { + return [[self alloc] initWithAppCredentials:app::AppCredentials::function(static_cast(RLMConvertRLMBSONToBson(payload)))]; +} + ++ (instancetype)credentialsWithUserAPIKey:(NSString *)apiKey { + return [[self alloc] initWithAppCredentials:app::AppCredentials::user_api_key(apiKey.UTF8String)]; +} + ++ (instancetype)credentialsWithServerAPIKey:(NSString *)apiKey { + return [[self alloc] initWithAppCredentials:app::AppCredentials::server_api_key(apiKey.UTF8String)]; +} + ++ (instancetype)anonymousCredentials { + return [[self alloc] initWithAppCredentials:realm::app::AppCredentials::anonymous()]; +} + +- (BOOL)isEqual:(id)object { + if (auto that = RLMDynamicCast(object)) { + return [self.provider isEqualToString:that.provider] + && self.appCredentials.serialize_as_json() == that.appCredentials.serialize_as_json(); + } + return NO; +} +@end diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMDecimal128.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMDecimal128.mm new file mode 100644 index 0000000..aa595bf --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMDecimal128.mm @@ -0,0 +1,200 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 "RLMDecimal128_Private.hpp" + +#import "RLMUtil.hpp" + +#import + +// Swift's obj-c bridging does not support making an obj-c defined class conform +// to Decodable, so we need a Swift-defined subclass for that. This means that +// when Realm Swift is being used, we need to produce objects of that type rather +// than our obj-c defined type. objc_runtime_visible marks the type as being +// visbile only to the obj-c runtime and not the linker, which means that it'll +// be `nil` at runtime rather than being a linker error if it's not defined, and +// valid if it happens to be defined by some other library (i.e. Realm Swift). +// +// At the point where the objects are being allocated we generally don't have +// any good way of knowing whether or not it's going to end up being used by +// Swift, so we just switch to the subclass unconditionally if the subclass +// exists. This shouldn't have any impact on obj-c code other than a small +// performance hit. +[[clang::objc_runtime_visible]] +@interface RealmSwiftDecimal128 : RLMDecimal128 +@end + +@implementation RLMDecimal128 { + realm::Decimal128 _value; +} + +- (instancetype)init { + if (self = [super init]) { + if (auto cls = [RealmSwiftDecimal128 class]; cls && cls != self.class) { + object_setClass(self, cls); + } + } + return self; +} + +- (instancetype)initWithDecimal128:(realm::Decimal128)value { + if ((self = [self init])) { + _value = value; + } + return self; +} + +- (instancetype)initWithValue:(id)value { + if ((self = [self init])) { + _value = RLMObjcToDecimal128(value); + } + return self; +} + +- (instancetype)initWithNumber:(NSNumber *)number { + if ((self = [self init])) { + _value = RLMObjcToDecimal128(number); + } + return self; +} + +- (instancetype)initWithString:(NSString *)string error:(NSError **)error { + if ((self = [self init])) { + try { + _value = realm::Decimal128(string.UTF8String); + } + catch (std::exception const& e) { + if (error) { + *error = RLMMakeError(RLMErrorInvalidInput, e); + } + return nil; + } + } + return self; +} + ++ (instancetype)decimalWithNumber:(NSNumber *)number { + return [[self alloc] initWithNumber:number]; +} + ++ (instancetype)decimalWithNSDecimal:(NSDecimalNumber *)number { + return [[self alloc] initWithString:number.stringValue error:nil]; +} + +- (realm::Decimal128)decimal128Value { + return _value; +} + +- (BOOL)isEqual:(id)object { + if (auto decimal128 = RLMDynamicCast(object)) { + return _value == decimal128->_value; + } + if (auto number = RLMDynamicCast(object)) { + return _value == RLMObjcToDecimal128(number); + } + return NO; +} + +- (NSUInteger)hash { + return std::hash()(_value); +} + +- (NSString *)description { + return self.stringValue; +} + +- (NSComparisonResult)compare:(RLMDecimal128 *)other { + return static_cast(_value.compare(other->_value)); +} + +- (double)doubleValue { + return [NSDecimalNumber decimalNumberWithDecimal:self.decimalValue].doubleValue; +} + +- (NSDecimal)decimalValue { + NSDecimal ret; + [[[NSScanner alloc] initWithString:@(_value.to_string().c_str())] scanDecimal:&ret]; + return ret; +} + +- (NSString *)stringValue { + return @(_value.to_string().c_str()); +} + +- (BOOL)isNaN { + return _value.is_nan(); +} + +- (RLMDecimal128 *)magnitude { + auto result = realm::Decimal128(abs(self.doubleValue)); + return [[RLMDecimal128 alloc] initWithDecimal128:result]; +} + +- (void)negate { + _value = realm::Decimal128(-self.doubleValue); +} + ++ (RLMDecimal128 *)minimumDecimalNumber { + return [[RLMDecimal128 alloc] initWithDecimal128:std::numeric_limits::lowest()]; +} + ++ (RLMDecimal128 *)maximumDecimalNumber { + return [[RLMDecimal128 alloc] initWithDecimal128:std::numeric_limits::max()]; +} + +- (RLMDecimal128 *)decimalNumberByAdding:(RLMDecimal128 *)decimalNumber { + auto rhs = RLMObjcToDecimal128(decimalNumber); + return [[RLMDecimal128 alloc] initWithDecimal128:_value+rhs]; +} + +- (RLMDecimal128 *)decimalNumberByDividingBy:(RLMDecimal128 *)decimalNumber { + auto rhs = RLMObjcToDecimal128(decimalNumber); + return [[RLMDecimal128 alloc] initWithDecimal128:_value/rhs]; +} + +- (RLMDecimal128 *)decimalNumberBySubtracting:(RLMDecimal128 *)decimalNumber { + auto rhs = RLMObjcToDecimal128(decimalNumber); + return [[RLMDecimal128 alloc] initWithDecimal128:_value-rhs]; +} + +- (RLMDecimal128 *)decimalNumberByMultiplyingBy:(RLMDecimal128 *)decimalNumber { + auto rhs = RLMObjcToDecimal128(decimalNumber); + return [[RLMDecimal128 alloc] initWithDecimal128:_value*rhs]; +} + +- (BOOL)isGreaterThan:(RLMDecimal128 *)decimalNumber { + auto rhs = RLMObjcToDecimal128(decimalNumber); + return _value > rhs; +} + +- (BOOL)isGreaterThanOrEqualTo:(RLMDecimal128 *)decimalNumber { + auto rhs = RLMObjcToDecimal128(decimalNumber); + return _value >= rhs; +} + +- (BOOL)isLessThan:(RLMDecimal128 *)decimalNumber { + auto rhs = RLMObjcToDecimal128(decimalNumber); + return _value < rhs; +} + +- (BOOL)isLessThanOrEqualTo:(RLMDecimal128 *)decimalNumber { + auto rhs = RLMObjcToDecimal128(decimalNumber); + return _value <= rhs; +} + +@end diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMEmailPasswordAuth.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMEmailPasswordAuth.mm new file mode 100644 index 0000000..5971fec --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMEmailPasswordAuth.mm @@ -0,0 +1,83 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 "RLMEmailPasswordAuth.h" +#import "RLMProviderClient_Private.hpp" + +#import "RLMBSON_Private.hpp" +#import "RLMApp_Private.hpp" +#import "sync/app.hpp" + +@implementation RLMEmailPasswordAuth + +- (realm::app::App::UsernamePasswordProviderClient)client { + return self.app._realmApp->provider_client(); +} + +- (void)registerUserWithEmail:(NSString *)email + password:(NSString *)password + completion:(RLMEmailPasswordAuthOptionalErrorBlock)completion { + self.client.register_email(email.UTF8String, password.UTF8String, ^(realm::util::Optional error) { + [self handleResponse:error completion:completion]; + }); +} + +- (void)confirmUser:(NSString *)token + tokenId:(NSString *)tokenId + completion:(RLMEmailPasswordAuthOptionalErrorBlock)completion { + self.client.confirm_user(token.UTF8String, tokenId.UTF8String, ^(realm::util::Optional error) { + [self handleResponse:error completion:completion]; + }); +} + +- (void)resendConfirmationEmail:(NSString *)email + completion:(RLMEmailPasswordAuthOptionalErrorBlock)completion { + self.client.resend_confirmation_email(email.UTF8String, ^(realm::util::Optional error) { + [self handleResponse:error completion:completion]; + }); +} + +- (void)sendResetPasswordEmail:(NSString *)email + completion:(RLMEmailPasswordAuthOptionalErrorBlock)completion { + self.client.send_reset_password_email(email.UTF8String, ^(realm::util::Optional error) { + [self handleResponse:error completion:completion]; + }); +} + +- (void)resetPasswordTo:(NSString *)password + token:(NSString *)token + tokenId:(NSString *)tokenId + completion:(RLMEmailPasswordAuthOptionalErrorBlock)completion { + self.client.reset_password(password.UTF8String, token.UTF8String, tokenId.UTF8String, ^(realm::util::Optional error) { + [self handleResponse:error completion:completion]; + }); +} + +- (void)callResetPasswordFunction:(NSString *)email + password:(NSString *)password + args:(NSArray> *)args + completion:(RLMEmailPasswordAuthOptionalErrorBlock)completion { + self.client.call_reset_password_function(email.UTF8String, + password.UTF8String, + static_cast(RLMConvertRLMBSONToBson(args)), + ^(realm::util::Optional error) { + [self handleResponse:error completion:completion]; + }); +} + +@end diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMEmbeddedObject.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMEmbeddedObject.mm new file mode 100644 index 0000000..746ebc3 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMEmbeddedObject.mm @@ -0,0 +1,109 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 "RLMEmbeddedObject.h" + +#import "RLMObject_Private.hpp" +#import "RLMSchema_Private.h" + +@implementation RLMEmbeddedObject +// synthesized in RLMObjectBase but redeclared here for documentation purposes +@dynamic invalidated, realm, objectSchema; + +#pragma mark - Designated Initializers + +- (instancetype)init { + return [super init]; +} + +#pragma mark - Convenience Initializers + +- (instancetype)initWithValue:(id)value { + if (!(self = [self init])) { + return nil; + } + RLMInitializeWithValue(self, value, RLMSchema.partialPrivateSharedSchema); + return self; +} + +#pragma mark - Subscripting + +- (id)objectForKeyedSubscript:(NSString *)key { + return RLMObjectBaseObjectForKeyedSubscript(self, key); +} + +- (void)setObject:(id)obj forKeyedSubscript:(NSString *)key { + RLMObjectBaseSetObjectForKeyedSubscript(self, key, obj); +} + +#pragma mark - Other Instance Methods + +- (BOOL)isEqualToObject:(RLMObjectBase *)object { + return [object isKindOfClass:RLMObjectBase.class] && RLMObjectBaseAreEqual(self, object); +} + +- (instancetype)freeze { + return RLMObjectFreeze(self); +} + +- (RLMNotificationToken *)addNotificationBlock:(RLMObjectChangeBlock)block { + return RLMObjectAddNotificationBlock(self, block, nil); +} + +- (RLMNotificationToken *)addNotificationBlock:(RLMObjectChangeBlock)block queue:(dispatch_queue_t)queue { + return RLMObjectAddNotificationBlock(self, block, queue); +} + ++ (NSString *)className { + return [super className]; +} + +#pragma mark - Default values for schema definition + ++ (NSString *)primaryKey { + return nil; +} + ++ (NSArray *)indexedProperties { + return @[]; +} + ++ (NSDictionary *)linkingObjectsProperties { + return @{}; +} + ++ (NSDictionary *)defaultPropertyValues { + return nil; +} + ++ (NSArray *)ignoredProperties { + return nil; +} + ++ (NSArray *)requiredProperties { + return @[]; +} + ++ (bool)_realmIgnoreClass { + return false; +} + ++ (bool)isEmbedded { + return true; +} +@end diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMFindOneAndModifyOptions.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMFindOneAndModifyOptions.mm new file mode 100644 index 0000000..f472a3f --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMFindOneAndModifyOptions.mm @@ -0,0 +1,88 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 "RLMFindOneAndModifyOptions_Private.hpp" +#import "RLMBSON_Private.hpp" + +@interface RLMFindOneAndModifyOptions() { + realm::app::MongoCollection::FindOneAndModifyOptions _options; +}; +@end + +@implementation RLMFindOneAndModifyOptions + +- (instancetype)initWithProjection:(id _Nullable)projection + sort:(id _Nullable)sort + upsert:(BOOL)upsert + shouldReturnNewDocument:(BOOL)shouldReturnNewDocument { + if (self = [super init]) { + self.upsert = upsert; + self.shouldReturnNewDocument = shouldReturnNewDocument; + self.projection = projection; + self.sort = sort; + } + return self; +} + +- (realm::app::MongoCollection::FindOneAndModifyOptions)_findOneAndModifyOptions { + return _options; +} + +- (id)projection { + return RLMConvertBsonDocumentToRLMBSON(_options.projection_bson); +} + +- (id)sort { + return RLMConvertBsonDocumentToRLMBSON(_options.sort_bson); +} + +- (BOOL)upsert { + return _options.upsert; +} + +- (BOOL)shouldReturnNewDocument { + return _options.return_new_document; +} + +- (void)setProjection:(id)projection { + if (projection) { + auto bson = realm::bson::BsonDocument(RLMConvertRLMBSONToBson(projection)); + _options.projection_bson = realm::util::Optional(bson); + } else { + _options.projection_bson = realm::util::none; + } +} + +- (void)setSort:(id)sort { + if (sort) { + auto bson = realm::bson::BsonDocument(RLMConvertRLMBSONToBson(sort)); + _options.sort_bson = realm::util::Optional(bson); + } else { + _options.sort_bson = realm::util::none; + } +} + +- (void)setUpsert:(BOOL)upsert { + _options.upsert = upsert; +} + +- (void)setShouldReturnNewDocument:(BOOL)returnNewDocument { + _options.return_new_document = returnNewDocument; +} + +@end diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMFindOptions.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMFindOptions.mm new file mode 100644 index 0000000..e72bc51 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMFindOptions.mm @@ -0,0 +1,87 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 "RLMFindOptions_Private.hpp" +#import "RLMBSON_Private.hpp" + +@interface RLMFindOptions() { + realm::app::MongoCollection::FindOptions _options; +}; +@end + +@implementation RLMFindOptions + +- (instancetype)initWithLimit:(NSInteger)limit + projection:(id _Nullable)projection + sort:(id _Nullable)sort { + if (self = [super init]) { + self.projection = projection; + self.sort = sort; + self.limit = limit; + } + return self; +} + +- (instancetype)initWithProjection:(id _Nullable)projection + sort:(id _Nullable)sort { + if (self = [super init]) { + self.projection = projection; + self.sort = sort; + } + return self; +} + +- (realm::app::MongoCollection::FindOptions)_findOptions { + return _options; +} + +- (id)projection { + return RLMConvertBsonDocumentToRLMBSON(_options.projection_bson); +} + +- (id)sort { + return RLMConvertBsonDocumentToRLMBSON(_options.sort_bson); +} + +- (void)setProjection:(id)projection { + if (projection) { + auto bson = realm::bson::BsonDocument(RLMConvertRLMBSONToBson(projection)); + _options.projection_bson = realm::util::Optional(bson); + } else { + _options.projection_bson = realm::util::none; + } +} + +- (void)setSort:(id)sort { + if (sort) { + auto bson = realm::bson::BsonDocument(RLMConvertRLMBSONToBson(sort)); + _options.sort_bson = realm::util::Optional(bson); + } else { + _options.sort_bson = realm::util::none; + } +} + +- (NSInteger)limit { + return static_cast(_options.limit.value_or(0)); +} + +- (void)setLimit:(NSInteger)limit { + _options.limit = realm::util::Optional(limit); +} + +@end diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMListBase.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMListBase.mm new file mode 100644 index 0000000..882343e --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMListBase.mm @@ -0,0 +1,157 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// 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 "RLMListBase.h" + +#import "RLMArray_Private.hpp" +#import "RLMObjectSchema_Private.h" +#import "RLMObject_Private.hpp" +#import "RLMObservation.hpp" +#import "RLMProperty_Private.h" +#import "RLMRealm_Private.hpp" + +@interface RLMArray (KVO) +- (NSArray *)objectsAtIndexes:(__unused NSIndexSet *)indexes; +@end + +@implementation RLMListBase { + std::unique_ptr _observationInfo; +} + ++ (RLMArray *)_unmanagedArray { + return nil; +} + +- (instancetype)init { + return self = [super init]; +} + +- (instancetype)initWithArray:(RLMArray *)array { + self = [super init]; + if (self) { + __rlmArray = array; + } + return self; +} + +- (RLMArray *)_rlmArray { + if (!__rlmArray) { + __rlmArray = self.class._unmanagedArray; + } + return __rlmArray; +} + +- (id)valueForKey:(NSString *)key { + return [self._rlmArray valueForKey:key]; +} + +- (id)valueForKeyPath:(NSString *)keyPath { + return [self._rlmArray valueForKeyPath:keyPath]; +} + +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state + objects:(id __unsafe_unretained [])buffer + count:(NSUInteger)len { + return [self._rlmArray countByEnumeratingWithState:state objects:buffer count:len]; +} + +- (NSArray *)objectsAtIndexes:(NSIndexSet *)indexes { + return [self._rlmArray objectsAtIndexes:indexes]; +} + +- (void)addObserver:(id)observer + forKeyPath:(NSString *)keyPath + options:(NSKeyValueObservingOptions)options + context:(void *)context { + RLMEnsureArrayObservationInfo(_observationInfo, keyPath, self._rlmArray, self); + [super addObserver:observer forKeyPath:keyPath options:options context:context]; +} + +- (BOOL)isEqual:(id)object { + if (auto array = RLMDynamicCast(object)) { + return !array._rlmArray.realm + && ((self._rlmArray.count == 0 && array._rlmArray.count == 0) || + [self._rlmArray isEqual:array._rlmArray]); + } + return NO; +} + +@end + +@implementation RLMLinkingObjectsHandle { + realm::TableKey _tableKey; + realm::ObjKey _objKey; + RLMClassInfo *_info; + RLMRealm *_realm; + RLMProperty *_property; + + RLMResults *_results; +} + +- (instancetype)initWithObject:(RLMObjectBase *)object property:(RLMProperty *)prop { + if (!(self = [super init])) { + return nil; + } + auto& obj = object->_row; + _tableKey = obj.get_table()->get_key(); + _objKey = obj.get_key(); + _info = object->_info; + _realm = object->_realm; + _property = prop; + + return self; +} + +- (instancetype)initWithLinkingObjects:(RLMResults *)linkingObjects { + if (!(self = [super init])) { + return nil; + } + _realm = linkingObjects.realm; + _results = linkingObjects; + + return self; +} + +- (instancetype)freeze { + RLMLinkingObjectsHandle *frozen = [[self.class alloc] init]; + frozen->_results = [self.results freeze]; + return frozen; +} + +- (RLMResults *)results { + if (_results) { + return _results; + } + [_realm verifyThread]; + + auto table = _realm.group.get_table(_tableKey); + if (!table->is_valid(_objKey)) { + @throw RLMException(@"Object has been deleted or invalidated."); + } + + auto obj = _realm.group.get_table(_tableKey)->get_object(_objKey); + auto& objectInfo = _realm->_info[_property.objectClassName]; + auto& linkOrigin = _info->objectSchema->computed_properties[_property.index].link_origin_property_name; + auto linkingProperty = objectInfo.objectSchema->property_for_name(linkOrigin); + realm::Results results(_realm->_realm, obj.get_backlink_view(objectInfo.table(), linkingProperty->column_key)); + _results = [RLMLinkingObjects resultsWithObjectInfo:objectInfo results:std::move(results)]; + _realm = nil; + return _results; +} + +@end diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMManagedArray.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMManagedArray.mm new file mode 100644 index 0000000..189dd79 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMManagedArray.mm @@ -0,0 +1,560 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// 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 "RLMArray_Private.hpp" + +#import "RLMAccessor.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObjectStore.h" +#import "RLMObject_Private.hpp" +#import "RLMObservation.hpp" +#import "RLMProperty_Private.h" +#import "RLMQueryUtil.hpp" +#import "RLMRealm_Private.hpp" +#import "RLMSchema.h" +#import "RLMThreadSafeReference_Private.hpp" +#import "RLMUtil.hpp" + +#import "list.hpp" +#import "results.hpp" +#import "shared_realm.hpp" + +#import +#import + +@interface RLMManagedArrayHandoverMetadata : NSObject +@property (nonatomic) NSString *parentClassName; +@property (nonatomic) NSString *key; +@end + +@implementation RLMManagedArrayHandoverMetadata +@end + +@interface RLMManagedArray () +@end + +// +// RLMArray implementation +// +@implementation RLMManagedArray { +@public + realm::List _backingList; + RLMRealm *_realm; + RLMClassInfo *_objectInfo; + RLMClassInfo *_ownerInfo; + std::unique_ptr _observationInfo; +} + +- (RLMManagedArray *)initWithList:(realm::List)list + parentInfo:(RLMClassInfo *)parentInfo + property:(__unsafe_unretained RLMProperty *const)property { + if (property.type == RLMPropertyTypeObject) + self = [self initWithObjectClassName:property.objectClassName]; + else + self = [self initWithObjectType:property.type optional:property.optional]; + if (self) { + _realm = parentInfo->realm; + REALM_ASSERT(list.get_realm() == _realm->_realm); + _backingList = std::move(list); + _ownerInfo = parentInfo; + if (property.type == RLMPropertyTypeObject) + _objectInfo = &parentInfo->linkTargetType(property.index); + else + _objectInfo = _ownerInfo; + _key = property.name; + } + return self; +} + +- (RLMManagedArray *)initWithParent:(__unsafe_unretained RLMObjectBase *const)parentObject + property:(__unsafe_unretained RLMProperty *const)property { + __unsafe_unretained RLMRealm *const realm = parentObject->_realm; + auto col = parentObject->_info->tableColumn(property); + return [self initWithList:realm::List(realm->_realm, parentObject->_row, col) + parentInfo:parentObject->_info + property:property]; +} + +void RLMValidateArrayObservationKey(__unsafe_unretained NSString *const keyPath, + __unsafe_unretained RLMArray *const array) { + if (![keyPath isEqualToString:RLMInvalidatedKey]) { + @throw RLMException(@"[<%@ %p> addObserver:forKeyPath:options:context:] is not supported. Key path: %@", + [array class], array, keyPath); + } +} + +void RLMEnsureArrayObservationInfo(std::unique_ptr& info, + __unsafe_unretained NSString *const keyPath, + __unsafe_unretained RLMArray *const array, + __unsafe_unretained id const observed) { + RLMValidateArrayObservationKey(keyPath, array); + if (!info && array.class == [RLMManagedArray class]) { + auto lv = static_cast(array); + info = std::make_unique(*lv->_ownerInfo, + lv->_backingList.get_parent_object_key(), + observed); + } +} + +// +// validation helpers +// +[[gnu::noinline]] +[[noreturn]] +static void throwError(__unsafe_unretained RLMManagedArray *const ar, NSString *aggregateMethod) { + try { + throw; + } + catch (realm::InvalidTransactionException const&) { + @throw RLMException(@"Cannot modify managed RLMArray outside of a write transaction."); + } + catch (realm::IncorrectThreadException const&) { + @throw RLMException(@"Realm accessed from incorrect thread."); + } + catch (realm::List::InvalidatedException const&) { + @throw RLMException(@"RLMArray has been invalidated or the containing object has been deleted."); + } + catch (realm::List::OutOfBoundsIndexException const& e) { + @throw RLMException(@"Index %zu is out of bounds (must be less than %zu).", + e.requested, e.valid_count); + } + catch (realm::Results::UnsupportedColumnTypeException const& e) { + if (ar->_backingList.get_type() == realm::PropertyType::Object) { + @throw RLMException(@"%@: is not supported for %s%s property '%s'.", + aggregateMethod, + string_for_property_type(e.property_type), + is_nullable(e.property_type) ? "?" : "", + e.column_name.data()); + } + @throw RLMException(@"%@: is not supported for %s%s array '%@.%@'.", + aggregateMethod, + string_for_property_type(e.property_type), + is_nullable(e.property_type) ? "?" : "", + ar->_ownerInfo->rlmObjectSchema.className, ar->_key); + } + catch (std::logic_error const& e) { + @throw RLMException(e); + } +} + +template +static auto translateErrors(__unsafe_unretained RLMManagedArray *const ar, + Function&& f, NSString *aggregateMethod=nil) { + try { + return f(); + } + catch (...) { + throwError(ar, aggregateMethod); + } +} + +template +static auto translateErrors(Function&& f) { + try { + return f(); + } + catch (...) { + throwError(nil, nil); + } +} + +template +static void changeArray(__unsafe_unretained RLMManagedArray *const ar, + NSKeyValueChange kind, dispatch_block_t f, IndexSetFactory&& is) { + translateErrors([&] { ar->_backingList.verify_in_transaction(); }); + + RLMObservationTracker tracker(ar->_realm); + tracker.trackDeletions(); + auto obsInfo = RLMGetObservationInfo(ar->_observationInfo.get(), + ar->_backingList.get_parent_object_key(), + *ar->_ownerInfo); + if (obsInfo) { + tracker.willChange(obsInfo, ar->_key, kind, is()); + } + + translateErrors(f); +} + +static void changeArray(__unsafe_unretained RLMManagedArray *const ar, NSKeyValueChange kind, NSUInteger index, dispatch_block_t f) { + changeArray(ar, kind, f, [=] { return [NSIndexSet indexSetWithIndex:index]; }); +} + +static void changeArray(__unsafe_unretained RLMManagedArray *const ar, NSKeyValueChange kind, NSRange range, dispatch_block_t f) { + changeArray(ar, kind, f, [=] { return [NSIndexSet indexSetWithIndexesInRange:range]; }); +} + +static void changeArray(__unsafe_unretained RLMManagedArray *const ar, NSKeyValueChange kind, NSIndexSet *is, dispatch_block_t f) { + changeArray(ar, kind, f, [=] { return is; }); +} + +// +// public method implementations +// +- (RLMRealm *)realm { + return _realm; +} + +- (NSUInteger)count { + return translateErrors([&] { return _backingList.size(); }); +} + +- (BOOL)isInvalidated { + return translateErrors([&] { return !_backingList.is_valid(); }); +} + +- (RLMClassInfo *)objectInfo { + return _objectInfo; +} + + +- (bool)isBackedByList:(realm::List const&)list { + return _backingList == list; +} + +- (BOOL)isEqual:(id)object { + return [object respondsToSelector:@selector(isBackedByList:)] && [object isBackedByList:_backingList]; +} + +- (NSUInteger)hash { + return std::hash()(_backingList); +} + +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state + objects:(__unused __unsafe_unretained id [])buffer + count:(NSUInteger)len { + return RLMFastEnumerate(state, len, self); +} + +- (id)objectAtIndex:(NSUInteger)index { + return translateErrors([&] { + RLMAccessorContext context(*_objectInfo); + return _backingList.get(context, index); + }); +} + +static void RLMInsertObject(RLMManagedArray *ar, id object, NSUInteger index) { + RLMArrayValidateMatchingObjectType(ar, object); + if (index == NSUIntegerMax) { + index = translateErrors([&] { return ar->_backingList.size(); }); + } + + changeArray(ar, NSKeyValueChangeInsertion, index, ^{ + RLMAccessorContext context(*ar->_objectInfo); + ar->_backingList.insert(context, index, object); + }); +} + +- (void)addObject:(id)object { + RLMInsertObject(self, object, NSUIntegerMax); +} + +- (void)insertObject:(id)object atIndex:(NSUInteger)index { + RLMInsertObject(self, object, index); +} + +- (void)insertObjects:(id)objects atIndexes:(NSIndexSet *)indexes { + changeArray(self, NSKeyValueChangeInsertion, indexes, ^{ + NSUInteger index = [indexes firstIndex]; + RLMAccessorContext context(*_objectInfo); + for (id obj in objects) { + RLMArrayValidateMatchingObjectType(self, obj); + _backingList.insert(context, index, obj); + index = [indexes indexGreaterThanIndex:index]; + } + }); +} + + +- (void)removeObjectAtIndex:(NSUInteger)index { + changeArray(self, NSKeyValueChangeRemoval, index, ^{ + _backingList.remove(index); + }); +} + +- (void)removeObjectsAtIndexes:(NSIndexSet *)indexes { + changeArray(self, NSKeyValueChangeRemoval, indexes, ^{ + [indexes enumerateIndexesWithOptions:NSEnumerationReverse usingBlock:^(NSUInteger idx, BOOL *) { + _backingList.remove(idx); + }]; + }); +} + +- (void)addObjectsFromArray:(NSArray *)array { + changeArray(self, NSKeyValueChangeInsertion, NSMakeRange(self.count, array.count), ^{ + RLMAccessorContext context(*_objectInfo); + for (id obj in array) { + RLMArrayValidateMatchingObjectType(self, obj); + _backingList.add(context, obj); + } + }); +} + +- (void)removeAllObjects { + changeArray(self, NSKeyValueChangeRemoval, NSMakeRange(0, self.count), ^{ + _backingList.remove_all(); + }); +} + +- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)object { + RLMArrayValidateMatchingObjectType(self, object); + changeArray(self, NSKeyValueChangeReplacement, index, ^{ + RLMAccessorContext context(*_objectInfo); + _backingList.set(context, index, object); + }); +} + +- (void)moveObjectAtIndex:(NSUInteger)sourceIndex toIndex:(NSUInteger)destinationIndex { + auto start = std::min(sourceIndex, destinationIndex); + auto len = std::max(sourceIndex, destinationIndex) - start + 1; + changeArray(self, NSKeyValueChangeReplacement, {start, len}, ^{ + _backingList.move(sourceIndex, destinationIndex); + }); +} + +- (void)exchangeObjectAtIndex:(NSUInteger)index1 withObjectAtIndex:(NSUInteger)index2 { + changeArray(self, NSKeyValueChangeReplacement, ^{ + _backingList.swap(index1, index2); + }, [=] { + NSMutableIndexSet *set = [[NSMutableIndexSet alloc] initWithIndex:index1]; + [set addIndex:index2]; + return set; + }); +} + +- (NSUInteger)indexOfObject:(id)object { + RLMArrayValidateMatchingObjectType(self, object); + return translateErrors([&] { + RLMAccessorContext context(*_objectInfo); + return RLMConvertNotFound(_backingList.find(context, object)); + }); +} + +- (id)valueForKeyPath:(NSString *)keyPath { + if ([keyPath hasPrefix:@"@"]) { + // Delegate KVC collection operators to RLMResults + return translateErrors([&] { + auto results = [RLMResults resultsWithObjectInfo:*_objectInfo results:_backingList.as_results()]; + return [results valueForKeyPath:keyPath]; + }); + } + return [super valueForKeyPath:keyPath]; +} + +- (id)valueForKey:(NSString *)key { + // Ideally we'd use "@invalidated" for this so that "invalidated" would use + // normal array KVC semantics, but observing @things works very oddly (when + // it's part of a key path, it's triggered automatically when array index + // changes occur, and can't be sent explicitly, but works normally when it's + // the entire key path), and an RLMManagedArray *can't* have objects where + // invalidated is true, so we're not losing much. + return translateErrors([&]() -> id { + if ([key isEqualToString:RLMInvalidatedKey]) { + return @(!_backingList.is_valid()); + } + + _backingList.verify_attached(); + return RLMCollectionValueForKey(_backingList, key, *_objectInfo); + }); +} + +- (void)setValue:(id)value forKey:(NSString *)key { + if ([key isEqualToString:@"self"]) { + RLMArrayValidateMatchingObjectType(self, value); + RLMAccessorContext context(*_objectInfo); + translateErrors([&] { + for (size_t i = 0, count = _backingList.size(); i < count; ++i) { + _backingList.set(context, i, value); + } + }); + return; + } + else if (_type == RLMPropertyTypeObject) { + RLMArrayValidateMatchingObjectType(self, value); + translateErrors([&] { _backingList.verify_in_transaction(); }); + RLMCollectionSetValueForKey(self, key, value); + } + else { + [self setValue:value forUndefinedKey:key]; + } +} + +- (realm::ColKey)columnForProperty:(NSString *)propertyName { + if (_backingList.get_type() == realm::PropertyType::Object) { + return _objectInfo->tableColumn(propertyName); + } + if (![propertyName isEqualToString:@"self"]) { + @throw RLMException(@"Arrays of '%@' can only be aggregated on \"self\"", RLMTypeToString(_type)); + } + return {}; +} + +- (id)minOfProperty:(NSString *)property { + auto column = [self columnForProperty:property]; + auto value = translateErrors(self, [&] { return _backingList.min(column); }, @"minOfProperty"); + return value ? RLMMixedToObjc(*value) : nil; +} + +- (id)maxOfProperty:(NSString *)property { + auto column = [self columnForProperty:property]; + auto value = translateErrors(self, [&] { return _backingList.max(column); }, @"maxOfProperty"); + return value ? RLMMixedToObjc(*value) : nil; +} + +- (id)sumOfProperty:(NSString *)property { + auto column = [self columnForProperty:property]; + return RLMMixedToObjc(translateErrors(self, [&] { return _backingList.sum(column); }, @"sumOfProperty")); +} + +- (id)averageOfProperty:(NSString *)property { + auto column = [self columnForProperty:property]; + auto value = translateErrors(self, [&] { return _backingList.average(column); }, @"averageOfProperty"); + return value ? RLMMixedToObjc(*value) : nil; +} + +- (void)deleteObjectsFromRealm { + if (_type != RLMPropertyTypeObject) { + @throw RLMException(@"Cannot delete objects from RLMArray<%@>: only RLMObjects can be deleted.", RLMTypeToString(_type)); + } + // delete all target rows from the realm + RLMObservationTracker tracker(_realm, true); + translateErrors([&] { _backingList.delete_all(); }); +} + +- (RLMResults *)sortedResultsUsingDescriptors:(NSArray *)properties { + return translateErrors([&] { + return [RLMResults resultsWithObjectInfo:*_objectInfo + results:_backingList.sort(RLMSortDescriptorsToKeypathArray(properties))]; + }); +} + +- (RLMResults *)distinctResultsUsingKeyPaths:(NSArray *)keyPaths { + return translateErrors([&] { + auto results = [RLMResults resultsWithObjectInfo:*_objectInfo results:_backingList.as_results()]; + return [results distinctResultsUsingKeyPaths:keyPaths]; + }); +} + +- (RLMResults *)objectsWithPredicate:(NSPredicate *)predicate { + if (_type != RLMPropertyTypeObject) { + @throw RLMException(@"Querying is currently only implemented for arrays of Realm Objects"); + } + auto query = RLMPredicateToQuery(predicate, _objectInfo->rlmObjectSchema, _realm.schema, _realm.group); + auto results = translateErrors([&] { return _backingList.filter(std::move(query)); }); + return [RLMResults resultsWithObjectInfo:*_objectInfo results:std::move(results)]; +} + +- (NSUInteger)indexOfObjectWithPredicate:(NSPredicate *)predicate { + if (_type != RLMPropertyTypeObject) { + @throw RLMException(@"Querying is currently only implemented for arrays of Realm Objects"); + } + realm::Query query = RLMPredicateToQuery(predicate, _objectInfo->rlmObjectSchema, + _realm.schema, _realm.group); + + return translateErrors([&] { + return RLMConvertNotFound(_backingList.find(std::move(query))); + }); +} + +- (NSArray *)objectsAtIndexes:(__unused NSIndexSet *)indexes { + // FIXME: this is called by KVO when array changes are made. It's not clear + // why, and returning nil seems to work fine. + return nil; +} + +- (void)addObserver:(id)observer + forKeyPath:(NSString *)keyPath + options:(NSKeyValueObservingOptions)options + context:(void *)context { + RLMEnsureArrayObservationInfo(_observationInfo, keyPath, self, self); + [super addObserver:observer forKeyPath:keyPath options:options context:context]; +} + +- (realm::TableView)tableView { + return translateErrors([&] { return _backingList.get_query(); }).find_all(); +} + +- (RLMFastEnumerator *)fastEnumerator { + return translateErrors([&] { + return [[RLMFastEnumerator alloc] initWithList:_backingList collection:self + classInfo:*_objectInfo]; + }); +} + +- (BOOL)isFrozen { + return _realm.isFrozen; +} + +- (instancetype)freeze { + if (self.frozen) { + return self; + } + + RLMRealm *frozenRealm = [_realm freeze]; + auto& parentInfo = _ownerInfo->freeze(frozenRealm); + return translateRLMResultsErrors([&] { + return [[self.class alloc] initWithList:_backingList.freeze(frozenRealm->_realm) + parentInfo:&parentInfo + property:parentInfo.rlmObjectSchema[_key]]; + }); +} + +// The compiler complains about the method's argument type not matching due to +// it not having the generic type attached, but it doesn't seem to be possible +// to actually include the generic type +// http://www.openradar.me/radar?id=6135653276319744 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wmismatched-parameter-types" +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMArray *, RLMCollectionChange *, NSError *))block { + return RLMAddNotificationBlock(self, block, nil); +} +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMArray *, RLMCollectionChange *, NSError *))block queue:(dispatch_queue_t)queue { + return RLMAddNotificationBlock(self, block, queue); +} +#pragma clang diagnostic pop + +realm::List& RLMGetBackingCollection(RLMManagedArray *self) { + return self->_backingList; +} + +#pragma mark - Thread Confined Protocol Conformance + +- (realm::ThreadSafeReference)makeThreadSafeReference { + return _backingList; +} + +- (RLMManagedArrayHandoverMetadata *)objectiveCMetadata { + RLMManagedArrayHandoverMetadata *metadata = [[RLMManagedArrayHandoverMetadata alloc] init]; + metadata.parentClassName = _ownerInfo->rlmObjectSchema.className; + metadata.key = _key; + return metadata; +} + ++ (instancetype)objectWithThreadSafeReference:(realm::ThreadSafeReference)reference + metadata:(RLMManagedArrayHandoverMetadata *)metadata + realm:(RLMRealm *)realm { + auto list = reference.resolve(realm->_realm); + if (!list.is_valid()) { + return nil; + } + RLMClassInfo *parentInfo = &realm->_info[metadata.parentClassName]; + return [[RLMManagedArray alloc] initWithList:std::move(list) + parentInfo:parentInfo + property:parentInfo->rlmObjectSchema[metadata.key]]; +} + +@end diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMMigration.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMMigration.mm new file mode 100644 index 0000000..d1a6ebb --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMMigration.mm @@ -0,0 +1,170 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// 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 "RLMMigration_Private.h" + +#import "RLMAccessor.h" +#import "RLMObject_Private.h" +#import "RLMObject_Private.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObjectStore.h" +#import "RLMProperty_Private.h" +#import "RLMRealm_Dynamic.h" +#import "RLMRealm_Private.hpp" +#import "RLMResults_Private.hpp" +#import "RLMSchema_Private.hpp" +#import "RLMUtil.hpp" + +#import "object_store.hpp" +#import "shared_realm.hpp" +#import "schema.hpp" + +#import + +using namespace realm; + +// The source realm for a migration has to use a SharedGroup to be able to share +// the file with the destination realm, but we don't want to let the user call +// beginWriteTransaction on it as that would make no sense. +@interface RLMMigrationRealm : RLMRealm +@end + +@implementation RLMMigrationRealm +- (BOOL)readonly { + return YES; +} + +- (void)beginWriteTransaction { + @throw RLMException(@"Cannot modify the source Realm in a migration"); +} +@end + +@implementation RLMMigration { + realm::Schema *_schema; +} + +- (instancetype)initWithRealm:(RLMRealm *)realm oldRealm:(RLMRealm *)oldRealm schema:(realm::Schema &)schema { + self = [super init]; + if (self) { + _realm = realm; + _oldRealm = oldRealm; + _schema = &schema; + object_setClass(_oldRealm, RLMMigrationRealm.class); + } + return self; +} + +- (RLMSchema *)oldSchema { + return self.oldRealm.schema; +} + +- (RLMSchema *)newSchema { + return self.realm.schema; +} + +- (void)enumerateObjects:(NSString *)className block:(__attribute__((noescape)) RLMObjectMigrationBlock)block { + RLMResults *objects = [_realm.schema schemaForClassName:className] ? [_realm allObjects:className] : nil; + RLMResults *oldObjects = [_oldRealm.schema schemaForClassName:className] ? [_oldRealm allObjects:className] : nil; + + // For whatever reason if this is a newly added table we enumerate the + // objects in it, while in all other cases we enumerate only the existing + // objects. It's unclear how this could be useful, but changing it would + // also be a pointless breaking change and it's unlikely to be hurting anyone. + if (objects && !oldObjects) { + for (RLMObject *object in objects) { + @autoreleasepool { + block(nil, object); + } + } + return; + } + + if (oldObjects.count == 0 || objects.count == 0) { + return; + } + + auto& info = _realm->_info[className]; + for (RLMObject *oldObject in oldObjects) { + @autoreleasepool { + Obj newObj; + try { + newObj = info.table()->get_object(oldObject->_row.get_key()); + } + catch (KeyNotFound const&) { + continue; + } + block(oldObject, (id)RLMCreateObjectAccessor(info, std::move(newObj))); + } + } +} + +- (void)execute:(RLMMigrationBlock)block { + @autoreleasepool { + // disable all primary keys for migration and use DynamicObject for all types + for (RLMObjectSchema *objectSchema in _realm.schema.objectSchema) { + objectSchema.accessorClass = RLMDynamicObject.class; + objectSchema.primaryKeyProperty.isPrimary = NO; + } + for (RLMObjectSchema *objectSchema in _oldRealm.schema.objectSchema) { + objectSchema.accessorClass = RLMDynamicObject.class; + } + + block(self, _oldRealm->_realm->schema_version()); + + _oldRealm = nil; + _realm = nil; + } +} + +- (RLMObject *)createObject:(NSString *)className withValue:(id)value { + return [_realm createObject:className withValue:value]; +} + +- (RLMObject *)createObject:(NSString *)className withObject:(id)object { + return [self createObject:className withValue:object]; +} + +- (void)deleteObject:(RLMObject *)object { + [_realm deleteObject:object]; +} + +- (BOOL)deleteDataForClassName:(NSString *)name { + if (!name) { + return false; + } + + TableRef table = ObjectStore::table_for_object_type(_realm.group, name.UTF8String); + if (!table) { + return false; + } + if ([_realm.schema schemaForClassName:name]) { + table->clear(); + } + else { + _realm.group.remove_table(table->get_key()); + } + + return true; +} + +- (void)renamePropertyForClass:(NSString *)className oldName:(NSString *)oldName newName:(NSString *)newName { + realm::ObjectStore::rename_property(_realm.group, *_schema, className.UTF8String, + oldName.UTF8String, newName.UTF8String); +} + +@end diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMMongoClient.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMMongoClient.mm new file mode 100644 index 0000000..bb5a132 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMMongoClient.mm @@ -0,0 +1,67 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 "RLMMongoClient_Private.hpp" +#import "RLMMongoDatabase_Private.hpp" +#import "RLMMongoCollection_Private.hpp" +#import "RLMApp_Private.hpp" + +#import "sync/remote_mongo_client.hpp" +#import "sync/remote_mongo_database.hpp" + +#import + +@implementation RLMMongoClient + +- (instancetype)initWithUser:(RLMUser *)user serviceName:(NSString *)serviceName { + if (self = [super init]) { + _user = user; + _name = serviceName; + } + return self; +} + +- (RLMMongoDatabase *)databaseWithName:(NSString *)name { + return [[RLMMongoDatabase alloc] initWithUser:self.user + serviceName:self.name + databaseName:name]; +} + +@end + +@implementation RLMMongoDatabase + +- (instancetype)initWithUser:(RLMUser *)user + serviceName:(NSString *)serviceName + databaseName:(NSString *)databaseName { + if (self = [super init]) { + _user = user; + _serviceName = serviceName; + _name = databaseName; + } + return self; +} + +- (RLMMongoCollection *)collectionWithName:(NSString *)name { + return [[RLMMongoCollection alloc] initWithUser:self.user + serviceName:self.serviceName + databaseName:self.name + collectionName:name]; +} + +@end diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMMongoCollection.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMMongoCollection.mm new file mode 100644 index 0000000..38997e1 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMMongoCollection.mm @@ -0,0 +1,419 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 "RLMMongoCollection_Private.hpp" + +#import "RLMApp_Private.hpp" +#import "RLMBSON_Private.hpp" +#import "RLMFindOneAndModifyOptions_Private.hpp" +#import "RLMFindOptions_Private.hpp" +#import "RLMNetworkTransport_Private.hpp" +#import "RLMUpdateResult_Private.hpp" +#import "RLMUser_Private.hpp" + +#import "sync/remote_mongo_client.hpp" +#import "sync/remote_mongo_collection.hpp" +#import "sync/remote_mongo_database.hpp" + +@implementation RLMChangeStream { + realm::app::WatchStream _watchStream; + id _subscriber; + __weak NSURLSession *_session; + _Nonnull dispatch_queue_t _queue; +} + +- (instancetype)initWithChangeEventSubscriber:(id)subscriber + delegateQueue:(nullable dispatch_queue_t)queue { + if (self = [super init]) { + _subscriber = subscriber; + _queue = queue ?: dispatch_get_main_queue(); + return self; + } + return nil; +} + +- (void)didCloseWithError:(NSError *)error { + dispatch_async(_queue, ^{ + [_subscriber changeStreamDidCloseWithError:error]; + }); +} + +- (void)didOpen { + dispatch_async(_queue, ^{ + [_subscriber changeStreamDidOpen:self]; + }); +} + +- (void)didReceiveError:(nonnull NSError *)error { + dispatch_async(_queue, ^{ + [_subscriber changeStreamDidReceiveError:error]; + }); +} + +- (void)didReceiveEvent:(nonnull NSData *)event { + std::string_view str = [[NSString alloc] initWithData:event encoding:NSUTF8StringEncoding].UTF8String; + if (!str.empty() && _watchStream.state() == realm::app::WatchStream::State::NEED_DATA) { + _watchStream.feed_buffer(str); + } + + while (_watchStream.state() == realm::app::WatchStream::State::HAVE_EVENT) { + id event = RLMConvertBsonToRLMBSON(_watchStream.next_event()); + dispatch_async(_queue, ^{ + [_subscriber changeStreamDidReceiveChangeEvent:event]; + }); + } + + if (_watchStream.state() == realm::app::WatchStream::State::HAVE_ERROR) { + [self didReceiveError:RLMAppErrorToNSError(_watchStream.error())]; + } +} + +- (void)attachURLSession:(NSURLSession *)urlSession { + _session = urlSession; +} + +- (void)close { + [_session invalidateAndCancel]; +} + +@end + +@implementation RLMMongoCollection + +static realm::bson::BsonDocument toBsonDocument(id bson) { + return realm::bson::BsonDocument(RLMConvertRLMBSONToBson(bson)); +} +static realm::bson::BsonArray toBsonArray(id bson) { + return realm::bson::BsonArray(RLMConvertRLMBSONToBson(bson)); +} + +- (instancetype)initWithUser:(RLMUser *)user + serviceName:(NSString *)serviceName + databaseName:(NSString *)databaseName + collectionName:(NSString *)collectionName { + if (self = [super init]) { + _user = user; + _serviceName = serviceName; + _databaseName = databaseName; + _name = collectionName; + } + return self; +} + +- (realm::app::MongoCollection)collection:(NSString *)name { + return _user._syncUser->mongo_client(self.serviceName.UTF8String) + .db(self.databaseName.UTF8String).collection(name.UTF8String); +} + +- (realm::app::MongoCollection)collection { + return [self collection:self.name]; +} + +- (void)findWhere:(NSDictionary> *)document + options:(RLMFindOptions *)options + completion:(RLMMongoFindBlock)completion { + self.collection.find(toBsonDocument(document), [options _findOptions], + [completion](realm::util::Optional documents, + realm::util::Optional error) { + if (error) { + return completion(nil, RLMAppErrorToNSError(*error)); + } + completion((NSArray> *> *)RLMConvertBsonToRLMBSON(*documents), nil); + }); +} + +- (void)findWhere:(NSDictionary> *)document + completion:(RLMMongoFindBlock)completion { + [self findWhere:document options:[[RLMFindOptions alloc] init] completion:completion]; +} + +- (void)findOneDocumentWhere:(NSDictionary> *)document + options:(RLMFindOptions *)options + completion:(RLMMongoFindOneBlock)completion { + self.collection.find_one(toBsonDocument(document), [options _findOptions], + [completion](realm::util::Optional document, + realm::util::Optional error) { + if (error) { + return completion(nil, RLMAppErrorToNSError(*error)); + } + completion((NSDictionary> *)RLMConvertBsonToRLMBSON(*document), nil); + }); +} + +- (void)findOneDocumentWhere:(NSDictionary> *)document + completion:(RLMMongoFindOneBlock)completion { + [self findOneDocumentWhere:document options:[[RLMFindOptions alloc] init] completion:completion]; +} + +- (void)insertOneDocument:(NSDictionary> *)document + completion:(RLMMongoInsertBlock)completion { + self.collection.insert_one(toBsonDocument(document), + [completion](realm::util::Optional objectId, + realm::util::Optional error) { + if (error) { + return completion(nil, RLMAppErrorToNSError(*error)); + } + completion(RLMConvertBsonToRLMBSON(*objectId), nil); + }); +} + +- (void)insertManyDocuments:(NSArray> *> *)documents + completion:(RLMMongoInsertManyBlock)completion { + self.collection.insert_many(toBsonArray(documents), + [completion](std::vector insertedIds, + realm::util::Optional error) { + if (error) { + return completion(nil, RLMAppErrorToNSError(*error)); + } + NSMutableArray *insertedArr = [[NSMutableArray alloc] initWithCapacity:insertedIds.size()]; + for (auto& objectId : insertedIds) { + [insertedArr addObject:RLMConvertBsonToRLMBSON(objectId)]; + } + completion(insertedArr, nil); + }); +} + +- (void)aggregateWithPipeline:(NSArray> *> *)pipeline + completion:(RLMMongoFindBlock)completion { + self.collection.aggregate(toBsonArray(pipeline), + [completion](realm::util::Optional documents, + realm::util::Optional error) { + if (error) { + return completion(nil, RLMAppErrorToNSError(*error)); + } + completion((NSArray *)RLMConvertBsonToRLMBSON(*documents), nil); + }); +} + +- (void)countWhere:(NSDictionary> *)document + limit:(NSInteger)limit + completion:(RLMMongoCountBlock)completion { + self.collection.count(toBsonDocument(document), limit, + [completion](uint64_t count, + realm::util::Optional error) { + if (error) { + return completion(0, RLMAppErrorToNSError(*error)); + } + completion(static_cast(count), nil); + }); +} + +- (void)countWhere:(NSDictionary> *)document + completion:(RLMMongoCountBlock)completion { + [self countWhere:document limit:0 completion:completion]; +} + +- (void)deleteOneDocumentWhere:(NSDictionary> *)document + completion:(RLMMongoCountBlock)completion { + self.collection.delete_one(toBsonDocument(document), + [completion](uint64_t count, + realm::util::Optional error) { + if (error) { + return completion(0, RLMAppErrorToNSError(*error)); + } + completion(static_cast(count), nil); + }); +} + +- (void)deleteManyDocumentsWhere:(NSDictionary> *)document + completion:(RLMMongoCountBlock)completion { + self.collection.delete_many(toBsonDocument(document), + [completion](uint64_t count, + realm::util::Optional error) { + if (error) { + return completion(0, RLMAppErrorToNSError(*error)); + } + completion(static_cast(count), nil); + }); +} + +- (void)updateOneDocumentWhere:(NSDictionary> *)filterDocument + updateDocument:(NSDictionary> *)updateDocument + upsert:(BOOL)upsert + completion:(RLMMongoUpdateBlock)completion { + self.collection.update_one(toBsonDocument(filterDocument), toBsonDocument(updateDocument), + upsert, + [completion](realm::app::MongoCollection::UpdateResult result, + realm::util::Optional error) { + if (error) { + return completion(nil, RLMAppErrorToNSError(*error)); + } + completion([[RLMUpdateResult alloc] initWithUpdateResult:result], nil); + }); +} + +- (void)updateOneDocumentWhere:(NSDictionary> *)filterDocument + updateDocument:(NSDictionary> *)updateDocument + completion:(RLMMongoUpdateBlock)completion { + [self updateOneDocumentWhere:filterDocument + updateDocument:updateDocument + upsert:NO + completion:completion]; +} + +- (void)updateManyDocumentsWhere:(NSDictionary> *)filterDocument + updateDocument:(NSDictionary> *)updateDocument + upsert:(BOOL)upsert + completion:(RLMMongoUpdateBlock)completion { + self.collection.update_many(toBsonDocument(filterDocument), toBsonDocument(updateDocument), + upsert, + [completion](realm::app::MongoCollection::UpdateResult result, + realm::util::Optional error) { + if (error) { + return completion(nil, RLMAppErrorToNSError(*error)); + } + completion([[RLMUpdateResult alloc] initWithUpdateResult:result], nil); + }); +} + +- (void)updateManyDocumentsWhere:(NSDictionary> *)filterDocument + updateDocument:(NSDictionary> *)updateDocument + completion:(RLMMongoUpdateBlock)completion { + [self updateManyDocumentsWhere:filterDocument + updateDocument:updateDocument + upsert:NO + completion:completion]; +} + +- (void)findOneAndUpdateWhere:(NSDictionary> *)filterDocument + updateDocument:(NSDictionary> *)updateDocument + options:(RLMFindOneAndModifyOptions *)options + completion:(RLMMongoFindOneBlock)completion { + self.collection.find_one_and_update(toBsonDocument(filterDocument), toBsonDocument(updateDocument), + [options _findOneAndModifyOptions], + [completion](realm::util::Optional document, + realm::util::Optional error) { + if (error) { + return completion(nil, RLMAppErrorToNSError(*error)); + } + + return completion((NSDictionary *)RLMConvertBsonDocumentToRLMBSON(document), nil); + }); +} + +- (void)findOneAndUpdateWhere:(NSDictionary> *)filterDocument + updateDocument:(NSDictionary> *)updateDocument + completion:(RLMMongoFindOneBlock)completion { + [self findOneAndUpdateWhere:filterDocument + updateDocument:updateDocument + options:[[RLMFindOneAndModifyOptions alloc] init] + completion:completion]; +} + +- (void)findOneAndReplaceWhere:(NSDictionary> *)filterDocument + replacementDocument:(NSDictionary> *)replacementDocument + options:(RLMFindOneAndModifyOptions *)options + completion:(RLMMongoFindOneBlock)completion { + self.collection.find_one_and_replace(toBsonDocument(filterDocument), toBsonDocument(replacementDocument), + [options _findOneAndModifyOptions], + [completion](realm::util::Optional document, + realm::util::Optional error) { + if (error) { + return completion(nil, RLMAppErrorToNSError(*error)); + } + + return completion((NSDictionary *)RLMConvertBsonDocumentToRLMBSON(document), nil); + }); +} + +- (void)findOneAndReplaceWhere:(NSDictionary> *)filterDocument + replacementDocument:(NSDictionary> *)replacementDocument + completion:(RLMMongoFindOneBlock)completion { + [self findOneAndReplaceWhere:filterDocument + replacementDocument:replacementDocument + options:[[RLMFindOneAndModifyOptions alloc] init] + completion:completion]; +} + +- (void)findOneAndDeleteWhere:(NSDictionary> *)filterDocument + options:(RLMFindOneAndModifyOptions *)options + completion:(RLMMongoDeleteBlock)completion { + self.collection.find_one_and_delete(toBsonDocument(filterDocument), + [options _findOneAndModifyOptions], + [completion](realm::util::Optional document, + realm::util::Optional error) { + if (error) { + return completion(nil, RLMAppErrorToNSError(*error)); + } + + return completion((NSDictionary *)RLMConvertBsonDocumentToRLMBSON(document), nil); + }); +} + +- (void)findOneAndDeleteWhere:(NSDictionary> *)filterDocument + completion:(RLMMongoDeleteBlock)completion { + [self findOneAndDeleteWhere:filterDocument + options:[[RLMFindOneAndModifyOptions alloc] init] + completion:completion]; +} + +- (RLMChangeStream *)watchWithDelegate:(id)delegate + delegateQueue:(nullable dispatch_queue_t)delegateQueue { + return [self watchWithMatchFilter:nil + idFilter:nil + delegate:delegate + delegateQueue:delegateQueue]; +} + +- (RLMChangeStream *)watchWithFilterIds:(NSArray *)filterIds + delegate:(id)delegate + delegateQueue:(nullable dispatch_queue_t)delegateQueue { + return [self watchWithMatchFilter:nil + idFilter:filterIds + delegate:delegate + delegateQueue:delegateQueue]; +} + +- (RLMChangeStream *)watchWithMatchFilter:(NSDictionary> *)matchFilter + delegate:(id)delegate + delegateQueue:(nullable dispatch_queue_t)delegateQueue { + return [self watchWithMatchFilter:matchFilter + idFilter:nil + delegate:delegate + delegateQueue:delegateQueue]; +} + +- (RLMChangeStream *)watchWithMatchFilter:(nullable id)matchFilter + idFilter:(nullable id)idFilter + delegate:(id)delegate + delegateQueue:(nullable dispatch_queue_t)queue { + realm::bson::BsonDocument baseArgs = { + {"database", self.databaseName.UTF8String}, + {"collection", self.name.UTF8String} + }; + + if (matchFilter) { + baseArgs["filter"] = RLMConvertRLMBSONToBson(matchFilter); + } + if (idFilter) { + baseArgs["ids"] = RLMConvertRLMBSONToBson(idFilter); + } + auto args = realm::bson::BsonArray{baseArgs}; + auto app = self.user.app._realmApp; + auto request = app->make_streaming_request(app->current_user(), "watch", args, + realm::util::Optional(self.serviceName.UTF8String)); + RLMChangeStream *changeStream = [[RLMChangeStream alloc] initWithChangeEventSubscriber:delegate delegateQueue:queue]; + RLMNetworkTransport *transport = self.user.app.configuration.transport; + RLMRequest *rlmRequest = [transport RLMRequestFromRequest:request]; + NSURLSession *watchSession = [transport doStreamRequest:rlmRequest + eventSubscriber:changeStream]; + [changeStream attachURLSession:watchSession]; + return changeStream; +} + +@end diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMNetworkTransport.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMNetworkTransport.mm new file mode 100644 index 0000000..28881c1 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMNetworkTransport.mm @@ -0,0 +1,231 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 "RLMNetworkTransport_Private.hpp" + +#import "RLMApp.h" +#import "RLMRealmConfiguration.h" +#import "RLMSyncUtil_Private.hpp" +#import "RLMSyncManager_Private.hpp" +#import "RLMUtil.hpp" + +#import + +#import "sync/generic_network_transport.hpp" + +using namespace realm; + +typedef void(^RLMServerURLSessionCompletionBlock)(NSData *, NSURLResponse *, NSError *); + +static_assert((int)RLMHTTPMethodGET == (int)app::HttpMethod::get); +static_assert((int)RLMHTTPMethodPOST == (int)app::HttpMethod::post); +static_assert((int)RLMHTTPMethodPUT == (int)app::HttpMethod::put); +static_assert((int)RLMHTTPMethodPATCH == (int)app::HttpMethod::patch); +static_assert((int)RLMHTTPMethodDELETE == (int)app::HttpMethod::del); + +#pragma mark RLMSessionDelegate + +@interface RLMSessionDelegate : NSObject ++ (instancetype)delegateWithCompletion:(RLMNetworkTransportCompletionBlock)completion; +@end + +NSString * const RLMHTTPMethodToNSString[] = { + [RLMHTTPMethodGET] = @"GET", + [RLMHTTPMethodPOST] = @"POST", + [RLMHTTPMethodPUT] = @"PUT", + [RLMHTTPMethodPATCH] = @"PATCH", + [RLMHTTPMethodDELETE] = @"DELETE" +}; + +@implementation RLMRequest +@end + +@implementation RLMResponse +@end + +@interface RLMEventSessionDelegate : NSObject ++ (instancetype)delegateWithEventSubscriber:(RLMEventSubscriber *)subscriber; +@end; + +@implementation RLMNetworkTransport + +- (void)sendRequestToServer:(RLMRequest *) request + completion:(RLMNetworkTransportCompletionBlock)completionBlock; { + // Create the request + NSURL *requestURL = [[NSURL alloc] initWithString: request.url]; + NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:requestURL]; + urlRequest.HTTPMethod = RLMHTTPMethodToNSString[request.method]; + if (![urlRequest.HTTPMethod isEqualToString:@"GET"]) { + urlRequest.HTTPBody = [request.body dataUsingEncoding:NSUTF8StringEncoding]; + } + urlRequest.timeoutInterval = request.timeout; + + for (NSString *key in request.headers) { + [urlRequest addValue:request.headers[key] forHTTPHeaderField:key]; + } + id delegate = [RLMSessionDelegate delegateWithCompletion:completionBlock]; + auto session = [NSURLSession sessionWithConfiguration:NSURLSessionConfiguration.defaultSessionConfiguration + delegate:delegate delegateQueue:nil]; + + // Add the request to a task and start it + [[session dataTaskWithRequest:urlRequest] resume]; + // Tell the session to destroy itself once it's done with the request + [session finishTasksAndInvalidate]; +} + +- (NSURLSession *)doStreamRequest:(nonnull RLMRequest *)request + eventSubscriber:(nonnull id)subscriber { + NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration]; + sessionConfig.timeoutIntervalForRequest = 30; + sessionConfig.timeoutIntervalForResource = INT_MAX; + sessionConfig.HTTPAdditionalHeaders = @{ + @"Content-Type": @"text/event-stream", + @"Cache": @"no-cache", + @"Accept": @"text/event-stream" + }; + id delegate = [RLMEventSessionDelegate delegateWithEventSubscriber:subscriber]; + auto session = [NSURLSession sessionWithConfiguration:sessionConfig + delegate:delegate + delegateQueue:nil]; + NSURL *url = [[NSURL alloc] initWithString:request.url]; + [[session dataTaskWithURL:url] resume]; + return session; +} + +- (RLMRequest *)RLMRequestFromRequest:(const realm::app::Request)request { + RLMRequest *rlmRequest = [RLMRequest new]; + NSMutableDictionary *headersDict = [NSMutableDictionary new]; + for(auto &[key, value] : request.headers) { + [headersDict setValue:@(value.c_str()) forKey:@(key.c_str())]; + } + rlmRequest.headers = headersDict; + rlmRequest.method = static_cast(request.method); + rlmRequest.timeout = request.timeout_ms; + rlmRequest.url = @(request.url.c_str()); + rlmRequest.body = @(request.body.c_str()); + return rlmRequest; +} + +@end + +#pragma mark RLMSessionDelegate + +@implementation RLMSessionDelegate { + NSData *_data; + RLMNetworkTransportCompletionBlock _completionBlock; +} + ++ (instancetype)delegateWithCompletion:(RLMNetworkTransportCompletionBlock)completion { + RLMSessionDelegate *delegate = [RLMSessionDelegate new]; + delegate->_completionBlock = completion; + return delegate; +} + +- (void)URLSession:(__unused NSURLSession *)session + dataTask:(__unused NSURLSessionDataTask *)dataTask + didReceiveData:(NSData *)data { + if (!_data) { + _data = data; + return; + } + if (![_data respondsToSelector:@selector(appendData:)]) { + _data = [_data mutableCopy]; + } + [(id)_data appendData:data]; +} + +- (void)URLSession:(__unused NSURLSession *)session + task:(NSURLSessionTask *)task +didCompleteWithError:(NSError *)error +{ + RLMResponse *response = [RLMResponse new]; + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) task.response; + response.headers = httpResponse.allHeaderFields; + response.httpStatusCode = httpResponse.statusCode; + + if (error) { + response.body = [error localizedDescription]; + return _completionBlock(response); + } + + response.body = [[NSString alloc] initWithData:_data encoding:NSUTF8StringEncoding]; + + _completionBlock(response); +} + +@end + +@implementation RLMEventSessionDelegate { + RLMEventSubscriber *_subscriber; + bool _hasOpened; +} + ++ (instancetype)delegateWithEventSubscriber:(RLMEventSubscriber *)subscriber { + RLMEventSessionDelegate *delegate = [RLMEventSessionDelegate new]; + delegate->_subscriber = subscriber; + return delegate; +} + +- (void)URLSession:(__unused NSURLSession *)session + dataTask:(__unused NSURLSessionDataTask *)dataTask + didReceiveData:(NSData *)data { + if (!_hasOpened) { + _hasOpened = true; + [_subscriber didOpen]; + } + + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) dataTask.response; + if (httpResponse.statusCode != 200) { + NSString *errorStatus = [NSString stringWithFormat:@"URLSession HTTP error code: %ld", + (long)httpResponse.statusCode]; + NSError *error = [NSError errorWithDomain:RLMErrorDomain + code:0 + userInfo:@{NSLocalizedDescriptionKey: errorStatus}]; + return [_subscriber didCloseWithError:error]; + } + [_subscriber didReceiveEvent:data]; +} + +- (void)URLSession:(__unused NSURLSession *)session + task:(NSURLSessionTask *)task +didCompleteWithError:(NSError *)error +{ + RLMResponse *response = [RLMResponse new]; + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) task.response; + response.headers = httpResponse.allHeaderFields; + response.httpStatusCode = httpResponse.statusCode; + + // -999 indicates that the session was cancelled. + if (error && (error.code != -999)) { + response.body = [error localizedDescription]; + return [_subscriber didCloseWithError:error]; + } else if (error && (error.code == -999)) { + return [_subscriber didCloseWithError:nil]; + } + + if (response.httpStatusCode != 200) { + NSString *errorStatus = [NSString stringWithFormat:@"URLSession HTTP error code: %ld", + (long)httpResponse.statusCode]; + NSError *error = [NSError errorWithDomain:RLMErrorDomain + code:0 + userInfo:@{NSLocalizedDescriptionKey: errorStatus}]; + return [_subscriber didCloseWithError:error]; + } +} + +@end diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMObject.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMObject.mm new file mode 100644 index 0000000..731e2ad --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMObject.mm @@ -0,0 +1,238 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// 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 "RLMObject_Private.hpp" + +#import "RLMAccessor.h" +#import "RLMArray.h" +#import "RLMCollection_Private.hpp" +#import "RLMObjectBase_Private.h" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObjectStore.h" +#import "RLMProperty_Private.h" +#import "RLMQueryUtil.hpp" +#import "RLMRealm_Private.hpp" +#import "RLMSchema_Private.h" + +#import "object.hpp" + +// We declare things in RLMObject which are actually implemented in RLMObjectBase +// for documentation's sake, which leads to -Wunimplemented-method warnings. +// Other alternatives to this would be to disable -Wunimplemented-method for this +// file (but then we could miss legitimately missing things), or declaring the +// inherited things in a category (but they currently aren't nicely grouped for +// that). +@implementation RLMObject + +// synthesized in RLMObjectBase +@dynamic invalidated, realm, objectSchema; + +#pragma mark - Designated Initializers + +- (instancetype)init { + return [super init]; +} + +#pragma mark - Convenience Initializers + +- (instancetype)initWithValue:(id)value { + if (!(self = [self init])) { + return nil; + } + RLMInitializeWithValue(self, value, RLMSchema.partialPrivateSharedSchema); + return self; +} + +#pragma mark - Class-based Object Creation + ++ (instancetype)createInDefaultRealmWithValue:(id)value { + return (RLMObject *)RLMCreateObjectInRealmWithValue([RLMRealm defaultRealm], [self className], value, RLMUpdatePolicyError); +} + ++ (instancetype)createInRealm:(RLMRealm *)realm withValue:(id)value { + return (RLMObject *)RLMCreateObjectInRealmWithValue(realm, [self className], value, RLMUpdatePolicyError); +} + ++ (instancetype)createOrUpdateInDefaultRealmWithValue:(id)value { + return [self createOrUpdateInRealm:[RLMRealm defaultRealm] withValue:value]; +} + ++ (instancetype)createOrUpdateModifiedInDefaultRealmWithValue:(id)value { + return [self createOrUpdateModifiedInRealm:[RLMRealm defaultRealm] withValue:value]; +} + ++ (instancetype)createOrUpdateInRealm:(RLMRealm *)realm withValue:(id)value { + RLMVerifyHasPrimaryKey(self); + return (RLMObject *)RLMCreateObjectInRealmWithValue(realm, [self className], value, RLMUpdatePolicyUpdateAll); +} + ++ (instancetype)createOrUpdateModifiedInRealm:(RLMRealm *)realm withValue:(id)value { + RLMVerifyHasPrimaryKey(self); + return (RLMObject *)RLMCreateObjectInRealmWithValue(realm, [self className], value, RLMUpdatePolicyUpdateChanged); +} + +#pragma mark - Subscripting + +- (id)objectForKeyedSubscript:(NSString *)key { + return RLMObjectBaseObjectForKeyedSubscript(self, key); +} + +- (void)setObject:(id)obj forKeyedSubscript:(NSString *)key { + RLMObjectBaseSetObjectForKeyedSubscript(self, key, obj); +} + +#pragma mark - Getting & Querying + ++ (RLMResults *)allObjects { + return RLMGetObjects(RLMRealm.defaultRealm, self.className, nil); +} + ++ (RLMResults *)allObjectsInRealm:(__unsafe_unretained RLMRealm *const)realm { + return RLMGetObjects(realm, self.className, nil); +} + ++ (RLMResults *)objectsWhere:(NSString *)predicateFormat, ... { + va_list args; + va_start(args, predicateFormat); + RLMResults *results = [self objectsWhere:predicateFormat args:args]; + va_end(args); + return results; +} + ++ (RLMResults *)objectsWhere:(NSString *)predicateFormat args:(va_list)args { + return [self objectsWithPredicate:[NSPredicate predicateWithFormat:predicateFormat arguments:args]]; +} + ++ (RLMResults *)objectsInRealm:(RLMRealm *)realm where:(NSString *)predicateFormat, ... { + va_list args; + va_start(args, predicateFormat); + RLMResults *results = [self objectsInRealm:realm where:predicateFormat args:args]; + va_end(args); + return results; +} + ++ (RLMResults *)objectsInRealm:(RLMRealm *)realm where:(NSString *)predicateFormat args:(va_list)args { + return [self objectsInRealm:realm withPredicate:[NSPredicate predicateWithFormat:predicateFormat arguments:args]]; +} + ++ (RLMResults *)objectsWithPredicate:(NSPredicate *)predicate { + return RLMGetObjects(RLMRealm.defaultRealm, self.className, predicate); +} + ++ (RLMResults *)objectsInRealm:(RLMRealm *)realm withPredicate:(NSPredicate *)predicate { + return RLMGetObjects(realm, self.className, predicate); +} + ++ (instancetype)objectForPrimaryKey:(id)primaryKey { + return RLMGetObject(RLMRealm.defaultRealm, self.className, primaryKey); +} + ++ (instancetype)objectInRealm:(RLMRealm *)realm forPrimaryKey:(id)primaryKey { + return RLMGetObject(realm, self.className, primaryKey); +} + +#pragma mark - Other Instance Methods + +- (BOOL)isEqualToObject:(RLMObject *)object { + return [object isKindOfClass:RLMObject.class] && RLMObjectBaseAreEqual(self, object); +} + +- (instancetype)freeze { + return RLMObjectFreeze(self); +} + +- (BOOL)isFrozen { + return _realm.isFrozen; +} + +- (RLMNotificationToken *)addNotificationBlock:(RLMObjectChangeBlock)block { + return RLMObjectAddNotificationBlock(self, block, nil); +} + +- (RLMNotificationToken *)addNotificationBlock:(RLMObjectChangeBlock)block + queue:(nonnull dispatch_queue_t)queue { + return RLMObjectAddNotificationBlock(self, block, queue); +} + ++ (NSString *)className { + return [super className]; +} + +#pragma mark - Default values for schema definition + ++ (NSArray *)indexedProperties { + return @[]; +} + ++ (NSDictionary *)linkingObjectsProperties { + return @{}; +} + ++ (NSDictionary *)defaultPropertyValues { + return nil; +} + ++ (NSString *)primaryKey { + return nil; +} + ++ (NSArray *)ignoredProperties { + return nil; +} + ++ (NSArray *)requiredProperties { + return @[]; +} + ++ (bool)_realmIgnoreClass { + return false; +} + +@end + +@implementation RLMDynamicObject + ++ (bool)_realmIgnoreClass { + return true; +} + ++ (BOOL)shouldIncludeInDefaultSchema { + return NO; +} + +- (id)valueForUndefinedKey:(NSString *)key { + return RLMDynamicGetByName(self, key); +} + +- (void)setValue:(id)value forUndefinedKey:(NSString *)key { + RLMDynamicValidatedSet(self, key, value); +} + ++ (RLMObjectSchema *)sharedSchema { + return nil; +} + +@end + +BOOL RLMIsObjectOrSubclass(Class klass) { + return RLMIsKindOfClass(klass, RLMObjectBase.class); +} + +BOOL RLMIsObjectSubclass(Class klass) { + return RLMIsKindOfClass(class_getSuperclass(class_getSuperclass(klass)), RLMObjectBase.class); +} diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMObjectBase.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMObjectBase.mm new file mode 100644 index 0000000..6060f57 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMObjectBase.mm @@ -0,0 +1,729 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// 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 "RLMObject_Private.hpp" + +#import "RLMAccessor.h" +#import "RLMArray_Private.hpp" +#import "RLMDecimal128.h" +#import "RLMListBase.h" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObjectStore.h" +#import "RLMObservation.hpp" +#import "RLMOptionalBase.h" +#import "RLMProperty_Private.h" +#import "RLMRealm_Private.hpp" +#import "RLMSchema_Private.h" +#import "RLMSwiftSupport.h" +#import "RLMThreadSafeReference_Private.hpp" +#import "RLMUtil.hpp" + +#import "object.hpp" +#import "object_schema.hpp" +#import "shared_realm.hpp" + +using namespace realm; + +const NSUInteger RLMDescriptionMaxDepth = 5; + + +static bool isManagedAccessorClass(Class cls) { + const char *className = class_getName(cls); + const char accessorClassPrefix[] = "RLM:Managed"; + return strncmp(className, accessorClassPrefix, sizeof(accessorClassPrefix) - 1) == 0; +} + +static bool maybeInitObjectSchemaForUnmanaged(RLMObjectBase *obj) { + Class cls = obj.class; + if (isManagedAccessorClass(cls)) { + return false; + } + + obj->_objectSchema = [cls sharedSchema]; + if (!obj->_objectSchema) { + return false; + } + + // set default values + if (!obj->_objectSchema.isSwiftClass) { + NSDictionary *dict = RLMDefaultValuesForObjectSchema(obj->_objectSchema); + for (NSString *key in dict) { + [obj setValue:dict[key] forKey:key]; + } + } + + // set unmanaged accessor class + object_setClass(obj, obj->_objectSchema.unmanagedClass); + return true; +} + +@interface RLMObjectBase () +@end + +@implementation RLMObjectBase +// unmanaged init +- (instancetype)init { + if ((self = [super init])) { + maybeInitObjectSchemaForUnmanaged(self); + } + return self; +} + +- (void)dealloc { + // This can't be a unique_ptr because associated objects are removed + // *after* c++ members are destroyed and dealloc is called, and we need it + // to be in a validish state when that happens + delete _observationInfo; + _observationInfo = nullptr; +} + +static id coerceToObjectType(id obj, Class cls, RLMSchema *schema) { + if ([obj isKindOfClass:cls]) { + return obj; + } + id value = [[cls alloc] init]; + RLMInitializeWithValue(value, obj, schema); + return value; +} + +static id validatedObjectForProperty(__unsafe_unretained id const obj, + __unsafe_unretained RLMObjectSchema *const objectSchema, + __unsafe_unretained RLMProperty *const prop, + __unsafe_unretained RLMSchema *const schema) { + RLMValidateValueForProperty(obj, objectSchema, prop); + if (!obj || obj == NSNull.null) { + return nil; + } + if (prop.type == RLMPropertyTypeObject) { + Class objectClass = schema[prop.objectClassName].objectClass; + if (prop.array) { + NSMutableArray *ret = [[NSMutableArray alloc] init]; + for (id el in obj) { + [ret addObject:coerceToObjectType(el, objectClass, schema)]; + } + return ret; + } + return coerceToObjectType(obj, objectClass, schema); + } + else if (prop.type == RLMPropertyTypeDecimal128 && !prop.array) { + return [[RLMDecimal128 alloc] initWithValue:obj]; + } + return obj; +} + +void RLMInitializeWithValue(RLMObjectBase *self, id value, RLMSchema *schema) { + if (!value || value == NSNull.null) { + @throw RLMException(@"Must provide a non-nil value."); + } + + RLMObjectSchema *objectSchema = self->_objectSchema; + if (!objectSchema) { + // Will be nil if we're called during schema init, when we don't want + // to actually populate the object anyway + return; + } + + NSArray *properties = objectSchema.properties; + if (NSArray *array = RLMDynamicCast(value)) { + if (array.count > properties.count) { + @throw RLMException(@"Invalid array input: more values (%llu) than properties (%llu).", + (unsigned long long)array.count, (unsigned long long)properties.count); + } + NSUInteger i = 0; + for (id val in array) { + RLMProperty *prop = properties[i++]; + [self setValue:validatedObjectForProperty(RLMCoerceToNil(val), objectSchema, prop, schema) + forKey:prop.name]; + } + } + else { + // assume our object is an NSDictionary or an object with kvc properties + for (RLMProperty *prop in properties) { + id obj = RLMValidatedValueForProperty(value, prop.name, objectSchema.className); + + // don't set unspecified properties + if (!obj) { + continue; + } + + [self setValue:validatedObjectForProperty(RLMCoerceToNil(obj), objectSchema, prop, schema) + forKey:prop.name]; + } + } +} + +id RLMCreateManagedAccessor(Class cls, RLMClassInfo *info) { + RLMObjectBase *obj = [[cls alloc] init]; + obj->_info = info; + obj->_realm = info->realm; + obj->_objectSchema = info->rlmObjectSchema; + return obj; +} + +- (id)valueForKey:(NSString *)key { + if (_observationInfo) { + return _observationInfo->valueForKey(key); + } + return [super valueForKey:key]; +} + +// Generic Swift properties can't be dynamic, so KVO doesn't work for them by default +- (id)valueForUndefinedKey:(NSString *)key { + RLMProperty *prop = _objectSchema[key]; + if (Class accessor = prop.swiftAccessor) { + return [accessor get:(char *)(__bridge void *)self + ivar_getOffset(prop.swiftIvar)]; + } + if (Ivar ivar = prop.swiftIvar) { + return RLMCoerceToNil(object_getIvar(self, ivar)); + } + return [super valueForUndefinedKey:key]; +} + +- (void)setValue:(id)value forUndefinedKey:(NSString *)key { + value = RLMCoerceToNil(value); + RLMProperty *property = _objectSchema[key]; + if (Ivar ivar = property.swiftIvar) { + if (property.array) { + value = RLMAsFastEnumeration(value); + RLMArray *array = [object_getIvar(self, ivar) _rlmArray]; + [array removeAllObjects]; + + if (value) { + [array addObjects:validatedObjectForProperty(value, _objectSchema, property, + RLMSchema.partialPrivateSharedSchema)]; + } + } + else if (property.optional) { + RLMSetOptional(object_getIvar(self, ivar), value); + } + return; + } + [super setValue:value forUndefinedKey:key]; +} + +// overridden at runtime per-class for performance ++ (NSString *)className { + NSString *className = NSStringFromClass(self); + if ([RLMSwiftSupport isSwiftClassName:className]) { + className = [RLMSwiftSupport demangleClassName:className]; + } + return className; +} + +// overridden at runtime per-class for performance ++ (RLMObjectSchema *)sharedSchema { + return [RLMSchema sharedSchemaForClass:self.class]; +} + ++ (void)initializeLinkedObjectSchemas { + for (RLMProperty *prop in self.sharedSchema.properties) { + if (prop.type == RLMPropertyTypeObject && !RLMSchema.partialPrivateSharedSchema[prop.objectClassName]) { + [[RLMSchema classForString:prop.objectClassName] initializeLinkedObjectSchemas]; + } + } +} + ++ (nullable NSArray *)_getProperties { + return nil; +} + +- (NSString *)description { + if (self.isInvalidated) { + return @"[invalid object]"; + } + + return [self descriptionWithMaxDepth:RLMDescriptionMaxDepth]; +} + +- (NSString *)descriptionWithMaxDepth:(NSUInteger)depth { + if (depth == 0) { + return @""; + } + + NSString *baseClassName = _objectSchema.className; + NSMutableString *mString = [NSMutableString stringWithFormat:@"%@ {\n", baseClassName]; + + for (RLMProperty *property in _objectSchema.properties) { + id object = [(id)self objectForKeyedSubscript:property.name]; + NSString *sub; + if ([object respondsToSelector:@selector(descriptionWithMaxDepth:)]) { + sub = [object descriptionWithMaxDepth:depth - 1]; + } + else if (property.type == RLMPropertyTypeData) { + static NSUInteger maxPrintedDataLength = 24; + NSData *data = object; + NSUInteger length = data.length; + if (length > maxPrintedDataLength) { + data = [NSData dataWithBytes:data.bytes length:maxPrintedDataLength]; + } + NSString *dataDescription = [data description]; + sub = [NSString stringWithFormat:@"<%@ — %lu total bytes>", [dataDescription substringWithRange:NSMakeRange(1, dataDescription.length - 2)], (unsigned long)length]; + } + else { + sub = [object description]; + } + [mString appendFormat:@"\t%@ = %@;\n", property.name, [sub stringByReplacingOccurrencesOfString:@"\n" withString:@"\n\t"]]; + } + [mString appendString:@"}"]; + + return [NSString stringWithString:mString]; +} + +- (RLMRealm *)realm { + return _realm; +} + +- (RLMObjectSchema *)objectSchema { + return _objectSchema; +} + +- (BOOL)isInvalidated { + // if not unmanaged and our accessor has been detached, we have been deleted + return self.class == _objectSchema.accessorClass && !_row.is_valid(); +} + +- (BOOL)isEqual:(id)object { + if (RLMObjectBase *other = RLMDynamicCast(object)) { + if (_objectSchema.primaryKeyProperty || _realm.isFrozen) { + return RLMObjectBaseAreEqual(self, other); + } + } + return [super isEqual:object]; +} + +- (NSUInteger)hash { + if (_objectSchema.primaryKeyProperty) { + // If we have a primary key property, that's an immutable value which we + // can use as the identity of the object. + id primaryProperty = [self valueForKey:_objectSchema.primaryKeyProperty.name]; + + // modify the hash of our primary key value to avoid potential (although unlikely) collisions + return [primaryProperty hash] ^ 1; + } + else if (_realm.isFrozen) { + // The object key can never change for frozen objects, so that's usable + // for objects without primary keys + return static_cast(_row.get_key().value); + } + else { + // Non-frozen objects without primary keys don't have any immutable + // concept of identity that we can hash so we have to fall back to + // pointer equality + return [super hash]; + } +} + ++ (BOOL)shouldIncludeInDefaultSchema { + return RLMIsObjectSubclass(self); +} + ++ (NSString *)primaryKey { + return nil; +} + ++ (NSString *)_realmObjectName { + return nil; +} + ++ (NSDictionary *)_realmColumnNames { + return nil; +} + ++ (bool)_realmIgnoreClass { + return false; +} + ++ (bool)isEmbedded { + return false; +} + +- (id)mutableArrayValueForKey:(NSString *)key { + id obj = [self valueForKey:key]; + if ([obj isKindOfClass:[RLMArray class]]) { + return obj; + } + return [super mutableArrayValueForKey:key]; +} + +- (void)addObserver:(id)observer + forKeyPath:(NSString *)keyPath + options:(NSKeyValueObservingOptions)options + context:(void *)context { + if (!_observationInfo) { + _observationInfo = new RLMObservationInfo(self); + } + _observationInfo->recordObserver(_row, _info, _objectSchema, keyPath); + + [super addObserver:observer forKeyPath:keyPath options:options context:context]; +} + +- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath { + [super removeObserver:observer forKeyPath:keyPath]; + if (_observationInfo) + _observationInfo->removeObserver(); +} + ++ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key { + if (isManagedAccessorClass(self) && [class_getSuperclass(self.class) sharedSchema][key]) { + return NO; + } + + return [super automaticallyNotifiesObserversForKey:key]; +} + +#pragma mark - Thread Confined Protocol Conformance + +- (realm::ThreadSafeReference)makeThreadSafeReference { + return Object(_realm->_realm, *_info->objectSchema, _row); +} + +- (id)objectiveCMetadata { + return nil; +} + ++ (instancetype)objectWithThreadSafeReference:(realm::ThreadSafeReference)reference + metadata:(__unused id)metadata + realm:(RLMRealm *)realm { + Object object = reference.resolve(realm->_realm); + if (!object.is_valid()) { + return nil; + } + NSString *objectClassName = @(object.get_object_schema().name.c_str()); + return RLMCreateObjectAccessor(realm->_info[objectClassName], object.obj()); +} + +@end + +RLMRealm *RLMObjectBaseRealm(__unsafe_unretained RLMObjectBase *object) { + return object ? object->_realm : nil; +} + +RLMObjectSchema *RLMObjectBaseObjectSchema(__unsafe_unretained RLMObjectBase *object) { + return object ? object->_objectSchema : nil; +} + +id RLMObjectBaseObjectForKeyedSubscript(RLMObjectBase *object, NSString *key) { + if (!object) { + return nil; + } + + if (object->_realm) { + return RLMDynamicGetByName(object, key); + } + else { + return [object valueForKey:key]; + } +} + +void RLMObjectBaseSetObjectForKeyedSubscript(RLMObjectBase *object, NSString *key, id obj) { + if (!object) { + return; + } + + if (object->_realm || object.class == object->_objectSchema.accessorClass) { + RLMDynamicValidatedSet(object, key, obj); + } + else { + [object setValue:obj forKey:key]; + } +} + + +BOOL RLMObjectBaseAreEqual(RLMObjectBase *o1, RLMObjectBase *o2) { + // if not the correct types throw + if ((o1 && ![o1 isKindOfClass:RLMObjectBase.class]) || (o2 && ![o2 isKindOfClass:RLMObjectBase.class])) { + @throw RLMException(@"Can only compare objects of class RLMObjectBase"); + } + // if identical object (or both are nil) + if (o1 == o2) { + return YES; + } + // if one is nil + if (o1 == nil || o2 == nil) { + return NO; + } + // if not in realm or differing realms + if (o1->_realm == nil || o1->_realm != o2->_realm) { + return NO; + } + // if either are detached + if (!o1->_row.is_valid() || !o2->_row.is_valid()) { + return NO; + } + // if table and index are the same + return o1->_row.get_table() == o2->_row.get_table() + && o1->_row.get_key() == o2->_row.get_key(); +} + +id RLMObjectFreeze(RLMObjectBase *obj) { + if (!obj->_realm && !obj.isInvalidated) { + @throw RLMException(@"Unmanaged objects cannot be frozen."); + } + RLMVerifyAttached(obj); + if (obj->_realm.frozen) { + return obj; + } + RLMRealm *frozenRealm = [obj->_realm freeze]; + RLMObjectBase *frozen = RLMCreateManagedAccessor(obj.class, &frozenRealm->_info[obj->_info->rlmObjectSchema.className]); + frozen->_row = frozenRealm->_realm->import_copy_of(obj->_row); + if (!frozen->_row.is_valid()) { + @throw RLMException(@"Cannot freeze an object in the same write transaction as it was created in."); + } + RLMInitializeSwiftAccessorGenerics(frozen); + return frozen; +} + +id RLMValidatedValueForProperty(id object, NSString *key, NSString *className) { + @try { + return [object valueForKey:key]; + } + @catch (NSException *e) { + if ([e.name isEqualToString:NSUndefinedKeyException]) { + @throw RLMException(@"Invalid value '%@' to initialize object of type '%@': missing key '%@'", + object, className, key); + } + @throw; + } +} + +#pragma mark - Notifications + +namespace { +struct ObjectChangeCallbackWrapper { + RLMObjectNotificationCallback block; + RLMObjectBase *object; + + NSArray *propertyNames = nil; + NSArray *oldValues = nil; + bool deleted = false; + + void populateProperties(realm::CollectionChangeSet const& c) { + if (propertyNames) { + return; + } + if (!c.deletions.empty()) { + deleted = true; + return; + } + if (c.columns.empty()) { + return; + } + + auto properties = [NSMutableArray new]; + for (RLMProperty *property in object->_info->rlmObjectSchema.properties) { + if (c.columns.count(object->_info->tableColumn(property).value)) { + [properties addObject:property.name]; + } + } + if (properties.count) { + propertyNames = properties; + } + } + + NSArray *readValues(realm::CollectionChangeSet const& c) { + if (c.empty()) { + return nil; + } + populateProperties(c); + if (!propertyNames) { + return nil; + } + + auto values = [NSMutableArray arrayWithCapacity:propertyNames.count]; + for (NSString *name in propertyNames) { + id value = [object valueForKey:name]; + if (!value || [value isKindOfClass:[RLMArray class]]) { + [values addObject:NSNull.null]; + } + else { + [values addObject:value]; + } + } + return values; + } + + void before(realm::CollectionChangeSet const& c) { + @autoreleasepool { + oldValues = readValues(c); + } + } + + void after(realm::CollectionChangeSet const& c) { + @autoreleasepool { + auto newValues = readValues(c); + if (deleted) { + block(nil, nil, nil, nil, nil); + } + else if (newValues) { + block(object, propertyNames, oldValues, newValues, nil); + } + propertyNames = nil; + oldValues = nil; + } + } + + void error(std::exception_ptr err) { + @autoreleasepool { + try { + rethrow_exception(err); + } + catch (...) { + NSError *error = nil; + RLMRealmTranslateException(&error); + block(nil, nil, nil, nil, error); + } + } + } +}; +} // anonymous namespace + +@interface RLMPropertyChange () +@property (nonatomic, readwrite, strong) NSString *name; +@property (nonatomic, readwrite, strong, nullable) id previousValue; +@property (nonatomic, readwrite, strong, nullable) id value; +@end + +@implementation RLMPropertyChange +- (NSString *)description { + return [NSString stringWithFormat:@" %@ %@ -> %@", + (__bridge void *)self, _name, _previousValue, _value]; +} +@end + +@interface RLMObjectNotificationToken : RLMNotificationToken +@end + +@implementation RLMObjectNotificationToken { + std::mutex _mutex; + __unsafe_unretained RLMRealm *_realm; + realm::Object _object; + realm::NotificationToken _token; +} + +- (RLMRealm *)realm { + return _realm; +} + +- (void)suppressNextNotification { + std::lock_guard lock(_mutex); + if (_object.is_valid()) { + _token.suppress_next(); + } +} + +- (void)invalidate { + std::lock_guard lock(_mutex); + _realm = nil; + _token = {}; + _object = {}; +} + +- (void)addNotificationBlock:(RLMObjectNotificationCallback)block + threadSafeReference:(RLMThreadSafeReference *)tsr + config:(RLMRealmConfiguration *)config + queue:(dispatch_queue_t)queue { + std::lock_guard lock(_mutex); + if (!_realm) { + // Token was invalidated before we got this far + return; + } + + NSError *error; + RLMRealm *realm = _realm = [RLMRealm realmWithConfiguration:config queue:queue error:&error]; + if (!realm) { + block(nil, nil, nil, nil, error); + return; + } + RLMObjectBase *obj = [realm resolveThreadSafeReference:tsr]; + + _object = realm::Object(obj->_realm->_realm, *obj->_info->objectSchema, obj->_row); + _token = _object.add_notification_callback(ObjectChangeCallbackWrapper{block, obj}); +} + +- (void)addNotificationBlock:(RLMObjectNotificationCallback)block object:(RLMObjectBase *)obj { + _object = realm::Object(obj->_realm->_realm, *obj->_info->objectSchema, obj->_row); + _realm = obj->_realm; + _token = _object.add_notification_callback(ObjectChangeCallbackWrapper{block, obj}); +} + +RLMNotificationToken *RLMObjectBaseAddNotificationBlock(RLMObjectBase *obj, dispatch_queue_t queue, + RLMObjectNotificationCallback block) { + if (!obj->_realm) { + @throw RLMException(@"Only objects which are managed by a Realm support change notifications"); + } + + if (!queue) { + [obj->_realm verifyNotificationsAreSupported:true]; + auto token = [[RLMObjectNotificationToken alloc] init]; + token->_realm = obj->_realm; + [token addNotificationBlock:block object:obj]; + return token; + } + + RLMThreadSafeReference *tsr = [RLMThreadSafeReference referenceWithThreadConfined:(id)obj]; + auto token = [[RLMObjectNotificationToken alloc] init]; + token->_realm = obj->_realm; + RLMRealmConfiguration *config = obj->_realm.configuration; + dispatch_async(queue, ^{ + @autoreleasepool { + [token addNotificationBlock:block threadSafeReference:tsr config:config queue:queue]; + } + }); + return token; +} + +@end + +RLMNotificationToken *RLMObjectAddNotificationBlock(RLMObjectBase *obj, RLMObjectChangeBlock block, dispatch_queue_t queue) { + return RLMObjectBaseAddNotificationBlock(obj, queue, ^(RLMObjectBase *, NSArray *propertyNames, + NSArray *oldValues, NSArray *newValues, NSError *error) { + if (error) { + block(false, nil, error); + } + else if (!propertyNames) { + block(true, nil, nil); + } + else { + auto properties = [NSMutableArray arrayWithCapacity:propertyNames.count]; + for (NSUInteger i = 0, count = propertyNames.count; i < count; ++i) { + auto prop = [RLMPropertyChange new]; + prop.name = propertyNames[i]; + prop.previousValue = RLMCoerceToNil(oldValues[i]); + prop.value = RLMCoerceToNil(newValues[i]); + [properties addObject:prop]; + } + block(false, properties, nil); + } + }); +} + +uint64_t RLMObjectBaseGetCombineId(__unsafe_unretained RLMObjectBase *const obj) { + if (obj.invalidated) { + RLMVerifyAttached(obj); + } + if (obj->_realm) { + return obj->_row.get_key().value; + } + return reinterpret_cast((__bridge void *)obj); +} + +@implementation RealmSwiftObject +@end + +@implementation RealmSwiftEmbeddedObject +@end diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMObjectId.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMObjectId.mm new file mode 100644 index 0000000..e8ad509 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMObjectId.mm @@ -0,0 +1,128 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 "RLMObjectId_Private.hpp" + +#import "RLMUtil.hpp" + +#import + +// Swift's obj-c bridging does not support making an obj-c defined class conform +// to Decodable, so we need a Swift-defined subclass for that. This means that +// when Realm Swift is being used, we need to produce objects of that type rather +// than our obj-c defined type. objc_runtime_visible marks the type as being +// visbile only to the obj-c runtime and not the linker, which means that it'll +// be `nil` at runtime rather than being a linker error if it's not defined, and +// valid if it happens to be defined by some other library (i.e. Realm Swift). +// +// At the point where the objects are being allocated we generally don't have +// any good way of knowing whether or not it's going to end up being used by +// Swift, so we just switch to the subclass unconditionally if the subclass +// exists. This shouldn't have any impact on obj-c code other than a small +// performance hit. +[[clang::objc_runtime_visible]] +@interface RealmSwiftObjectId : RLMObjectId +@end + +@implementation RLMObjectId +- (instancetype)init { + if ((self = [super init])) { + if (auto cls = [RealmSwiftObjectId class]; cls && cls != self.class) { + object_setClass(self, cls); + } + } + return self; +} + +- (instancetype)initWithString:(NSString *)string error:(NSError **)error { + if ((self = [self init])) { + const char *str = string.UTF8String; + if (!realm::ObjectId::is_valid_str(str)) { + if (error) { + NSString *msg = [NSString stringWithFormat:@"Invalid Object ID string '%@': must be 24 hex digits", string]; + *error = [NSError errorWithDomain:RLMErrorDomain + code:RLMErrorInvalidInput + userInfo:@{NSLocalizedDescriptionKey: msg}]; + } + return nil; + } + _value = realm::ObjectId(str); + } + return self; +} + +- (instancetype)initWithTimestamp:(NSDate *)timestamp + machineIdentifier:(int)machineIdentifier + processIdentifier:(int)processIdentifier { + if ((self = [self init])) { + _value = realm::ObjectId(RLMTimestampForNSDate(timestamp), machineIdentifier, processIdentifier); + } + return self; +} + +- (instancetype)initWithValue:(realm::ObjectId)value { + if ((self = [self init])) { + _value = value; + } + return self; +} + ++ (instancetype)objectId { + return [[RLMObjectId alloc] initWithValue:realm::ObjectId::gen()]; +} + +- (BOOL)isEqual:(id)object { + if (RLMObjectId *objectId = RLMDynamicCast(object)) { + return objectId->_value == _value; + } + return NO; +} + +- (BOOL)isGreaterThan:(nullable RLMObjectId *)objectId { + return _value > objectId.value; +} + +- (BOOL)isGreaterThanOrEqualTo:(nullable RLMObjectId *)objectId { + return _value >= objectId.value; +} + +- (BOOL)isLessThan:(nullable RLMObjectId *)objectId { + return _value < objectId.value; +} + +- (BOOL)isLessThanOrEqualTo:(nullable RLMObjectId *)objectId { + return _value <= objectId.value; +} + +- (NSUInteger)hash { + return _value.hash(); +} + +- (NSString *)description { + return self.stringValue; +} + +- (NSString *)stringValue { + return @(_value.to_string().c_str()); +} + +- (NSDate *)timestamp { + return RLMTimestampToNSDate(_value.get_timestamp()); +} + +@end diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMObjectSchema.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMObjectSchema.mm new file mode 100644 index 0000000..db872c9 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMObjectSchema.mm @@ -0,0 +1,372 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// 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 "RLMObjectSchema_Private.hpp" + +#import "RLMArray.h" +#import "RLMEmbeddedObject.h" +#import "RLMListBase.h" +#import "RLMObject_Private.h" +#import "RLMProperty_Private.hpp" +#import "RLMRealm_Dynamic.h" +#import "RLMRealm_Private.hpp" +#import "RLMSchema_Private.h" +#import "RLMSwiftSupport.h" +#import "RLMUtil.hpp" + +#import "object_schema.hpp" +#import "object_store.hpp" + +using namespace realm; + +// private properties +@interface RLMObjectSchema () +@property (nonatomic, readwrite) NSDictionary *allPropertiesByName; +@property (nonatomic, readwrite) NSString *className; +@end + +@implementation RLMObjectSchema { + NSArray *_swiftGenericProperties; +} + +- (instancetype)initWithClassName:(NSString *)objectClassName objectClass:(Class)objectClass properties:(NSArray *)properties { + self = [super init]; + self.className = objectClassName; + self.properties = properties; + self.objectClass = objectClass; + self.accessorClass = objectClass; + self.unmanagedClass = objectClass; + return self; +} + +// return properties by name +- (RLMProperty *)objectForKeyedSubscript:(__unsafe_unretained NSString *const)key { + return _allPropertiesByName[key]; +} + +// create property map when setting property array +- (void)setProperties:(NSArray *)properties { + _properties = properties; + [self _propertiesDidChange]; +} + +- (void)setComputedProperties:(NSArray *)computedProperties { + _computedProperties = computedProperties; + [self _propertiesDidChange]; +} + +- (void)_propertiesDidChange { + NSMutableDictionary *map = [NSMutableDictionary dictionaryWithCapacity:_properties.count + _computedProperties.count]; + NSUInteger index = 0; + for (RLMProperty *prop in _properties) { + prop.index = index++; + map[prop.name] = prop; + if (prop.isPrimary) { + self.primaryKeyProperty = prop; + } + } + index = 0; + for (RLMProperty *prop in _computedProperties) { + prop.index = index++; + map[prop.name] = prop; + } + _allPropertiesByName = map; +} + + +- (void)setPrimaryKeyProperty:(RLMProperty *)primaryKeyProperty { + _primaryKeyProperty.isPrimary = NO; + primaryKeyProperty.isPrimary = YES; + _primaryKeyProperty = primaryKeyProperty; +} + ++ (instancetype)schemaForObjectClass:(Class)objectClass { + RLMObjectSchema *schema = [RLMObjectSchema new]; + + // determine classname from objectclass as className method has not yet been updated + NSString *className = NSStringFromClass(objectClass); + bool hasSwiftName = [RLMSwiftSupport isSwiftClassName:className]; + if (hasSwiftName) { + className = [RLMSwiftSupport demangleClassName:className]; + } + + bool isSwift = hasSwiftName || RLMIsSwiftObjectClass(objectClass); + + schema.className = className; + schema.objectClass = objectClass; + schema.accessorClass = objectClass; + schema.unmanagedClass = objectClass; + schema.isSwiftClass = isSwift; + schema.isEmbedded = [(id)objectClass isEmbedded]; + + // create array of RLMProperties, inserting properties of superclasses first + Class cls = objectClass; + Class superClass = class_getSuperclass(cls); + NSArray *allProperties = @[]; + while (superClass && superClass != RLMObjectBase.class) { + allProperties = [[RLMObjectSchema propertiesForClass:cls isSwift:isSwift] + arrayByAddingObjectsFromArray:allProperties]; + cls = superClass; + superClass = class_getSuperclass(superClass); + } + NSArray *persistedProperties = [allProperties filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(RLMProperty *property, NSDictionary *) { + return !RLMPropertyTypeIsComputed(property.type); + }]]; + schema.properties = persistedProperties; + + NSArray *computedProperties = [allProperties filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(RLMProperty *property, NSDictionary *) { + return RLMPropertyTypeIsComputed(property.type); + }]]; + schema.computedProperties = computedProperties; + + // verify that we didn't add any properties twice due to inheritance + if (allProperties.count != [NSSet setWithArray:[allProperties valueForKey:@"name"]].count) { + NSCountedSet *countedPropertyNames = [NSCountedSet setWithArray:[allProperties valueForKey:@"name"]]; + NSArray *duplicatePropertyNames = [countedPropertyNames filteredSetUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id object, NSDictionary *) { + return [countedPropertyNames countForObject:object] > 1; + }]].allObjects; + + if (duplicatePropertyNames.count == 1) { + @throw RLMException(@"Property '%@' is declared multiple times in the class hierarchy of '%@'", duplicatePropertyNames.firstObject, className); + } else { + @throw RLMException(@"Object '%@' has properties that are declared multiple times in its class hierarchy: '%@'", className, [duplicatePropertyNames componentsJoinedByString:@"', '"]); + } + } + + if (NSString *primaryKey = [objectClass primaryKey]) { + for (RLMProperty *prop in schema.properties) { + if ([primaryKey isEqualToString:prop.name]) { + prop.indexed = YES; + schema.primaryKeyProperty = prop; + break; + } + } + + if (!schema.primaryKeyProperty) { + @throw RLMException(@"Primary key property '%@' does not exist on object '%@'", primaryKey, className); + } + if (schema.primaryKeyProperty.type != RLMPropertyTypeInt && schema.primaryKeyProperty.type != RLMPropertyTypeString && schema.primaryKeyProperty.type != RLMPropertyTypeObjectId) { + @throw RLMException(@"Property '%@' cannot be made the primary key of '%@' because it is not a 'string', 'int', or 'objectId' property.", + primaryKey, className); + } + } + + for (RLMProperty *prop in schema.properties) { + if (prop.optional && prop.array && (prop.type == RLMPropertyTypeObject || prop.type == RLMPropertyTypeLinkingObjects)) { + // FIXME: message is awkward + @throw RLMException(@"Property '%@.%@' cannot be made optional because optional '%@' properties are not supported.", + className, prop.name, RLMTypeToString(prop.type)); + } + } + + if ([objectClass shouldIncludeInDefaultSchema] && schema.isSwiftClass && schema.properties.count == 0) { + @throw RLMException(@"No properties are defined for '%@'. Did you remember to mark them with '@objc' in your model?", schema.className); + } + return schema; +} + ++ (NSArray *)propertiesForClass:(Class)objectClass isSwift:(bool)isSwiftClass { + if (NSArray *props = [objectClass _getProperties]) { + return props; + } + + // For Swift subclasses of RLMObject we need an instance of the object when parsing properties + id swiftObjectInstance = isSwiftClass ? [[objectClass alloc] init] : nil; + + NSArray *ignoredProperties = [objectClass ignoredProperties]; + NSDictionary *linkingObjectsProperties = [objectClass linkingObjectsProperties]; + NSDictionary *columnNameMap = [objectClass _realmColumnNames]; + + unsigned int count; + std::unique_ptr props(class_copyPropertyList(objectClass, &count), &free); + NSMutableArray *propArray = [NSMutableArray arrayWithCapacity:count]; + NSSet *indexed = [[NSSet alloc] initWithArray:[objectClass indexedProperties]]; + for (unsigned int i = 0; i < count; i++) { + NSString *propertyName = @(property_getName(props[i])); + if ([ignoredProperties containsObject:propertyName]) { + continue; + } + + RLMProperty *prop = nil; + if (isSwiftClass) { + prop = [[RLMProperty alloc] initSwiftPropertyWithName:propertyName + indexed:[indexed containsObject:propertyName] + linkPropertyDescriptor:linkingObjectsProperties[propertyName] + property:props[i] + instance:swiftObjectInstance]; + } + else { + prop = [[RLMProperty alloc] initWithName:propertyName + indexed:[indexed containsObject:propertyName] + linkPropertyDescriptor:linkingObjectsProperties[propertyName] + property:props[i]]; + } + + if (prop) { + if (columnNameMap) { + prop.columnName = columnNameMap[prop.name]; + } + [propArray addObject:prop]; + } + } + + if (auto requiredProperties = [objectClass requiredProperties]) { + for (RLMProperty *property in propArray) { + bool required = [requiredProperties containsObject:property.name]; + if (required && property.type == RLMPropertyTypeObject && !property.array) { + @throw RLMException(@"Object properties cannot be made required, " + "but '+[%@ requiredProperties]' included '%@'", objectClass, property.name); + } + property.optional &= !required; + } + } + + for (RLMProperty *property in propArray) { + if (!property.optional && property.type == RLMPropertyTypeObject && !property.array) { + @throw RLMException(@"The `%@.%@` property must be marked as being optional.", + [objectClass className], property.name); + } + } + + return propArray; +} + +- (id)copyWithZone:(NSZone *)zone { + RLMObjectSchema *schema = [[RLMObjectSchema allocWithZone:zone] init]; + schema->_objectClass = _objectClass; + schema->_className = _className; + schema->_objectClass = _objectClass; + schema->_accessorClass = _objectClass; + schema->_unmanagedClass = _unmanagedClass; + schema->_isSwiftClass = _isSwiftClass; + schema->_isEmbedded = _isEmbedded; + + // call property setter to reset map and primary key + schema.properties = [[NSArray allocWithZone:zone] initWithArray:_properties copyItems:YES]; + schema.computedProperties = [[NSArray allocWithZone:zone] initWithArray:_computedProperties copyItems:YES]; + + return schema; +} + +- (BOOL)isEqualToObjectSchema:(RLMObjectSchema *)objectSchema { + if (objectSchema.properties.count != _properties.count) { + return NO; + } + + if (![_properties isEqualToArray:objectSchema.properties]) { + return NO; + } + if (![_computedProperties isEqualToArray:objectSchema.computedProperties]) { + return NO; + } + + return YES; +} + +- (NSString *)description { + NSMutableString *propertiesString = [NSMutableString string]; + for (RLMProperty *property in self.properties) { + [propertiesString appendFormat:@"\t%@\n", [property.description stringByReplacingOccurrencesOfString:@"\n" withString:@"\n\t"]]; + } + for (RLMProperty *property in self.computedProperties) { + [propertiesString appendFormat:@"\t%@\n", [property.description stringByReplacingOccurrencesOfString:@"\n" withString:@"\n\t"]]; + } + return [NSString stringWithFormat:@"%@ %@{\n%@}", + self.className, _isEmbedded ? @"(embedded) " : @"", propertiesString]; +} + +- (NSString *)objectName { + return [self.objectClass _realmObjectName] ?: _className; +} + +- (realm::ObjectSchema)objectStoreCopy:(RLMSchema *)schema { + ObjectSchema objectSchema; + objectSchema.name = self.objectName.UTF8String; + objectSchema.primary_key = _primaryKeyProperty ? _primaryKeyProperty.columnName.UTF8String : ""; + objectSchema.is_embedded = ObjectSchema::IsEmbedded(_isEmbedded); + for (RLMProperty *prop in _properties) { + Property p = [prop objectStoreCopy:schema]; + p.is_primary = (prop == _primaryKeyProperty); + objectSchema.persisted_properties.push_back(std::move(p)); + } + for (RLMProperty *prop in _computedProperties) { + objectSchema.computed_properties.push_back([prop objectStoreCopy:schema]); + } + return objectSchema; +} + ++ (instancetype)objectSchemaForObjectStoreSchema:(realm::ObjectSchema const&)objectSchema { + RLMObjectSchema *schema = [RLMObjectSchema new]; + schema.className = @(objectSchema.name.c_str()); + schema.isEmbedded = objectSchema.is_embedded; + + // create array of RLMProperties + NSMutableArray *properties = [NSMutableArray arrayWithCapacity:objectSchema.persisted_properties.size()]; + for (const Property &prop : objectSchema.persisted_properties) { + RLMProperty *property = [RLMProperty propertyForObjectStoreProperty:prop]; + property.isPrimary = (prop.name == objectSchema.primary_key); + [properties addObject:property]; + } + schema.properties = properties; + + NSMutableArray *computedProperties = [NSMutableArray arrayWithCapacity:objectSchema.computed_properties.size()]; + for (const Property &prop : objectSchema.computed_properties) { + [computedProperties addObject:[RLMProperty propertyForObjectStoreProperty:prop]]; + } + schema.computedProperties = computedProperties; + + // get primary key from realm metadata + if (objectSchema.primary_key.length()) { + NSString *primaryKeyString = [NSString stringWithUTF8String:objectSchema.primary_key.c_str()]; + schema.primaryKeyProperty = schema[primaryKeyString]; + if (!schema.primaryKeyProperty) { + @throw RLMException(@"No property matching primary key '%@'", primaryKeyString); + } + } + + // for dynamic schema use vanilla RLMDynamicObject accessor classes + schema.objectClass = RLMObject.class; + schema.accessorClass = RLMDynamicObject.class; + schema.unmanagedClass = RLMObject.class; + + return schema; +} + +- (NSArray *)swiftGenericProperties { + if (_swiftGenericProperties) { + return _swiftGenericProperties; + } + + // Check if it's a swift class using the obj-c API + if (!RLMIsSwiftObjectClass(_accessorClass)) { + return _swiftGenericProperties = @[]; + } + + NSMutableArray *genericProperties = [NSMutableArray new]; + for (RLMProperty *prop in _properties) { + if (prop->_swiftIvar) { + [genericProperties addObject:prop]; + } + } + // Currently all computed properties are Swift generics + [genericProperties addObjectsFromArray:_computedProperties]; + + return _swiftGenericProperties = genericProperties; +} + +@end diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMObjectStore.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMObjectStore.mm new file mode 100644 index 0000000..e6e0b88 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMObjectStore.mm @@ -0,0 +1,242 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// 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 "RLMObjectStore.h" + +#import "RLMAccessor.hpp" +#import "RLMArray_Private.hpp" +#import "RLMListBase.h" +#import "RLMObservation.hpp" +#import "RLMObject_Private.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMOptionalBase.h" +#import "RLMProperty_Private.h" +#import "RLMQueryUtil.hpp" +#import "RLMRealm_Private.hpp" +#import "RLMSchema_Private.h" +#import "RLMSwiftSupport.h" +#import "RLMUtil.hpp" + +#import "object_store.hpp" +#import "results.hpp" +#import "shared_realm.hpp" + +#import + +#import + +using namespace realm; + +void RLMRealmCreateAccessors(RLMSchema *schema) { + const size_t bufferSize = sizeof("RLM:Managed ") // includes null terminator + + std::numeric_limits::digits10 + + realm::Group::max_table_name_length; + + char className[bufferSize] = "RLM:Managed "; + char *const start = className + strlen(className); + + for (RLMObjectSchema *objectSchema in schema.objectSchema) { + if (objectSchema.accessorClass != objectSchema.objectClass) { + continue; + } + + static unsigned long long count = 0; + sprintf(start, "%llu %s", count++, objectSchema.className.UTF8String); + objectSchema.accessorClass = RLMManagedAccessorClassForObjectClass(objectSchema.objectClass, objectSchema, className); + } +} + +static inline void RLMVerifyRealmRead(__unsafe_unretained RLMRealm *const realm) { + if (!realm) { + @throw RLMException(@"Realm must not be nil"); + } + [realm verifyThread]; + if (realm->_realm->is_closed()) { + // This message may seem overly specific, but frozen Realms are currently + // the only ones which we outright close. + @throw RLMException(@"Cannot read from a frozen Realm which has been invalidated."); + } +} + +static inline void RLMVerifyInWriteTransaction(__unsafe_unretained RLMRealm *const realm) { + RLMVerifyRealmRead(realm); + // if realm is not writable throw + if (!realm.inWriteTransaction) { + @throw RLMException(@"Can only add, remove, or create objects in a Realm in a write transaction - call beginWriteTransaction on an RLMRealm instance first."); + } +} + +void RLMInitializeSwiftAccessorGenerics(__unsafe_unretained RLMObjectBase *const object) { + if (!object || !object->_row || !object->_objectSchema->_isSwiftClass) { + return; + } + if (![object isKindOfClass:object->_objectSchema.objectClass]) { + // It can be a different class if it's a dynamic object, and those don't + // require any init here (and would crash since they don't have the ivars) + return; + } + + for (RLMProperty *prop in object->_objectSchema.swiftGenericProperties) { + if (prop.type == RLMPropertyTypeLinkingObjects) { + [prop.swiftAccessor initializeObject:(char *)(__bridge void *)object + ivar_getOffset(prop.swiftIvar) + parent:object property:prop]; + } + else if (prop.array) { + id ivar = object_getIvar(object, prop.swiftIvar); + RLMArray *array = [[RLMManagedArray alloc] initWithParent:object property:prop]; + [ivar set_rlmArray:array]; + } + else { + id ivar = object_getIvar(object, prop.swiftIvar); + RLMInitializeManagedOptional(ivar, object, prop); + } + } +} + +void RLMVerifyHasPrimaryKey(Class cls) { + RLMObjectSchema *schema = [cls sharedSchema]; + if (!schema.primaryKeyProperty) { + NSString *reason = [NSString stringWithFormat:@"'%@' does not have a primary key and can not be updated", schema.className]; + @throw [NSException exceptionWithName:@"RLMException" reason:reason userInfo:nil]; + } +} + +static CreatePolicy updatePolicyToCreatePolicy(RLMUpdatePolicy policy) { + CreatePolicy createPolicy = {.create = true, .copy = false, .diff = false, .update = false}; + switch (policy) { + case RLMUpdatePolicyError: + break; + case RLMUpdatePolicyUpdateChanged: + createPolicy.diff = true; + [[clang::fallthrough]]; + case RLMUpdatePolicyUpdateAll: + createPolicy.update = true; + break; + } + return createPolicy; +} + +void RLMAddObjectToRealm(__unsafe_unretained RLMObjectBase *const object, + __unsafe_unretained RLMRealm *const realm, + RLMUpdatePolicy updatePolicy) { + RLMVerifyInWriteTransaction(realm); + + CreatePolicy createPolicy = updatePolicyToCreatePolicy(updatePolicy); + createPolicy.copy = false; + auto& info = realm->_info[object->_objectSchema.className]; + RLMAccessorContext c{info}; + c.createObject(object, createPolicy); +} + +RLMObjectBase *RLMCreateObjectInRealmWithValue(RLMRealm *realm, NSString *className, + id value, RLMUpdatePolicy updatePolicy) { + RLMVerifyInWriteTransaction(realm); + + CreatePolicy createPolicy = updatePolicyToCreatePolicy(updatePolicy); + createPolicy.copy = true; + + auto& info = realm->_info[className]; + RLMAccessorContext c{info}; + RLMObjectBase *object = RLMCreateManagedAccessor(info.rlmObjectSchema.accessorClass, &info); + auto [obj, reuseExisting] = c.createObject(value, createPolicy, true); + if (reuseExisting) { + return value; + } + object->_row = std::move(obj); + RLMInitializeSwiftAccessorGenerics(object); + return object; +} + +void RLMDeleteObjectFromRealm(__unsafe_unretained RLMObjectBase *const object, + __unsafe_unretained RLMRealm *const realm) { + if (realm != object->_realm) { + @throw RLMException(@"Can only delete an object from the Realm it belongs to."); + } + + RLMVerifyInWriteTransaction(object->_realm); + + if (object->_row.is_valid()) { + RLMObservationTracker tracker(realm, true); + object->_row.remove(); + } + object->_realm = nil; +} + +void RLMDeleteAllObjectsFromRealm(RLMRealm *realm) { + RLMVerifyInWriteTransaction(realm); + + // clear table for each object schema + for (auto& info : realm->_info) { + RLMClearTable(info.second); + } +} + +RLMResults *RLMGetObjects(__unsafe_unretained RLMRealm *const realm, + NSString *objectClassName, + NSPredicate *predicate) { + RLMVerifyRealmRead(realm); + + // create view from table and predicate + RLMClassInfo& info = realm->_info[objectClassName]; + if (!info.table()) { + // read-only realms may be missing tables since we can't add any + // missing ones on init + return [RLMResults resultsWithObjectInfo:info results:{}]; + } + + if (predicate) { + realm::Query query = RLMPredicateToQuery(predicate, info.rlmObjectSchema, realm.schema, realm.group); + return [RLMResults resultsWithObjectInfo:info + results:realm::Results(realm->_realm, std::move(query))]; + } + + return [RLMResults resultsWithObjectInfo:info + results:realm::Results(realm->_realm, info.table())]; +} + +id RLMGetObject(RLMRealm *realm, NSString *objectClassName, id key) { + RLMVerifyRealmRead(realm); + + auto& info = realm->_info[objectClassName]; + if (RLMProperty *prop = info.propertyForPrimaryKey()) { + RLMValidateValueForProperty(key, info.rlmObjectSchema, prop); + } + try { + RLMAccessorContext c{info}; + auto obj = realm::Object::get_for_primary_key(c, realm->_realm, *info.objectSchema, + key ?: NSNull.null); + if (!obj.is_valid()) + return nil; + return RLMCreateObjectAccessor(info, obj.obj()); + } + catch (std::exception const& e) { + @throw RLMException(e); + } +} + +RLMObjectBase *RLMCreateObjectAccessor(RLMClassInfo& info, int64_t key) { + return RLMCreateObjectAccessor(info, info.table()->get_object(realm::ObjKey(key))); +} + +// Create accessor and register with realm +RLMObjectBase *RLMCreateObjectAccessor(RLMClassInfo& info, realm::Obj&& obj) { + RLMObjectBase *accessor = RLMCreateManagedAccessor(info.rlmObjectSchema.accessorClass, &info); + accessor->_row = std::move(obj); + RLMInitializeSwiftAccessorGenerics(accessor); + return accessor; +} diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMObservation.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMObservation.mm new file mode 100644 index 0000000..5d39175 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMObservation.mm @@ -0,0 +1,548 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// 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 "RLMObservation.hpp" + +#import "RLMAccessor.h" +#import "RLMArray_Private.hpp" +#import "RLMListBase.h" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObject_Private.hpp" +#import "RLMProperty_Private.h" +#import "RLMRealm_Private.hpp" + +#import + +using namespace realm; + +namespace { + template + struct IteratorPair { + Iterator first; + Iterator second; + }; + template + Iterator begin(IteratorPair const& p) { + return p.first; + } + template + Iterator end(IteratorPair const& p) { + return p.second; + } + + template + auto reverse(Container const& c) { + return IteratorPair{c.rbegin(), c.rend()}; + } +} + +RLMObservationInfo::RLMObservationInfo(RLMClassInfo &objectSchema, realm::ObjKey row, id object) +: object(object) +, objectSchema(&objectSchema) +{ + setRow(*objectSchema.table(), row); +} + +RLMObservationInfo::RLMObservationInfo(id object) +: object(object) +{ +} + +RLMObservationInfo::~RLMObservationInfo() { + if (prev) { + // Not the head of the linked list, so just detach from the list + REALM_ASSERT_DEBUG(prev->next == this); + prev->next = next; + if (next) { + REALM_ASSERT_DEBUG(next->prev == this); + next->prev = prev; + } + } + else if (objectSchema) { + // The head of the list, so remove self from the object schema's array + // of observation info, either replacing self with the next info or + // removing entirely if there is no next + auto end = objectSchema->observedObjects.end(); + auto it = find(objectSchema->observedObjects.begin(), end, this); + if (it != end) { + if (next) { + *it = next; + next->prev = nullptr; + } + else { + iter_swap(it, std::prev(end)); + objectSchema->observedObjects.pop_back(); + } + } + } + // Otherwise the observed object was unmanaged, so nothing to do + +#ifdef DEBUG + // ensure that incorrect cleanup fails noisily + object = (__bridge id)(void *)-1; + prev = (RLMObservationInfo *)-1; + next = (RLMObservationInfo *)-1; +#endif +} + +NSString *RLMObservationInfo::columnName(realm::ColKey col) const noexcept { + return objectSchema->propertyForTableColumn(col).name; +} + +void RLMObservationInfo::willChange(NSString *key, NSKeyValueChange kind, NSIndexSet *indexes) const { + if (indexes) { + forEach([=](__unsafe_unretained auto o) { + [o willChange:kind valuesAtIndexes:indexes forKey:key]; + }); + } + else { + forEach([=](__unsafe_unretained auto o) { + [o willChangeValueForKey:key]; + }); + } +} + +void RLMObservationInfo::didChange(NSString *key, NSKeyValueChange kind, NSIndexSet *indexes) const { + if (indexes) { + forEach([=](__unsafe_unretained auto o) { + [o didChange:kind valuesAtIndexes:indexes forKey:key]; + }); + } + else { + forEach([=](__unsafe_unretained auto o) { + [o didChangeValueForKey:key]; + }); + } +} + +void RLMObservationInfo::prepareForInvalidation() { + REALM_ASSERT_DEBUG(objectSchema); + REALM_ASSERT_DEBUG(!prev); + for (auto info = this; info; info = info->next) + info->invalidated = true; +} + +void RLMObservationInfo::setRow(realm::Table const& table, realm::ObjKey key) { + REALM_ASSERT_DEBUG(!row); + REALM_ASSERT_DEBUG(objectSchema); + row = table.get_object(key); + for (auto info : objectSchema->observedObjects) { + if (info->row && info->row.get_key() == key) { + prev = info; + next = info->next; + if (next) + next->prev = this; + info->next = this; + return; + } + } + objectSchema->observedObjects.push_back(this); +} + +void RLMObservationInfo::recordObserver(realm::Obj& objectRow, RLMClassInfo *objectInfo, + __unsafe_unretained RLMObjectSchema *const objectSchema, + __unsafe_unretained NSString *const keyPath) { + ++observerCount; + if (row) { + return; + } + + // add ourselves to the list of observed objects if this is the first time + // an observer is being added to a managed object + if (objectRow) { + this->objectSchema = objectInfo; + setRow(*objectRow.get_table(), objectRow.get_key()); + return; + } + + // Arrays need a reference to their containing object to avoid having to + // go through the awful proxy object from mutableArrayValueForKey. + // For managed objects we do this when the object is added or created + // (and have to to support notifications from modifying an object which + // was never observed), but for Swift classes (both RealmSwift and + // RLMObject) we can't do it then because we don't know what the parent + // object is. + + NSUInteger sep = [keyPath rangeOfString:@"."].location; + NSString *key = sep == NSNotFound ? keyPath : [keyPath substringToIndex:sep]; + RLMProperty *prop = objectSchema[key]; + if (prop && prop.array) { + id value = valueForKey(key); + RLMArray *array = [value isKindOfClass:[RLMListBase class]] ? [value _rlmArray] : value; + array->_key = key; + array->_parentObject = object; + } + else if (auto swiftIvar = prop.swiftIvar) { + if (auto optional = RLMDynamicCast(object_getIvar(object, swiftIvar))) { + RLMInitializeUnmanagedOptional(optional, object, prop); + } + } +} + +void RLMObservationInfo::removeObserver() { + --observerCount; +} + +id RLMObservationInfo::valueForKey(NSString *key) { + if (invalidated) { + if ([key isEqualToString:RLMInvalidatedKey]) { + return @YES; + } + return cachedObjects[key]; + } + + if (key != lastKey) { + lastKey = key; + lastProp = objectSchema ? objectSchema->rlmObjectSchema[key] : nil; + } + + static auto superValueForKey = reinterpret_cast([NSObject methodForSelector:@selector(valueForKey:)]); + if (!lastProp) { + // Not a managed property, so use NSObject's implementation of valueForKey: + return RLMCoerceToNil(superValueForKey(object, @selector(valueForKey:), key)); + } + + auto getSuper = [&] { + return row ? RLMDynamicGet(object, lastProp) : RLMCoerceToNil(superValueForKey(object, @selector(valueForKey:), key)); + }; + + // We need to return the same object each time for observing over keypaths + // to work, so we store a cache of them here. We can't just cache them on + // the object as that leads to retain cycles. + if (lastProp.array) { + RLMArray *value = cachedObjects[key]; + if (!value) { + value = getSuper(); + if (!cachedObjects) { + cachedObjects = [NSMutableDictionary new]; + } + cachedObjects[key] = value; + } + return value; + } + + if (lastProp.type == RLMPropertyTypeObject) { + auto col = row.get_table()->get_column_key(lastProp.name.UTF8String); + if (row.is_null(col)) { + [cachedObjects removeObjectForKey:key]; + return nil; + } + + RLMObjectBase *value = cachedObjects[key]; + if (value && value->_row.get_key() == row.get(col)) { + return value; + } + value = getSuper(); + if (!cachedObjects) { + cachedObjects = [NSMutableDictionary new]; + } + cachedObjects[key] = value; + return value; + } + + return getSuper(); +} + +RLMObservationInfo *RLMGetObservationInfo(RLMObservationInfo *info, realm::ObjKey row, + RLMClassInfo& objectSchema) { + if (info) { + return info; + } + + for (RLMObservationInfo *info : objectSchema.observedObjects) { + if (info->isForRow(row)) { + return info; + } + } + + return nullptr; +} + +void RLMClearTable(RLMClassInfo &objectSchema) { + for (auto info : objectSchema.observedObjects) { + info->willChange(RLMInvalidatedKey); + } + + { + RLMObservationTracker tracker(objectSchema.realm, true); + Results(objectSchema.realm->_realm, objectSchema.table()).clear(); + + for (auto info : objectSchema.observedObjects) { + info->prepareForInvalidation(); + } + } + + for (auto info : reverse(objectSchema.observedObjects)) { + info->didChange(RLMInvalidatedKey); + } + + objectSchema.observedObjects.clear(); +} + +RLMObservationTracker::RLMObservationTracker(__unsafe_unretained RLMRealm *const realm, bool trackDeletions) +: _realm(realm) +, _group(realm.group) +{ + if (trackDeletions) { + this->trackDeletions(); + } +} + +RLMObservationTracker::~RLMObservationTracker() { + didChange(); +} + +void RLMObservationTracker::willChange(RLMObservationInfo *info, NSString *key, + NSKeyValueChange kind, NSIndexSet *indexes) { + _key = key; + _kind = kind; + _indexes = indexes; + _info = info; + if (_info) { + _info->willChange(key, kind, indexes); + } +} + +void RLMObservationTracker::trackDeletions() { + if (_group.has_cascade_notification_handler()) { + // We're nested inside another call which will handle any cascaded changes for us + return; + } + + for (auto& info : _realm->_info) { + if (!info.second.observedObjects.empty()) { + _observedTables.push_back(&info.second.observedObjects); + } + } + + // No need for change tracking if no objects are observed + if (_observedTables.empty()) { + return; + } + + _group.set_cascade_notification_handler([=](realm::Group::CascadeNotification const& cs) { + cascadeNotification(cs); + }); +} + +template +void RLMObservationTracker::cascadeNotification(CascadeNotification const& cs) { + if (cs.rows.empty() && cs.links.empty()) { + return; + } + + size_t invalidatedCount = _invalidated.size(); + size_t changeCount = _changes.size(); + + auto tableKey = [](RLMObservationInfo *info) { + return info->getRow().get_table()->get_key(); + }; + std::sort(begin(_observedTables), end(_observedTables), + [=](auto a, auto b) { return tableKey(a->front()) < tableKey(b->front()); }); + for (auto const& link : cs.links) { + auto table = std::find_if(_observedTables.begin(), _observedTables.end(), [&](auto table) { + return tableKey(table->front()) == link.origin_table; + }); + if (table == _observedTables.end()) { + continue; + } + + for (auto observer : **table) { + if (!observer->isForRow(link.origin_key)) { + continue; + } + + NSString *name = observer->columnName(link.origin_col_key); + if (observer->getRow().get_table()->get_column_type(link.origin_col_key) != type_LinkList) { + _changes.push_back({observer, name}); + continue; + } + + auto c = find_if(begin(_changes), end(_changes), [&](auto const& c) { + return c.info == observer && c.property == name; + }); + if (c == end(_changes)) { + _changes.push_back({observer, name, [NSMutableIndexSet new]}); + c = prev(end(_changes)); + } + + // We know what row index is being removed from the LinkView, + // but what we actually want is the indexes in the LinkView that + // are going away + auto linkview = observer->getRow().get_linklist(link.origin_col_key); + linkview.find_all(link.old_target_key, [&](size_t index) { + [c->indexes addIndex:index]; + }); + } + } + if (!cs.rows.empty()) { + using Row = realm::Group::CascadeNotification::row; + auto begin = cs.rows.begin(); + for (auto table : _observedTables) { + auto currentTableKey = tableKey(table->front()); + if (begin->table_key < currentTableKey) { + // Find the first deleted object in or after this table + begin = std::lower_bound(begin, cs.rows.end(), Row{currentTableKey, realm::ObjKey(0)}); + } + if (begin == cs.rows.end()) { + // No more deleted objects + break; + } + if (currentTableKey < begin->table_key) { + // Next deleted object is in a table after this one + continue; + } + + // Find the end of the deletions in this table + auto end = std::lower_bound(begin, cs.rows.end(), Row{realm::TableKey(currentTableKey.value + 1), realm::ObjKey(0)}); + + // Check each observed object to see if it's in the deleted rows + for (auto info : *table) { + if (std::binary_search(begin, end, Row{currentTableKey, info->getRow().get_key()})) { + _invalidated.push_back(info); + } + } + + // Advance the begin iterator to the start of the next table + begin = end; + if (begin == cs.rows.end()) { + break; + } + } + } + + // The relative order of these loops is very important + for (size_t i = invalidatedCount; i < _invalidated.size(); ++i) { + _invalidated[i]->willChange(RLMInvalidatedKey); + } + for (size_t i = changeCount; i < _changes.size(); ++i) { + auto const& change = _changes[i]; + change.info->willChange(change.property, NSKeyValueChangeRemoval, change.indexes); + } + for (size_t i = invalidatedCount; i < _invalidated.size(); ++i) { + _invalidated[i]->prepareForInvalidation(); + } +} + +void RLMObservationTracker::didChange() { + if (_info) { + _info->didChange(_key, _kind, _indexes); + _info = nullptr; + } + if (_observedTables.empty()) { + return; + } + _group.set_cascade_notification_handler(nullptr); + + for (auto const& change : reverse(_changes)) { + change.info->didChange(change.property, NSKeyValueChangeRemoval, change.indexes); + } + for (auto info : reverse(_invalidated)) { + info->didChange(RLMInvalidatedKey); + } + _observedTables.clear(); + _changes.clear(); + _invalidated.clear(); +} + +namespace { +template +void forEach(realm::BindingContext::ObserverState const& state, Func&& func) { + for (auto& change : state.changes) { + func(realm::ColKey(change.first), change.second, static_cast(state.info)); + } +} +} + +std::vector RLMGetObservedRows(RLMSchemaInfo const& schema) { + std::vector observers; + for (auto& table : schema) { + for (auto info : table.second.observedObjects) { + auto const& row = info->getRow(); + if (!row.is_valid()) + continue; + observers.push_back({ + row.get_table()->get_key(), + row.get_key().value, + info}); + } + } + sort(begin(observers), end(observers)); + return observers; +} + +static NSKeyValueChange convert(realm::BindingContext::ColumnInfo::Kind kind) { + switch (kind) { + case realm::BindingContext::ColumnInfo::Kind::None: + case realm::BindingContext::ColumnInfo::Kind::SetAll: + return NSKeyValueChangeSetting; + case realm::BindingContext::ColumnInfo::Kind::Set: + return NSKeyValueChangeReplacement; + case realm::BindingContext::ColumnInfo::Kind::Insert: + return NSKeyValueChangeInsertion; + case realm::BindingContext::ColumnInfo::Kind::Remove: + return NSKeyValueChangeRemoval; + } +} + +static NSIndexSet *convert(realm::IndexSet const& in, NSMutableIndexSet *out) { + if (in.empty()) { + return nil; + } + + [out removeAllIndexes]; + for (auto range : in) { + [out addIndexesInRange:{range.first, range.second - range.first}]; + } + return out; +} + +void RLMWillChange(std::vector const& observed, + std::vector const& invalidated) { + for (auto info : invalidated) { + static_cast(info)->willChange(RLMInvalidatedKey); + } + if (!observed.empty()) { + NSMutableIndexSet *indexes = [NSMutableIndexSet new]; + for (auto const& o : observed) { + forEach(o, [&](realm::ColKey colKey, auto const& change, RLMObservationInfo *info) { + info->willChange(info->columnName(colKey), + convert(change.kind), convert(change.indices, indexes)); + }); + } + } + for (auto info : invalidated) { + static_cast(info)->prepareForInvalidation(); + } +} + +void RLMDidChange(std::vector const& observed, + std::vector const& invalidated) { + if (!observed.empty()) { + // Loop in reverse order to avoid O(N^2) behavior in Foundation + NSMutableIndexSet *indexes = [NSMutableIndexSet new]; + for (auto const& o : reverse(observed)) { + forEach(o, [&](realm::ColKey col, auto const& change, RLMObservationInfo *info) { + info->didChange(info->columnName(col), convert(change.kind), convert(change.indices, indexes)); + }); + } + } + for (auto const& info : reverse(invalidated)) { + static_cast(info)->didChange(RLMInvalidatedKey); + } +} diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMOptionalBase.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMOptionalBase.mm new file mode 100644 index 0000000..2617f0b --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMOptionalBase.mm @@ -0,0 +1,163 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// 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 "RLMOptionalBase.h" + +#import "RLMAccessor.hpp" +#import "RLMObject_Private.hpp" +#import "RLMProperty.h" +#import "RLMUtil.hpp" +#import "object.hpp" + +namespace { +struct OptionalBase { + virtual id get() = 0; + virtual void set(id) = 0; + virtual ~OptionalBase() = default; +}; + +class UnmanagedOptional : public OptionalBase { +public: + id get() override { + return _value; + } + + void set(__unsafe_unretained const id newValue) override { + @autoreleasepool { + RLMObjectBase *object = _parent; + [object willChangeValueForKey:_property]; + _value = newValue; + [object didChangeValueForKey:_property]; + } + } + + void attach(__unsafe_unretained RLMObjectBase *const obj, NSString *property) { + if (!_property) { + _property = property; + _parent = obj; + } + } + +private: + id _value; + NSString *_property; + __weak RLMObjectBase *_parent; + +}; + +class ManagedOptional : public OptionalBase { +public: + ManagedOptional(RLMObjectBase *obj, RLMProperty *prop) + : _realm(obj->_realm) + , _object(obj->_realm->_realm, *obj->_info->objectSchema, obj->_row) + , _propertyName(prop.name.UTF8String) + , _ctx(*obj->_info) + { + } + + id get() override { + return _object.get_property_value(_ctx, _propertyName); + } + + void set(__unsafe_unretained id const value) override { + _object.set_property_value(_ctx, _propertyName, value ?: NSNull.null); + } + +private: + // We have to hold onto a strong reference to the Realm as + // RLMAccessorContext holds a non-retaining one. + __unused RLMRealm *_realm; + realm::Object _object; + std::string _propertyName; + RLMAccessorContext _ctx; +}; +} // anonymous namespace + +@interface RLMOptionalBase () { + std::unique_ptr _impl; +} +@end + +@implementation RLMOptionalBase +- (instancetype)init { + return self; +} + +- (BOOL)isKindOfClass:(Class)aClass { + return [RLMGetOptional(self) isKindOfClass:aClass] || RLMIsKindOfClass(object_getClass(self), aClass); +} + +- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel { + return [RLMGetOptional(self) methodSignatureForSelector:sel]; +} + +- (void)forwardInvocation:(NSInvocation *)invocation { + [invocation invokeWithTarget:RLMGetOptional(self)]; +} + +- (id)forwardingTargetForSelector:(__unused SEL)sel { + return RLMGetOptional(self); +} + +- (BOOL)respondsToSelector:(SEL)aSelector { + return [RLMGetOptional(self) respondsToSelector:aSelector]; +} + +- (void)doesNotRecognizeSelector:(SEL)aSelector { + [RLMGetOptional(self) doesNotRecognizeSelector:aSelector]; +} + +id RLMGetOptional(__unsafe_unretained RLMOptionalBase *const self) { + try { + return self->_impl ? RLMCoerceToNil(self->_impl->get()) : nil; + } + catch (std::exception const& err) { + @throw RLMException(err); + } +} + +void RLMSetOptional(__unsafe_unretained RLMOptionalBase *const self, __unsafe_unretained const id value) { + try { + if (!self->_impl && value) { + self->_impl.reset(new UnmanagedOptional); + } + if (self->_impl) { + self->_impl->set(value); + } + } + catch (std::exception const& err) { + @throw RLMException(err); + } +} + +void RLMInitializeManagedOptional(__unsafe_unretained RLMOptionalBase *const self, + __unsafe_unretained RLMObjectBase *const parent, + __unsafe_unretained RLMProperty *const prop) { + REALM_ASSERT(parent->_realm); + self->_impl.reset(new ManagedOptional(parent, prop)); +} + +void RLMInitializeUnmanagedOptional(__unsafe_unretained RLMOptionalBase *const self, + __unsafe_unretained RLMObjectBase *const parent, + __unsafe_unretained RLMProperty *const prop) { + if (!self->_impl) { + self->_impl.reset(new UnmanagedOptional); + } + static_cast(*self->_impl).attach(parent, prop.name); +} +@end diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMPredicateUtil.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMPredicateUtil.mm new file mode 100644 index 0000000..830a9b2 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMPredicateUtil.mm @@ -0,0 +1,127 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// 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 "RLMPredicateUtil.hpp" + +#include + +// NSConditionalExpressionType is new in OS X 10.11 and iOS 9.0 +#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +#define CONDITIONAL_EXPRESSION_DECLARED (__MAC_OS_X_VERSION_MIN_REQUIRED >= 101100) +#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +#define CONDITIONAL_EXPRESSION_DECLARED (__IPHONE_OS_VERSION_MIN_REQUIRED >= 90000) +#else +#define CONDITIONAL_EXPRESSION_DECLARED 0 +#endif + +#if !CONDITIONAL_EXPRESSION_DECLARED + +#define NSConditionalExpressionType 20 + +@interface NSExpression (NewIn1011And90) ++ (NSExpression *)expressionForConditional:(NSPredicate *)predicate trueExpression:(NSExpression *)trueExpression falseExpression:(NSExpression *)falseExpression; +- (NSExpression *)trueExpression; +- (NSExpression *)falseExpression; +@end + +#endif + +namespace { + +struct PredicateExpressionTransformer { + PredicateExpressionTransformer(ExpressionVisitor visitor) : m_visitor(visitor) { } + + NSExpression *visit(NSExpression *expression) const; + NSPredicate *visit(NSPredicate *predicate) const; + + ExpressionVisitor m_visitor; +}; + +NSExpression *PredicateExpressionTransformer::visit(NSExpression *expression) const { + expression = m_visitor(expression); + + switch (expression.expressionType) { + case NSFunctionExpressionType: { + NSMutableArray *arguments = [NSMutableArray array]; + for (NSExpression *argument in expression.arguments) { + [arguments addObject:visit(argument)]; + } + if (expression.operand) { + return [NSExpression expressionForFunction:visit(expression.operand) selectorName:expression.function arguments:arguments]; + } else { + return [NSExpression expressionForFunction:expression.function arguments:arguments]; + } + } + + case NSUnionSetExpressionType: + return [NSExpression expressionForUnionSet:visit(expression.leftExpression) with:visit(expression.rightExpression)]; + case NSIntersectSetExpressionType: + return [NSExpression expressionForIntersectSet:visit(expression.leftExpression) with:visit(expression.rightExpression)]; + case NSMinusSetExpressionType: + return [NSExpression expressionForMinusSet:visit(expression.leftExpression) with:visit(expression.rightExpression)]; + + case NSSubqueryExpressionType: { + NSExpression *collection = expression.collection; + // NSExpression.collection is declared as id, but appears to always hold an NSExpression for subqueries. + REALM_ASSERT([collection isKindOfClass:[NSExpression class]]); + return [NSExpression expressionForSubquery:visit(collection) usingIteratorVariable:expression.variable predicate:visit(expression.predicate)]; + } + + case NSAggregateExpressionType: { + NSMutableArray *subexpressions = [NSMutableArray array]; + for (NSExpression *subexpression in expression.collection) { + [subexpressions addObject:visit(subexpression)]; + } + return [NSExpression expressionForAggregate:subexpressions]; + } + + case NSConditionalExpressionType: +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpartial-availability" + return [NSExpression expressionForConditional:visit(expression.predicate) trueExpression:visit(expression.trueExpression) falseExpression:visit(expression.falseExpression)]; +#pragma clang diagnostic pop + + default: + // The remaining expression types do not contain nested expressions or predicates. + return expression; + } +} + +NSPredicate *PredicateExpressionTransformer::visit(NSPredicate *predicate) const { + if ([predicate isKindOfClass:[NSCompoundPredicate class]]) { + NSCompoundPredicate *compoundPredicate = (NSCompoundPredicate *)predicate; + NSMutableArray *subpredicates = [NSMutableArray array]; + for (NSPredicate *subpredicate in compoundPredicate.subpredicates) { + [subpredicates addObject:visit(subpredicate)]; + } + return [[NSCompoundPredicate alloc] initWithType:compoundPredicate.compoundPredicateType subpredicates:subpredicates]; + } + if ([predicate isKindOfClass:[NSComparisonPredicate class]]) { + NSComparisonPredicate *comparisonPredicate = (NSComparisonPredicate *)predicate; + NSExpression *leftExpression = visit(comparisonPredicate.leftExpression); + NSExpression *rightExpression = visit(comparisonPredicate.rightExpression); + return [NSComparisonPredicate predicateWithLeftExpression:leftExpression rightExpression:rightExpression modifier:comparisonPredicate.comparisonPredicateModifier type:comparisonPredicate.predicateOperatorType options:comparisonPredicate.options]; + } + return predicate; +} + +} // anonymous namespace + +NSPredicate *transformPredicate(NSPredicate *predicate, ExpressionVisitor visitor) { + PredicateExpressionTransformer transformer(visitor); + return transformer.visit(predicate); +} diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMProperty.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMProperty.mm new file mode 100644 index 0000000..ddfcb7f --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMProperty.mm @@ -0,0 +1,642 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// 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 "RLMProperty_Private.hpp" + +#import "RLMArray_Private.hpp" +#import "RLMListBase.h" +#import "RLMObject.h" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObject_Private.h" +#import "RLMSchema_Private.h" +#import "RLMSwiftSupport.h" +#import "RLMUtil.hpp" + +#import "property.hpp" + +static_assert((int)RLMPropertyTypeInt == (int)realm::PropertyType::Int); +static_assert((int)RLMPropertyTypeBool == (int)realm::PropertyType::Bool); +static_assert((int)RLMPropertyTypeFloat == (int)realm::PropertyType::Float); +static_assert((int)RLMPropertyTypeDouble == (int)realm::PropertyType::Double); +static_assert((int)RLMPropertyTypeString == (int)realm::PropertyType::String); +static_assert((int)RLMPropertyTypeData == (int)realm::PropertyType::Data); +static_assert((int)RLMPropertyTypeDate == (int)realm::PropertyType::Date); +static_assert((int)RLMPropertyTypeObject == (int)realm::PropertyType::Object); +static_assert((int)RLMPropertyTypeObjectId == (int)realm::PropertyType::ObjectId); +static_assert((int)RLMPropertyTypeDecimal128 == (int)realm::PropertyType::Decimal); + +BOOL RLMPropertyTypeIsComputed(RLMPropertyType propertyType) { + return propertyType == RLMPropertyTypeLinkingObjects; +} + +// Swift obeys the ARC naming conventions for method families (except for init) +// but the end result doesn't really work (using KVC on a method returning a +// retained value results in a leak, but not returning a retained value results +// in crashes). Objective-C makes properties with naming fitting the method +// families a compile error, so we just disallow them in Swift as well. +// http://clang.llvm.org/docs/AutomaticReferenceCounting.html#arc-method-families +void RLMValidateSwiftPropertyName(NSString *name) { + // To belong to a method family, the property name must begin with the family + // name followed by a non-lowercase letter (or nothing), with an optional + // leading underscore + const char *str = name.UTF8String; + if (str[0] == '_') + ++str; + auto nameSize = strlen(str); + + // Note that "init" is deliberately not in this list because Swift does not + // infer family membership for it. + for (auto family : {"alloc", "new", "copy", "mutableCopy"}) { + auto familySize = strlen(family); + if (nameSize < familySize || !std::equal(str, str + familySize, family)) { + continue; + } + if (familySize == nameSize || !islower(str[familySize])) { + @throw RLMException(@"Property names beginning with '%s' are not " + "supported. Swift follows ARC's ownership " + "rules for methods based on their name, which " + "results in memory leaks when accessing " + "properties which return retained values via KVC.", + family); + } + return; + } +} + +static bool rawTypeShouldBeTreatedAsComputedProperty(NSString *rawType) { + return [rawType isEqualToString:@"@\"RLMLinkingObjects\""] || [rawType hasPrefix:@"@\"RLMLinkingObjects<"]; +} + +@implementation RLMProperty + ++ (instancetype)propertyForObjectStoreProperty:(const realm::Property &)prop { + auto ret = [[RLMProperty alloc] initWithName:@(prop.name.c_str()) + type:static_cast(prop.type & ~realm::PropertyType::Flags) + objectClassName:prop.object_type.length() ? @(prop.object_type.c_str()) : nil + linkOriginPropertyName:prop.link_origin_property_name.length() ? @(prop.link_origin_property_name.c_str()) : nil + indexed:prop.is_indexed + optional:is_nullable(prop.type)]; + if (is_array(prop.type)) { + ret->_array = true; + } + if (!prop.public_name.empty()) { + ret->_columnName = ret->_name; + ret->_name = @(prop.public_name.c_str()); + } + return ret; +} + +- (instancetype)initWithName:(NSString *)name + type:(RLMPropertyType)type + objectClassName:(NSString *)objectClassName + linkOriginPropertyName:(NSString *)linkOriginPropertyName + indexed:(BOOL)indexed + optional:(BOOL)optional { + self = [super init]; + if (self) { + _name = name; + _type = type; + _objectClassName = objectClassName; + _linkOriginPropertyName = linkOriginPropertyName; + _indexed = indexed; + _optional = optional; + [self updateAccessors]; + } + + return self; +} + +- (void)setName:(NSString *)name { + _name = name; + [self updateAccessors]; +} + +- (void)updateAccessors { + // populate getter/setter names if generic + if (!_getterName) { + _getterName = _name; + } + if (!_setterName) { + // Objective-C setters only capitalize the first letter of the property name if it falls between 'a' and 'z' + int asciiCode = [_name characterAtIndex:0]; + BOOL shouldUppercase = asciiCode >= 'a' && asciiCode <= 'z'; + NSString *firstChar = [_name substringToIndex:1]; + firstChar = shouldUppercase ? firstChar.uppercaseString : firstChar; + _setterName = [NSString stringWithFormat:@"set%@%@:", firstChar, [_name substringFromIndex:1]]; + } + + _getterSel = NSSelectorFromString(_getterName); + _setterSel = NSSelectorFromString(_setterName); +} + +static realm::util::Optional typeFromProtocolString(const char *type) { + if (strncmp(type, "RLM", 3)) { + return realm::none; + } + type += 3; + if (strcmp(type, "Int>\"") == 0) { + return RLMPropertyTypeInt; + } + if (strcmp(type, "Float>\"") == 0) { + return RLMPropertyTypeFloat; + } + if (strcmp(type, "Double>\"") == 0) { + return RLMPropertyTypeDouble; + } + if (strcmp(type, "Bool>\"") == 0) { + return RLMPropertyTypeBool; + } + if (strcmp(type, "String>\"") == 0) { + return RLMPropertyTypeString; + } + if (strcmp(type, "Data>\"") == 0) { + return RLMPropertyTypeData; + } + if (strcmp(type, "Date>\"") == 0) { + return RLMPropertyTypeDate; + } + if (strcmp(type, "Decimal128>\"") == 0) { + return RLMPropertyTypeDecimal128; + } + if (strcmp(type, "ObjectId>\"") == 0) { + return RLMPropertyTypeObjectId; + } + return realm::none; +} + +// determine RLMPropertyType from objc code - returns true if valid type was found/set +- (BOOL)setTypeFromRawType:(NSString *)rawType { + const char *code = rawType.UTF8String; + switch (*code) { + case 's': // short + case 'i': // int + case 'l': // long + case 'q': // long long + _type = RLMPropertyTypeInt; + return YES; + case 'f': + _type = RLMPropertyTypeFloat; + return YES; + case 'd': + _type = RLMPropertyTypeDouble; + return YES; + case 'c': // BOOL is stored as char - since rlm has no char type this is ok + case 'B': + _type = RLMPropertyTypeBool; + return YES; + case '@': + break; + default: + return NO; + } + + _optional = true; + static const char arrayPrefix[] = "@\"RLMArray<"; + static const int arrayPrefixLen = sizeof(arrayPrefix) - 1; + + static const char numberPrefix[] = "@\"NSNumber<"; + static const int numberPrefixLen = sizeof(numberPrefix) - 1; + + static const char linkingObjectsPrefix[] = "@\"RLMLinkingObjects"; + static const int linkingObjectsPrefixLen = sizeof(linkingObjectsPrefix) - 1; + + if (strcmp(code, "@\"NSString\"") == 0) { + _type = RLMPropertyTypeString; + } + else if (strcmp(code, "@\"NSDate\"") == 0) { + _type = RLMPropertyTypeDate; + } + else if (strcmp(code, "@\"NSData\"") == 0) { + _type = RLMPropertyTypeData; + } + else if (strcmp(code, "@\"RLMDecimal128\"") == 0) { + _type = RLMPropertyTypeDecimal128; + } + else if (strcmp(code, "@\"RLMObjectId\"") == 0) { + _type = RLMPropertyTypeObjectId; + } + else if (strncmp(code, arrayPrefix, arrayPrefixLen) == 0) { + _array = true; + if (auto type = typeFromProtocolString(code + arrayPrefixLen)) { + _type = *type; + return YES; + } + + // get object class from type string - @"RLMArray" + _objectClassName = [[NSString alloc] initWithBytes:code + arrayPrefixLen + length:strlen(code + arrayPrefixLen) - 2 // drop trailing >" + encoding:NSUTF8StringEncoding]; + + if ([RLMSchema classForString:_objectClassName]) { + _optional = false; + _type = RLMPropertyTypeObject; + return YES; + } + @throw RLMException(@"Property '%@' is of type 'RLMArray<%@>' which is not a supported RLMArray object type. " + @"RLMArrays can only contain instances of RLMObject subclasses. " + @"See https://realm.io/docs/objc/latest/#to-many for more information.", _name, _objectClassName); + } + else if (strncmp(code, numberPrefix, numberPrefixLen) == 0) { + auto type = typeFromProtocolString(code + numberPrefixLen); + if (type && (*type == RLMPropertyTypeInt || *type == RLMPropertyTypeFloat || *type == RLMPropertyTypeDouble || *type == RLMPropertyTypeBool)) { + _type = *type; + return YES; + } + @throw RLMException(@"Property '%@' is of type %s which is not a supported NSNumber object type. " + @"NSNumbers can only be RLMInt, RLMFloat, RLMDouble, and RLMBool at the moment. " + @"See https://realm.io/docs/objc/latest for more information.", _name, code + 1); + } + else if (strncmp(code, linkingObjectsPrefix, linkingObjectsPrefixLen) == 0 && + (code[linkingObjectsPrefixLen] == '"' || code[linkingObjectsPrefixLen] == '<')) { + _type = RLMPropertyTypeLinkingObjects; + _optional = false; + _array = true; + + if (!_objectClassName || !_linkOriginPropertyName) { + @throw RLMException(@"Property '%@' is of type RLMLinkingObjects but +linkingObjectsProperties did not specify the class " + "or property that is the origin of the link.", _name); + } + + // If the property was declared with a protocol indicating the contained type, validate that it matches + // the class from the dictionary returned by +linkingObjectsProperties. + if (code[linkingObjectsPrefixLen] == '<') { + NSString *classNameFromProtocol = [[NSString alloc] initWithBytes:code + linkingObjectsPrefixLen + 1 + length:strlen(code + linkingObjectsPrefixLen) - 3 // drop trailing >" + encoding:NSUTF8StringEncoding]; + if (![_objectClassName isEqualToString:classNameFromProtocol]) { + @throw RLMException(@"Property '%@' was declared with type RLMLinkingObjects<%@>, but a conflicting " + "class name of '%@' was returned by +linkingObjectsProperties.", _name, + classNameFromProtocol, _objectClassName); + } + } + } + else if (strcmp(code, "@\"NSNumber\"") == 0) { + @throw RLMException(@"Property '%@' requires a protocol defining the contained type - example: NSNumber.", _name); + } + else if (strcmp(code, "@\"RLMArray\"") == 0) { + @throw RLMException(@"Property '%@' requires a protocol defining the contained type - example: RLMArray.", _name); + } + else { + NSString *className; + Class cls = nil; + if (code[1] == '\0') { + className = @"id"; + } + else { + // for objects strip the quotes and @ + className = [rawType substringWithRange:NSMakeRange(2, rawType.length-3)]; + cls = [RLMSchema classForString:className]; + } + + if (!cls) { + @throw RLMException(@"Property '%@' is declared as '%@', which is not a supported RLMObject property type. " + @"All properties must be primitives, NSString, NSDate, NSData, NSNumber, RLMArray, RLMLinkingObjects, RLMDecimal128, RLMObjectId, or subclasses of RLMObject. " + @"See https://realm.io/docs/objc/latest/api/Classes/RLMObject.html for more information.", _name, className); + } + + _type = RLMPropertyTypeObject; + _optional = true; + _objectClassName = [cls className] ?: className; + } + return YES; +} + +- (void)parseObjcProperty:(objc_property_t)property + readOnly:(bool *)readOnly + computed:(bool *)computed + rawType:(NSString **)rawType { + unsigned int count; + objc_property_attribute_t *attrs = property_copyAttributeList(property, &count); + + *computed = true; + for (size_t i = 0; i < count; ++i) { + switch (*attrs[i].name) { + case 'T': + *rawType = @(attrs[i].value); + break; + case 'R': + *readOnly = true; + break; + case 'G': + _getterName = @(attrs[i].value); + break; + case 'S': + _setterName = @(attrs[i].value); + break; + case 'V': // backing ivar name + *computed = false; + break; + + case '&': + // retain/assign + break; + case 'C': + // copy + break; + case 'D': + // dynamic + break; + case 'N': + // nonatomic + break; + case 'P': + // GC'able + break; + case 'W': + // weak + break; + default: + break; + } + } + free(attrs); +} + +- (instancetype)initSwiftPropertyWithName:(NSString *)name + indexed:(BOOL)indexed + linkPropertyDescriptor:(RLMPropertyDescriptor *)linkPropertyDescriptor + property:(objc_property_t)property + instance:(RLMObject *)obj { + self = [super init]; + if (!self) { + return nil; + } + + RLMValidateSwiftPropertyName(name); + + _name = name; + _indexed = indexed; + + if (linkPropertyDescriptor) { + _objectClassName = [linkPropertyDescriptor.objectClass className]; + _linkOriginPropertyName = linkPropertyDescriptor.propertyName; + } + + NSString *rawType; + bool readOnly = false; + bool isComputed = false; + [self parseObjcProperty:property readOnly:&readOnly computed:&isComputed rawType:&rawType]; + + // Swift sometimes doesn't explicitly set the ivar name in the metadata, so check if + // there's an ivar with the same name as the property. + if (!readOnly && isComputed && class_getInstanceVariable([obj class], name.UTF8String)) { + isComputed = false; + } + + // Check if there's a storage ivar for a lazy property in this name. We don't honor + // @lazy in managed objects, but allow it for unmanaged objects which are + // subclasses of RLMObject (but not RealmSwift.Object). It's unclear if there's a + // good reason for this difference. + if (!readOnly && isComputed) { + // Xcode 10 and earlier + NSString *backingPropertyName = [NSString stringWithFormat:@"%@.storage", name]; + isComputed = !class_getInstanceVariable([obj class], backingPropertyName.UTF8String); + } + if (!readOnly && isComputed) { + // Xcode 11 + NSString *backingPropertyName = [NSString stringWithFormat:@"$__lazy_storage_$_%@", name]; + isComputed = !class_getInstanceVariable([obj class], backingPropertyName.UTF8String); + } + + if (readOnly || isComputed) { + return nil; + } + + id propertyValue = [obj valueForKey:_name]; + + // FIXME: temporarily workaround added since Objective-C generics used in Swift show up as `@` + // * broken starting in Swift 3.0 Xcode 8 b1 + // * tested to still be broken in Swift 3.0 Xcode 8 b6 + // * if the Realm Objective-C Swift tests pass with this removed, it's been fixed + // * once it has been fixed, remove this entire conditional block (contents included) entirely + // * Bug Report: SR-2031 https://bugs.swift.org/browse/SR-2031 + if ([rawType isEqualToString:@"@"]) { + if (propertyValue) { + rawType = [NSString stringWithFormat:@"@\"%@\"", [propertyValue class]]; + } else if (linkPropertyDescriptor) { + // we're going to naively assume that the user used the correct type since we can't check it + rawType = @"@\"RLMLinkingObjects\""; + } + } + + // convert array types to objc variant + if ([rawType isEqualToString:@"@\"RLMArray\""]) { + RLMArray *value = propertyValue; + _type = value.type; + _optional = value.optional; + _array = true; + _objectClassName = value.objectClassName; + if (_type == RLMPropertyTypeObject && ![RLMSchema classForString:_objectClassName]) { + @throw RLMException(@"Property '%@' is of type 'RLMArray<%@>' which is not a supported RLMArray object type. " + @"RLMArrays can only contain instances of RLMObject subclasses. " + @"See https://realm.io/docs/objc/latest/#to-many for more information.", _name, _objectClassName); + } + } + else if ([rawType isEqualToString:@"@\"NSNumber\""]) { + const char *numberType = [propertyValue objCType]; + if (!numberType) { + @throw RLMException(@"Can't persist NSNumber without default value: use a Swift-native number type or provide a default value."); + } + _optional = true; + switch (*numberType) { + case 'i': case 'l': case 'q': + _type = RLMPropertyTypeInt; + break; + case 'f': + _type = RLMPropertyTypeFloat; + break; + case 'd': + _type = RLMPropertyTypeDouble; + break; + case 'B': case 'c': + _type = RLMPropertyTypeBool; + break; + default: + @throw RLMException(@"Can't persist NSNumber of type '%s': only integers, floats, doubles, and bools are currently supported.", numberType); + } + } + else if (![self setTypeFromRawType:rawType]) { + @throw RLMException(@"Can't persist property '%@' with incompatible type. " + "Add to Object.ignoredProperties() class method to ignore.", + self.name); + } + + if ([rawType isEqualToString:@"c"]) { + // Check if it's a BOOL or Int8 by trying to set it to 2 and seeing if + // it actually sets it to 1. + [obj setValue:@2 forKey:name]; + NSNumber *value = [obj valueForKey:name]; + _type = value.intValue == 2 ? RLMPropertyTypeInt : RLMPropertyTypeBool; + } + + // update getter/setter names + [self updateAccessors]; + + return self; +} + +- (instancetype)initWithName:(NSString *)name + indexed:(BOOL)indexed + linkPropertyDescriptor:(RLMPropertyDescriptor *)linkPropertyDescriptor + property:(objc_property_t)property +{ + self = [super init]; + if (!self) { + return nil; + } + + _name = name; + _indexed = indexed; + + if (linkPropertyDescriptor) { + _objectClassName = [linkPropertyDescriptor.objectClass className]; + _linkOriginPropertyName = linkPropertyDescriptor.propertyName; + } + + NSString *rawType; + bool isReadOnly = false; + bool isComputed = false; + [self parseObjcProperty:property readOnly:&isReadOnly computed:&isComputed rawType:&rawType]; + bool shouldBeTreatedAsComputedProperty = rawTypeShouldBeTreatedAsComputedProperty(rawType); + if ((isReadOnly || isComputed) && !shouldBeTreatedAsComputedProperty) { + return nil; + } + + if (![self setTypeFromRawType:rawType]) { + @throw RLMException(@"Can't persist property '%@' with incompatible type. " + "Add to ignoredPropertyNames: method to ignore.", self.name); + } + + if (!isReadOnly && shouldBeTreatedAsComputedProperty) { + @throw RLMException(@"Property '%@' must be declared as readonly as %@ properties cannot be written to.", + self.name, RLMTypeToString(_type)); + } + + // update getter/setter names + [self updateAccessors]; + + return self; +} + +- (id)copyWithZone:(NSZone *)zone { + RLMProperty *prop = [[RLMProperty allocWithZone:zone] init]; + prop->_name = _name; + prop->_columnName = _columnName; + prop->_type = _type; + prop->_objectClassName = _objectClassName; + prop->_array = _array; + prop->_indexed = _indexed; + prop->_getterName = _getterName; + prop->_setterName = _setterName; + prop->_getterSel = _getterSel; + prop->_setterSel = _setterSel; + prop->_isPrimary = _isPrimary; + prop->_swiftIvar = _swiftIvar; + prop->_optional = _optional; + prop->_linkOriginPropertyName = _linkOriginPropertyName; + return prop; +} + +- (RLMProperty *)copyWithNewName:(NSString *)name { + RLMProperty *prop = [self copy]; + prop.name = name; + return prop; +} + +- (BOOL)isEqual:(id)object { + if (![object isKindOfClass:[RLMProperty class]]) { + return NO; + } + + return [self isEqualToProperty:object]; +} + +- (BOOL)isEqualToProperty:(RLMProperty *)property { + return _type == property->_type + && _indexed == property->_indexed + && _isPrimary == property->_isPrimary + && _optional == property->_optional + && [_name isEqualToString:property->_name] + && (_objectClassName == property->_objectClassName || [_objectClassName isEqualToString:property->_objectClassName]) + && (_linkOriginPropertyName == property->_linkOriginPropertyName || + [_linkOriginPropertyName isEqualToString:property->_linkOriginPropertyName]); +} + +- (NSString *)description { + NSString *objectClassName = @""; + if (self.type == RLMPropertyTypeObject || self.type == RLMPropertyTypeLinkingObjects) { + objectClassName = [NSString stringWithFormat: + @"\tobjectClassName = %@;\n" + @"\tlinkOriginPropertyName = %@;\n", + self.objectClassName, self.linkOriginPropertyName]; + } + return [NSString stringWithFormat: + @"%@ {\n" + "\ttype = %@;\n" + "%@" + "\tindexed = %@;\n" + "\tisPrimary = %@;\n" + "\tarray = %@;\n" + "\toptional = %@;\n" + "}", + self.name, RLMTypeToString(self.type), + objectClassName, + self.indexed ? @"YES" : @"NO", + self.isPrimary ? @"YES" : @"NO", + self.array ? @"YES" : @"NO", + self.optional ? @"YES" : @"NO"]; +} + +- (NSString *)columnName { + return _columnName ?: _name; +} + +- (realm::Property)objectStoreCopy:(RLMSchema *)schema { + realm::Property p; + p.name = self.columnName.UTF8String; + if (_objectClassName) { + RLMObjectSchema *targetSchema = schema[_objectClassName]; + p.object_type = (targetSchema.objectName ?: _objectClassName).UTF8String; + if (_linkOriginPropertyName) { + p.link_origin_property_name = (targetSchema[_linkOriginPropertyName].columnName ?: _linkOriginPropertyName).UTF8String; + } + } + p.is_indexed = static_cast(_indexed); + p.type = static_cast(_type); + if (_array) { + p.type |= realm::PropertyType::Array; + } + if (_optional) { + p.type |= realm::PropertyType::Nullable; + } + return p; +} + +@end + +@implementation RLMPropertyDescriptor + ++ (instancetype)descriptorWithClass:(Class)objectClass propertyName:(NSString *)propertyName +{ + RLMPropertyDescriptor *descriptor = [[RLMPropertyDescriptor alloc] init]; + descriptor->_objectClass = objectClass; + descriptor->_propertyName = propertyName; + return descriptor; +} + +@end diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMProviderClient.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMProviderClient.mm new file mode 100644 index 0000000..073135e --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMProviderClient.mm @@ -0,0 +1,42 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 "RLMProviderClient_Private.hpp" + +#import "RLMApp_Private.hpp" +#import "sync/app.hpp" + +#import + +@implementation RLMProviderClient +- (instancetype)initWithApp:(RLMApp *)app { + self = [super init]; + if (self) { + _app = app; + } + return self; +} + +- (void)handleResponse:(realm::util::Optional)error + completion:(RLMProviderClientOptionalErrorBlock)completion { + if (error && error->error_code) { + return completion(RLMAppErrorToNSError(*error)); + } + completion(nil); +} +@end diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMPushClient.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMPushClient.mm new file mode 100644 index 0000000..8a7af22 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMPushClient.mm @@ -0,0 +1,59 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 "RLMPushClient_Private.hpp" + +#import "RLMApp_Private.hpp" +#import "RLMUser_Private.hpp" + +#import "sync/push_client.hpp" + +using realm::util::Optional; + +@implementation RLMPushClient { + Optional _pushClient; +} + +- (instancetype)initWithPushClient:(realm::app::PushClient&&)pushClient { + if (self = [super init]) { + _pushClient = std::move(pushClient); + return self; + } + return nil; +} + +- (void)registerDeviceWithToken:(NSString *)token user:(RLMUser *)user completion:(RLMOptionalErrorBlock)completion { + _pushClient->register_device(token.UTF8String, user._syncUser, ^(Optional error) { + if (error && error->error_code) { + return completion(RLMAppErrorToNSError(*error)); + } + completion(nil); + }); +} + + +- (void)deregisterDeviceForUser:(RLMUser *)user completion:(RLMOptionalErrorBlock)completion { + _pushClient->deregister_device(user._syncUser, ^(Optional error) { + if (error && error->error_code) { + return completion(RLMAppErrorToNSError(*error)); + } + completion(nil); + }); +} + +@end diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMQueryUtil.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMQueryUtil.mm new file mode 100644 index 0000000..1ed8167 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMQueryUtil.mm @@ -0,0 +1,1493 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// 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 "RLMQueryUtil.hpp" + +#import "RLMArray.h" +#import "RLMDecimal128_Private.hpp" +#import "RLMObjectId_Private.hpp" +#import "RLMObjectSchema_Private.h" +#import "RLMObject_Private.hpp" +#import "RLMPredicateUtil.hpp" +#import "RLMProperty_Private.h" +#import "RLMSchema.h" +#import "RLMUtil.hpp" + +#import "object_store.hpp" +#import "results.hpp" + +#include +#include +#include +#include + +using namespace realm; + +NSString * const RLMPropertiesComparisonTypeMismatchException = @"RLMPropertiesComparisonTypeMismatchException"; +NSString * const RLMUnsupportedTypesFoundInPropertyComparisonException = @"RLMUnsupportedTypesFoundInPropertyComparisonException"; + +NSString * const RLMPropertiesComparisonTypeMismatchReason = @"Property type mismatch between %@ and %@"; +NSString * const RLMUnsupportedTypesFoundInPropertyComparisonReason = @"Comparison between %@ and %@"; + +// small helper to create the many exceptions thrown when parsing predicates +static NSException *RLMPredicateException(NSString *name, NSString *format, ...) { + va_list args; + va_start(args, format); + NSString *reason = [[NSString alloc] initWithFormat:format arguments:args]; + va_end(args); + + return [NSException exceptionWithName:name reason:reason userInfo:nil]; +} + +// check a precondition and throw an exception if it is not met +// this should be used iff the condition being false indicates a bug in the caller +// of the function checking its preconditions +static void RLMPrecondition(bool condition, NSString *name, NSString *format, ...) { + if (__builtin_expect(condition, 1)) { + return; + } + + va_list args; + va_start(args, format); + NSString *reason = [[NSString alloc] initWithFormat:format arguments:args]; + va_end(args); + + @throw [NSException exceptionWithName:name reason:reason userInfo:nil]; +} + +// return the property for a validated column name +RLMProperty *RLMValidatedProperty(RLMObjectSchema *desc, NSString *columnName) { + RLMProperty *prop = desc[columnName]; + RLMPrecondition(prop, @"Invalid property name", + @"Property '%@' not found in object of type '%@'", columnName, desc.className); + return prop; +} + +namespace { +BOOL RLMPropertyTypeIsNumeric(RLMPropertyType propertyType) { + switch (propertyType) { + case RLMPropertyTypeInt: + case RLMPropertyTypeFloat: + case RLMPropertyTypeDouble: + case RLMPropertyTypeDecimal128: + return YES; + default: + return NO; + } +} + +// Equal and ContainsSubstring are used by QueryBuilder::add_string_constraint as the comparator +// for performing diacritic-insensitive comparisons. + +bool equal(CFStringCompareFlags options, StringData v1, StringData v2) +{ + if (v1.is_null() || v2.is_null()) { + return v1.is_null() == v2.is_null(); + } + + auto s1 = util::adoptCF(CFStringCreateWithBytesNoCopy(kCFAllocatorSystemDefault, (const UInt8*)v1.data(), v1.size(), + kCFStringEncodingUTF8, false, kCFAllocatorNull)); + auto s2 = util::adoptCF(CFStringCreateWithBytesNoCopy(kCFAllocatorSystemDefault, (const UInt8*)v2.data(), v2.size(), + kCFStringEncodingUTF8, false, kCFAllocatorNull)); + + return CFStringCompare(s1.get(), s2.get(), options) == kCFCompareEqualTo; +} + +template +struct Equal { + using CaseSensitive = Equal; + using CaseInsensitive = Equal; + + bool operator()(StringData v1, StringData v2, bool v1_null, bool v2_null) const + { + REALM_ASSERT_DEBUG(v1_null == v1.is_null()); + REALM_ASSERT_DEBUG(v2_null == v2.is_null()); + + return equal(options, v1, v2); + } + + static const char* description() { return options & kCFCompareCaseInsensitive ? "==[cd]" : "==[d]"; } +}; + +bool contains_substring(CFStringCompareFlags options, StringData v1, StringData v2) +{ + if (v2.is_null()) { + // Everything contains NULL + return true; + } + + if (v1.is_null()) { + // NULL contains nothing (except NULL, handled above) + return false; + } + + if (v2.size() == 0) { + // Everything (except NULL, handled above) contains the empty string + return true; + } + + auto s1 = util::adoptCF(CFStringCreateWithBytesNoCopy(kCFAllocatorSystemDefault, (const UInt8*)v1.data(), v1.size(), + kCFStringEncodingUTF8, false, kCFAllocatorNull)); + auto s2 = util::adoptCF(CFStringCreateWithBytesNoCopy(kCFAllocatorSystemDefault, (const UInt8*)v2.data(), v2.size(), + kCFStringEncodingUTF8, false, kCFAllocatorNull)); + + return CFStringFind(s1.get(), s2.get(), options).location != kCFNotFound; +} + +template +struct ContainsSubstring { + using CaseSensitive = ContainsSubstring; + using CaseInsensitive = ContainsSubstring; + + bool operator()(StringData v1, StringData v2, bool v1_null, bool v2_null) const + { + REALM_ASSERT_DEBUG(v1_null == v1.is_null()); + REALM_ASSERT_DEBUG(v2_null == v2.is_null()); + + return contains_substring(options, v1, v2); + } + + static const char* description() { return options & kCFCompareCaseInsensitive ? "CONTAINS[cd]" : "CONTAINS[d]"; } +}; + + +NSString *operatorName(NSPredicateOperatorType operatorType) +{ + switch (operatorType) { + case NSLessThanPredicateOperatorType: + return @"<"; + case NSLessThanOrEqualToPredicateOperatorType: + return @"<="; + case NSGreaterThanPredicateOperatorType: + return @">"; + case NSGreaterThanOrEqualToPredicateOperatorType: + return @">="; + case NSEqualToPredicateOperatorType: + return @"=="; + case NSNotEqualToPredicateOperatorType: + return @"!="; + case NSMatchesPredicateOperatorType: + return @"MATCHES"; + case NSLikePredicateOperatorType: + return @"LIKE"; + case NSBeginsWithPredicateOperatorType: + return @"BEGINSWITH"; + case NSEndsWithPredicateOperatorType: + return @"ENDSWITH"; + case NSInPredicateOperatorType: + return @"IN"; + case NSContainsPredicateOperatorType: + return @"CONTAINS"; + case NSBetweenPredicateOperatorType: + return @"BETWEEN"; + case NSCustomSelectorPredicateOperatorType: + return @"custom selector"; + } + + return [NSString stringWithFormat:@"unknown operator %lu", (unsigned long)operatorType]; +} + +Table& get_table(Group& group, RLMObjectSchema *objectSchema) +{ + return *ObjectStore::table_for_object_type(group, objectSchema.objectName.UTF8String); +} + +// A reference to a column within a query. Can be resolved to a Columns for use in query expressions. +class ColumnReference { +public: + ColumnReference(Query& query, Group& group, RLMSchema *schema, RLMProperty* property, const std::vector& links = {}) + : m_links(links), m_property(property), m_schema(schema), m_group(&group), m_query(&query), m_table(query.get_table()) + { + auto& table = walk_link_chain([](Table const&, ColKey, RLMPropertyType) { }); + m_col = table.get_column_key(m_property.columnName.UTF8String); + } + + template + auto resolve(SubQuery&&... subquery) const + { + static_assert(sizeof...(SubQuery) < 2, "resolve() takes at most one subquery"); + LinkChain lc(m_table); + walk_link_chain([&](Table const& link_origin, ColKey col, RLMPropertyType type) { + if (type != RLMPropertyTypeLinkingObjects) { + lc.link(col); + } + else { + lc.backlink(link_origin, col); + } + }); + + if (type() != RLMPropertyTypeLinkingObjects) { + return lc.column(column(), std::forward(subquery)...); + } + + if constexpr (std::is_same_v) { + return with_link_origin(m_property, [&](Table& table, ColKey col) { + return lc.column(table, col, std::forward(subquery)...); + }); + } + + REALM_TERMINATE("LinkingObjects property did not have column type Link"); + } + + RLMProperty *property() const { return m_property; } + ColKey column() const { return m_col; } + RLMPropertyType type() const { return property().type; } + Group& group() const { return *m_group; } + + RLMObjectSchema *link_target_object_schema() const + { + switch (type()) { + case RLMPropertyTypeObject: + case RLMPropertyTypeLinkingObjects: + return m_schema[property().objectClassName]; + default: + REALM_UNREACHABLE(); + } + } + + bool has_links() const { return m_links.size(); } + + bool has_any_to_many_links() const { + return std::any_of(begin(m_links), end(m_links), + [](RLMProperty *property) { return property.array; }); + } + + ColumnReference last_link_column() const { + REALM_ASSERT(!m_links.empty()); + return {*m_query, *m_group, m_schema, m_links.back(), {m_links.begin(), m_links.end() - 1}}; + } + + ColumnReference column_ignoring_links(Query& query) const { + return {query, *m_group, m_schema, m_property}; + } + +private: + template + Table const& walk_link_chain(Func&& func) const + { + auto table = m_query->get_table().unchecked_ptr(); + for (const auto& link : m_links) { + if (link.type != RLMPropertyTypeLinkingObjects) { + auto index = table->get_column_key(link.columnName.UTF8String); + func(*table, index, link.type); + table = table->get_link_target(index).unchecked_ptr(); + } + else { + with_link_origin(link, [&](Table& link_origin_table, ColKey link_origin_column) { + func(link_origin_table, link_origin_column, link.type); + table = &link_origin_table; + }); + } + } + return *table; + } + + template + auto with_link_origin(RLMProperty *prop, Func&& func) const + { + RLMObjectSchema *link_origin_schema = m_schema[prop.objectClassName]; + Table& link_origin_table = get_table(*m_group, link_origin_schema); + NSString *column_name = link_origin_schema[prop.linkOriginPropertyName].columnName; + auto link_origin_column = link_origin_table.get_column_key(column_name.UTF8String); + return func(link_origin_table, link_origin_column); + } + + std::vector m_links; + RLMProperty *m_property; + RLMSchema *m_schema; + Group *m_group; + Query *m_query; + ConstTableRef m_table; + ColKey m_col; +}; + +class CollectionOperation { +public: + enum Type { + Count, + Minimum, + Maximum, + Sum, + Average, + }; + + CollectionOperation(Type type, ColumnReference link_column, util::Optional column) + : m_type(type) + , m_link_column(std::move(link_column)) + , m_column(std::move(column)) + { + RLMPrecondition(m_link_column.property().array, + @"Invalid predicate", @"Collection operation can only be applied to a property of type RLMArray."); + + switch (m_type) { + case Count: + RLMPrecondition(!m_column, @"Invalid predicate", @"Result of @count does not have any properties."); + break; + case Minimum: + case Maximum: + case Sum: + case Average: + RLMPrecondition(m_column && RLMPropertyTypeIsNumeric(m_column->type()), @"Invalid predicate", + @"%@ can only be applied to a numeric property.", name_for_type(m_type)); + break; + } + } + + CollectionOperation(NSString *operationName, ColumnReference link_column, util::Optional column = util::none) + : CollectionOperation(type_for_name(operationName), std::move(link_column), std::move(column)) + { + } + + Type type() const { return m_type; } + const ColumnReference& link_column() const { return m_link_column; } + const ColumnReference& column() const { return *m_column; } + + void validate_comparison(id value) const { + switch (m_type) { + case Count: + case Average: + RLMPrecondition([value isKindOfClass:[NSNumber class]], @"Invalid operand", + @"%@ can only be compared with a numeric value.", name_for_type(m_type)); + break; + case Minimum: + case Maximum: + case Sum: + RLMPrecondition(RLMIsObjectValidForProperty(value, m_column->property()), @"Invalid operand", + @"%@ on a property of type %@ cannot be compared with '%@'", + name_for_type(m_type), RLMTypeToString(m_column->type()), value); + break; + } + } + + void validate_comparison(const ColumnReference& column) const { + switch (m_type) { + case Count: + RLMPrecondition(RLMPropertyTypeIsNumeric(column.type()), @"Invalid operand", + @"%@ can only be compared with a numeric value.", name_for_type(m_type)); + break; + case Average: + case Minimum: + case Maximum: + case Sum: + RLMPrecondition(RLMPropertyTypeIsNumeric(column.type()), @"Invalid operand", + @"%@ on a property of type %@ cannot be compared with property of type '%@'", + name_for_type(m_type), RLMTypeToString(m_column->type()), RLMTypeToString(column.type())); + break; + } + } + +private: + static Type type_for_name(NSString *name) { + if ([name isEqualToString:@"@count"]) { + return Count; + } + if ([name isEqualToString:@"@min"]) { + return Minimum; + } + if ([name isEqualToString:@"@max"]) { + return Maximum; + } + if ([name isEqualToString:@"@sum"]) { + return Sum; + } + if ([name isEqualToString:@"@avg"]) { + return Average; + } + @throw RLMPredicateException(@"Invalid predicate", @"Unsupported collection operation '%@'", name); + } + + static NSString *name_for_type(Type type) { + switch (type) { + case Count: return @"@count"; + case Minimum: return @"@min"; + case Maximum: return @"@max"; + case Sum: return @"@sum"; + case Average: return @"@avg"; + } + } + + Type m_type; + ColumnReference m_link_column; + util::Optional m_column; +}; + +class QueryBuilder { +public: + QueryBuilder(Query& query, Group& group, RLMSchema *schema) + : m_query(query), m_group(group), m_schema(schema) { } + + void apply_predicate(NSPredicate *predicate, RLMObjectSchema *objectSchema); + + + void apply_collection_operator_expression(RLMObjectSchema *desc, NSString *keyPath, id value, NSComparisonPredicate *pred); + void apply_value_expression(RLMObjectSchema *desc, NSString *keyPath, id value, NSComparisonPredicate *pred); + void apply_column_expression(RLMObjectSchema *desc, NSString *leftKeyPath, NSString *rightKeyPath, NSComparisonPredicate *predicate); + void apply_subquery_count_expression(RLMObjectSchema *objectSchema, NSExpression *subqueryExpression, + NSPredicateOperatorType operatorType, NSExpression *right); + void apply_function_subquery_expression(RLMObjectSchema *objectSchema, NSExpression *functionExpression, + NSPredicateOperatorType operatorType, NSExpression *right); + void apply_function_expression(RLMObjectSchema *objectSchema, NSExpression *functionExpression, + NSPredicateOperatorType operatorType, NSExpression *right); + + + template + void add_numeric_constraint(RLMPropertyType datatype, + NSPredicateOperatorType operatorType, + A&& lhs, B&& rhs); + + template + void add_bool_constraint(RLMPropertyType, NSPredicateOperatorType operatorType, A&& lhs, B&& rhs); + + void add_substring_constraint(null, Query condition); + template + void add_substring_constraint(const T& value, Query condition); + template + void add_substring_constraint(const Columns& value, Query condition); + + template + void add_string_constraint(NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions predicateOptions, + Columns &&column, + T value); + + void add_string_constraint(NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions predicateOptions, + StringData value, + Columns&& column); + + template + void add_constraint(RLMPropertyType type, + NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions predicateOptions, + L const& lhs, R const& rhs); + template + void do_add_constraint(RLMPropertyType type, NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions predicateOptions, T&&... values); + void do_add_constraint(RLMPropertyType, NSPredicateOperatorType, NSComparisonPredicateOptions, id, realm::null); + + void add_between_constraint(const ColumnReference& column, id value); + + void add_binary_constraint(NSPredicateOperatorType operatorType, const ColumnReference& column, BinaryData value); + void add_binary_constraint(NSPredicateOperatorType operatorType, const ColumnReference& column, id value); + void add_binary_constraint(NSPredicateOperatorType operatorType, const ColumnReference& column, null); + void add_binary_constraint(NSPredicateOperatorType operatorType, id value, const ColumnReference& column); + void add_binary_constraint(NSPredicateOperatorType, const ColumnReference&, const ColumnReference&); + + void add_link_constraint(NSPredicateOperatorType operatorType, const ColumnReference& column, RLMObjectBase *obj); + void add_link_constraint(NSPredicateOperatorType operatorType, const ColumnReference& column, realm::null); + template + void add_link_constraint(NSPredicateOperatorType operatorType, T obj, const ColumnReference& column); + void add_link_constraint(NSPredicateOperatorType, const ColumnReference&, const ColumnReference&); + + template + void add_collection_operation_constraint(RLMPropertyType propertyType, NSPredicateOperatorType operatorType, T... values); + template + void add_collection_operation_constraint(NSPredicateOperatorType operatorType, + CollectionOperation collectionOperation, T... values); + + + CollectionOperation collection_operation_from_key_path(RLMObjectSchema *desc, NSString *keyPath); + ColumnReference column_reference_from_key_path(RLMObjectSchema *objectSchema, NSString *keyPath, bool isAggregate); + +private: + Query& m_query; + Group& m_group; + RLMSchema *m_schema; +}; + +// add a clause for numeric constraints based on operator type +template +void QueryBuilder::add_numeric_constraint(RLMPropertyType datatype, + NSPredicateOperatorType operatorType, + A&& lhs, B&& rhs) +{ + switch (operatorType) { + case NSLessThanPredicateOperatorType: + m_query.and_query(lhs < rhs); + break; + case NSLessThanOrEqualToPredicateOperatorType: + m_query.and_query(lhs <= rhs); + break; + case NSGreaterThanPredicateOperatorType: + m_query.and_query(lhs > rhs); + break; + case NSGreaterThanOrEqualToPredicateOperatorType: + m_query.and_query(lhs >= rhs); + break; + case NSEqualToPredicateOperatorType: + m_query.and_query(lhs == rhs); + break; + case NSNotEqualToPredicateOperatorType: + m_query.and_query(lhs != rhs); + break; + default: + @throw RLMPredicateException(@"Invalid operator type", + @"Operator '%@' not supported for type %@", + operatorName(operatorType), RLMTypeToString(datatype)); + } +} + +template +void QueryBuilder::add_bool_constraint(RLMPropertyType datatype, + NSPredicateOperatorType operatorType, + A&& lhs, B&& rhs) { + switch (operatorType) { + case NSEqualToPredicateOperatorType: + m_query.and_query(lhs == rhs); + break; + case NSNotEqualToPredicateOperatorType: + m_query.and_query(lhs != rhs); + break; + default: + @throw RLMPredicateException(@"Invalid operator type", + @"Operator '%@' not supported for type %@", + operatorName(operatorType), RLMTypeToString(datatype)); + } +} + +void QueryBuilder::add_substring_constraint(null, Query) { + // Foundation always returns false for substring operations with a RHS of null or "". + m_query.and_query(std::unique_ptr(new FalseExpression)); +} + +template +void QueryBuilder::add_substring_constraint(const T& value, Query condition) { + // Foundation always returns false for substring operations with a RHS of null or "". + m_query.and_query(value.size() + ? std::move(condition) + : std::unique_ptr(new FalseExpression)); +} + +template +void QueryBuilder::add_substring_constraint(const Columns& value, Query condition) { + // Foundation always returns false for substring operations with a RHS of null or "". + // We don't need to concern ourselves with the possibility of value traversing a link list + // and producing multiple values per row as such expressions will have been rejected. + m_query.and_query(const_cast&>(value).size() != 0 && std::move(condition)); +} + +template +void QueryBuilder::add_string_constraint(NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions predicateOptions, + Columns &&column, + T value) { + bool caseSensitive = !(predicateOptions & NSCaseInsensitivePredicateOption); + bool diacriticSensitive = !(predicateOptions & NSDiacriticInsensitivePredicateOption); + + if (diacriticSensitive) { + switch (operatorType) { + case NSBeginsWithPredicateOperatorType: + add_substring_constraint(value, column.begins_with(value, caseSensitive)); + break; + case NSEndsWithPredicateOperatorType: + add_substring_constraint(value, column.ends_with(value, caseSensitive)); + break; + case NSContainsPredicateOperatorType: + add_substring_constraint(value, column.contains(value, caseSensitive)); + break; + case NSEqualToPredicateOperatorType: + m_query.and_query(column.equal(value, caseSensitive)); + break; + case NSNotEqualToPredicateOperatorType: + m_query.and_query(column.not_equal(value, caseSensitive)); + break; + case NSLikePredicateOperatorType: + m_query.and_query(column.like(value, caseSensitive)); + break; + default: + @throw RLMPredicateException(@"Invalid operator type", + @"Operator '%@' not supported for string type", + operatorName(operatorType)); + } + return; + } + + auto as_subexpr = util::overload([](StringData value) { return make_subexpr(value); }, + [](const Columns& c) { return c.clone(); }); + auto left = as_subexpr(column); + auto right = as_subexpr(value); + + auto make_constraint = [&](auto comparator) { + using Comparator = decltype(comparator); + using CompareCS = Compare; + using CompareCI = Compare; + if (caseSensitive) { + return make_expression(std::move(left), std::move(right)); + } + else { + return make_expression(std::move(left), std::move(right)); + } + }; + + switch (operatorType) { + case NSBeginsWithPredicateOperatorType: { + using C = ContainsSubstring; + add_substring_constraint(value, make_constraint(C{})); + break; + } + case NSEndsWithPredicateOperatorType: { + using C = ContainsSubstring; + add_substring_constraint(value, make_constraint(C{})); + break; + } + case NSContainsPredicateOperatorType: { + using C = ContainsSubstring; + add_substring_constraint(value, make_constraint(C{})); + break; + } + case NSNotEqualToPredicateOperatorType: + m_query.Not(); + REALM_FALLTHROUGH; + case NSEqualToPredicateOperatorType: + m_query.and_query(make_constraint(Equal{})); + break; + case NSLikePredicateOperatorType: + @throw RLMPredicateException(@"Invalid operator type", + @"Operator 'LIKE' not supported with diacritic-insensitive modifier."); + default: + @throw RLMPredicateException(@"Invalid operator type", + @"Operator '%@' not supported for string type", operatorName(operatorType)); + } +} + +void QueryBuilder::add_string_constraint(NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions predicateOptions, + StringData value, + Columns&& column) { + switch (operatorType) { + case NSEqualToPredicateOperatorType: + case NSNotEqualToPredicateOperatorType: + add_string_constraint(operatorType, predicateOptions, std::move(column), value); + break; + default: + @throw RLMPredicateException(@"Invalid operator type", + @"Operator '%@' is not supported for string type with key path on right side of operator", + operatorName(operatorType)); + } +} + +id value_from_constant_expression_or_value(id value) { + if (NSExpression *exp = RLMDynamicCast(value)) { + RLMPrecondition(exp.expressionType == NSConstantValueExpressionType, + @"Invalid value", + @"Expressions within predicate aggregates must be constant values"); + return exp.constantValue; + } + return value; +} + +void validate_and_extract_between_range(id value, RLMProperty *prop, id *from, id *to) { + NSArray *array = RLMDynamicCast(value); + RLMPrecondition(array, @"Invalid value", @"object must be of type NSArray for BETWEEN operations"); + RLMPrecondition(array.count == 2, @"Invalid value", @"NSArray object must contain exactly two objects for BETWEEN operations"); + + *from = value_from_constant_expression_or_value(array.firstObject); + *to = value_from_constant_expression_or_value(array.lastObject); + RLMPrecondition(RLMIsObjectValidForProperty(*from, prop) && RLMIsObjectValidForProperty(*to, prop), + @"Invalid value", + @"NSArray objects must be of type %@ for BETWEEN operations", RLMTypeToString(prop.type)); +} + +void QueryBuilder::add_between_constraint(const ColumnReference& column, id value) { + if (column.has_any_to_many_links()) { + auto link_column = column.last_link_column(); + Query subquery = get_table(m_group, link_column.link_target_object_schema()).where(); + QueryBuilder(subquery, m_group, m_schema).add_between_constraint(column.column_ignoring_links(subquery), value); + + m_query.and_query(link_column.resolve(std::move(subquery)).count() > 0); + return; + } + + id from, to; + validate_and_extract_between_range(value, column.property(), &from, &to); + + RLMPropertyType type = column.type(); + + m_query.group(); + add_constraint(type, NSGreaterThanOrEqualToPredicateOperatorType, 0, column, from); + add_constraint(type, NSLessThanOrEqualToPredicateOperatorType, 0, column, to); + m_query.end_group(); +} + +void QueryBuilder::add_binary_constraint(NSPredicateOperatorType operatorType, + const ColumnReference& column, + BinaryData value) { + RLMPrecondition(!column.has_links(), @"Unsupported operator", @"NSData properties cannot be queried over an object link."); + + auto index = column.column(); + Query query = m_query.get_table()->where(); + + switch (operatorType) { + case NSBeginsWithPredicateOperatorType: + add_substring_constraint(value, query.begins_with(index, value)); + break; + case NSEndsWithPredicateOperatorType: + add_substring_constraint(value, query.ends_with(index, value)); + break; + case NSContainsPredicateOperatorType: + add_substring_constraint(value, query.contains(index, value)); + break; + case NSEqualToPredicateOperatorType: + m_query.equal(index, value); + break; + case NSNotEqualToPredicateOperatorType: + m_query.not_equal(index, value); + break; + default: + @throw RLMPredicateException(@"Invalid operator type", + @"Operator '%@' not supported for binary type", operatorName(operatorType)); + } +} + +void QueryBuilder::add_binary_constraint(NSPredicateOperatorType operatorType, const ColumnReference& column, id value) { + add_binary_constraint(operatorType, column, RLMBinaryDataForNSData(value)); +} + +void QueryBuilder::add_binary_constraint(NSPredicateOperatorType operatorType, const ColumnReference& column, null) { + add_binary_constraint(operatorType, column, BinaryData()); +} + +void QueryBuilder::add_binary_constraint(NSPredicateOperatorType operatorType, id value, const ColumnReference& column) { + switch (operatorType) { + case NSEqualToPredicateOperatorType: + case NSNotEqualToPredicateOperatorType: + add_binary_constraint(operatorType, column, value); + break; + default: + @throw RLMPredicateException(@"Invalid operator type", + @"Operator '%@' is not supported for binary type with key path on right side of operator", + operatorName(operatorType)); + } +} + +void QueryBuilder::add_binary_constraint(NSPredicateOperatorType, const ColumnReference&, const ColumnReference&) { + @throw RLMPredicateException(@"Invalid predicate", @"Comparisons between two NSData properties are not supported"); +} + +void QueryBuilder::add_link_constraint(NSPredicateOperatorType operatorType, + const ColumnReference& column, RLMObjectBase *obj) { + if (!obj->_row.is_valid()) { + // Unmanaged or deleted objects, so compare it to an object that doesn't + // exist from the target table + struct FakeObj : public ConstObj { + FakeObj(ColumnReference const& column) { + m_table = TableRef::unsafe_create(&::get_table(column.group(), column.link_target_object_schema())); + } + } fake(column); + add_bool_constraint(RLMPropertyTypeObject, operatorType, column.resolve(), fake); + } + else { + add_bool_constraint(RLMPropertyTypeObject, operatorType, column.resolve(), obj->_row); + } +} + +void QueryBuilder::add_link_constraint(NSPredicateOperatorType operatorType, + const ColumnReference& column, + realm::null) { + add_bool_constraint(RLMPropertyTypeObject, operatorType, column.resolve(), null()); +} + +template +void QueryBuilder::add_link_constraint(NSPredicateOperatorType operatorType, T obj, const ColumnReference& column) { + // Link constraints only support the equal-to and not-equal-to operators. The order of operands + // is not important for those comparisons so we can delegate to the other implementation. + add_link_constraint(operatorType, column, obj); +} + +void QueryBuilder::add_link_constraint(NSPredicateOperatorType, const ColumnReference&, const ColumnReference&) { + // This is not actually reachable as this case is caught earlier, but this + // overload is needed for the code to compile + @throw RLMPredicateException(@"Invalid predicate", @"Comparisons between two RLMArray properties are not supported"); +} + + +// iterate over an array of subpredicates, using @func to build a query from each +// one and ORing them together +template +void process_or_group(Query &query, id array, Func&& func) { + array = RLMAsFastEnumeration(array); + RLMPrecondition(array, @"Invalid value", @"IN clause requires an array of items"); + + query.group(); + + bool first = true; + for (id item in array) { + if (!first) { + query.Or(); + } + first = false; + + func(item); + } + + if (first) { + // Queries can't be empty, so if there's zero things in the OR group + // validation will fail. Work around this by adding an expression which + // will never find any rows in a table. + query.and_query(std::unique_ptr(new FalseExpression)); + } + + query.end_group(); +} + +template +RequestedType convert(id value); + +template <> +Timestamp convert(id value) { + return RLMTimestampForNSDate(value); +} + +template <> +bool convert(id value) { + return [value boolValue]; +} + +template <> +Double convert(id value) { + return [value doubleValue]; +} + +template <> +Float convert(id value) { + return [value floatValue]; +} + +template <> +Int convert(id value) { + return [value longLongValue]; +} + +template <> +String convert(id value) { + return RLMStringDataWithNSString(value); +} + +template <> +Decimal128 convert(id value) { + return RLMObjcToDecimal128(value); +} + +template <> +ObjectId convert(id value) { + if (auto objectId = RLMDynamicCast(value)) { + return objectId.value; + } + if (auto string = RLMDynamicCast(value)) { + return ObjectId(string.UTF8String); + } + @throw RLMException(@"Cannot convert value '%@' of type '%@' to object id", value, [value class]); +} + +template +realm::null value_of_type(realm::null) { + return realm::null(); +} + +template +auto value_of_type(id value) { + return ::convert(value); +} + +template +auto value_of_type(const ColumnReference& column) { + return column.resolve(); +} + + +template +void QueryBuilder::do_add_constraint(RLMPropertyType type, NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions predicateOptions, T&&... values) +{ + static_assert(sizeof...(T) == 2, "do_add_constraint accepts only two values as arguments"); + + switch (type) { + case RLMPropertyTypeBool: + add_bool_constraint(type, operatorType, value_of_type(values)...); + break; + case RLMPropertyTypeObjectId: + add_bool_constraint(type, operatorType, value_of_type(values)...); + break; + case RLMPropertyTypeDate: + add_numeric_constraint(type, operatorType, value_of_type(values)...); + break; + case RLMPropertyTypeDouble: + add_numeric_constraint(type, operatorType, value_of_type(values)...); + break; + case RLMPropertyTypeFloat: + add_numeric_constraint(type, operatorType, value_of_type(values)...); + break; + case RLMPropertyTypeInt: + add_numeric_constraint(type, operatorType, value_of_type(values)...); + break; + case RLMPropertyTypeDecimal128: + add_numeric_constraint(type, operatorType, value_of_type(values)...); + break; + case RLMPropertyTypeString: + add_string_constraint(operatorType, predicateOptions, value_of_type(values)...); + break; + case RLMPropertyTypeData: + add_binary_constraint(operatorType, values...); + break; + case RLMPropertyTypeObject: + case RLMPropertyTypeLinkingObjects: + add_link_constraint(operatorType, values...); + break; + default: + @throw RLMPredicateException(@"Unsupported predicate value type", + @"Object type %@ not supported", RLMTypeToString(type)); + } +} + +void QueryBuilder::do_add_constraint(RLMPropertyType, NSPredicateOperatorType, NSComparisonPredicateOptions, id, realm::null) +{ + // This is not actually reachable as this case is caught earlier, but this + // overload is needed for the code to compile + @throw RLMPredicateException(@"Invalid predicate expressions", + @"Predicate expressions must compare a keypath and another keypath or a constant value"); +} + +bool is_nsnull(id value) { + return !value || value == NSNull.null; +} + +template +bool is_nsnull(T) { + return false; +} + +template +void QueryBuilder::add_constraint(RLMPropertyType type, NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions predicateOptions, L const& lhs, R const& rhs) +{ + // The expression operators are only overloaded for realm::null on the rhs + RLMPrecondition(!is_nsnull(lhs), @"Unsupported operator", + @"Nil is only supported on the right side of operators"); + + if (is_nsnull(rhs)) { + do_add_constraint(type, operatorType, predicateOptions, lhs, realm::null()); + } + else { + do_add_constraint(type, operatorType, predicateOptions, lhs, rhs); + } +} + +struct KeyPath { + std::vector links; + RLMProperty *property; + bool containsToManyRelationship; +}; + +KeyPath key_path_from_string(RLMSchema *schema, RLMObjectSchema *objectSchema, NSString *keyPath) +{ + RLMProperty *property; + std::vector links; + + bool keyPathContainsToManyRelationship = false; + + NSUInteger start = 0, length = keyPath.length, end = NSNotFound; + do { + end = [keyPath rangeOfString:@"." options:0 range:{start, length - start}].location; + NSString *propertyName = [keyPath substringWithRange:{start, end == NSNotFound ? length - start : end - start}]; + property = objectSchema[propertyName]; + RLMPrecondition(property, @"Invalid property name", + @"Property '%@' not found in object of type '%@'", + propertyName, objectSchema.className); + + if (property.array) + keyPathContainsToManyRelationship = true; + + if (end != NSNotFound) { + RLMPrecondition(property.type == RLMPropertyTypeObject || property.type == RLMPropertyTypeLinkingObjects, + @"Invalid value", @"Property '%@' is not a link in object of type '%@'", + propertyName, objectSchema.className); + + links.push_back(property); + REALM_ASSERT(property.objectClassName); + objectSchema = schema[property.objectClassName]; + } + + start = end + 1; + } while (end != NSNotFound); + + return {std::move(links), property, keyPathContainsToManyRelationship}; +} + +ColumnReference QueryBuilder::column_reference_from_key_path(RLMObjectSchema *objectSchema, + NSString *keyPathString, bool isAggregate) +{ + auto keyPath = key_path_from_string(m_schema, objectSchema, keyPathString); + + if (isAggregate && !keyPath.containsToManyRelationship) { + @throw RLMPredicateException(@"Invalid predicate", + @"Aggregate operations can only be used on key paths that include an array property"); + } else if (!isAggregate && keyPath.containsToManyRelationship) { + @throw RLMPredicateException(@"Invalid predicate", + @"Key paths that include an array property must use aggregate operations"); + } + + return ColumnReference(m_query, m_group, m_schema, keyPath.property, std::move(keyPath.links)); +} + +void validate_property_value(const ColumnReference& column, + __unsafe_unretained id const value, + __unsafe_unretained NSString *const err, + __unsafe_unretained RLMObjectSchema *const objectSchema, + __unsafe_unretained NSString *const keyPath) { + RLMProperty *prop = column.property(); + if (prop.array) { + RLMPrecondition([RLMObjectBaseObjectSchema(RLMDynamicCast(value)).className isEqualToString:prop.objectClassName], + @"Invalid value", err, prop.objectClassName, keyPath, objectSchema.className, value); + } + else { + RLMPrecondition(RLMIsObjectValidForProperty(value, prop), + @"Invalid value", err, RLMTypeToString(prop.type), keyPath, objectSchema.className, value); + } + if (RLMObjectBase *obj = RLMDynamicCast(value)) { + RLMPrecondition(!obj->_row.is_valid() || &column.group() == &obj->_realm.group, + @"Invalid value origin", @"Object must be from the Realm being queried"); + } +} + +template +struct ValueOfTypeWithCollectionOperationHelper; + +template <> +struct ValueOfTypeWithCollectionOperationHelper { + static auto convert(const CollectionOperation& operation) + { + assert(operation.type() == CollectionOperation::Count); + return operation.link_column().resolve().count(); + } +}; + +#define VALUE_OF_TYPE_WITH_COLLECTION_OPERATOR_HELPER(OperationType, function) \ +template \ +struct ValueOfTypeWithCollectionOperationHelper { \ + static auto convert(const CollectionOperation& operation) \ + { \ + REALM_ASSERT(operation.type() == OperationType); \ + auto targetColumn = operation.link_column().resolve().template column(operation.column().column()); \ + return targetColumn.function(); \ + } \ +} \ + +VALUE_OF_TYPE_WITH_COLLECTION_OPERATOR_HELPER(CollectionOperation::Minimum, min); +VALUE_OF_TYPE_WITH_COLLECTION_OPERATOR_HELPER(CollectionOperation::Maximum, max); +VALUE_OF_TYPE_WITH_COLLECTION_OPERATOR_HELPER(CollectionOperation::Sum, sum); +VALUE_OF_TYPE_WITH_COLLECTION_OPERATOR_HELPER(CollectionOperation::Average, average); +#undef VALUE_OF_TYPE_WITH_COLLECTION_OPERATOR_HELPER + +template +auto value_of_type_with_collection_operation(T&& value) { + return value_of_type(std::forward(value)); +} + +template +auto value_of_type_with_collection_operation(CollectionOperation operation) { + using helper = ValueOfTypeWithCollectionOperationHelper; + return helper::convert(operation); +} + +template +void QueryBuilder::add_collection_operation_constraint(RLMPropertyType propertyType, NSPredicateOperatorType operatorType, T... values) +{ + switch (propertyType) { + case RLMPropertyTypeInt: + add_numeric_constraint(propertyType, operatorType, value_of_type_with_collection_operation(values)...); + break; + case RLMPropertyTypeFloat: + add_numeric_constraint(propertyType, operatorType, value_of_type_with_collection_operation(values)...); + break; + case RLMPropertyTypeDouble: + add_numeric_constraint(propertyType, operatorType, value_of_type_with_collection_operation(values)...); + break; + case RLMPropertyTypeDecimal128: + add_numeric_constraint(propertyType, operatorType, value_of_type_with_collection_operation(values)...); + break; + default: + REALM_ASSERT(false && "Only numeric property types should hit this path."); + } +} + +template +void QueryBuilder::add_collection_operation_constraint(NSPredicateOperatorType operatorType, + CollectionOperation collectionOperation, T... values) +{ + static_assert(sizeof...(T) == 2, "add_collection_operation_constraint accepts only two values as arguments"); + + switch (collectionOperation.type()) { + case CollectionOperation::Count: + add_numeric_constraint(RLMPropertyTypeInt, operatorType, + value_of_type_with_collection_operation(values)...); + break; + case CollectionOperation::Minimum: + add_collection_operation_constraint(collectionOperation.column().type(), operatorType, values...); + break; + case CollectionOperation::Maximum: + add_collection_operation_constraint(collectionOperation.column().type(), operatorType, values...); + break; + case CollectionOperation::Sum: + add_collection_operation_constraint(collectionOperation.column().type(), operatorType, values...); + break; + case CollectionOperation::Average: + add_collection_operation_constraint(collectionOperation.column().type(), operatorType, values...); + break; + } +} + +bool key_path_contains_collection_operator(NSString *keyPath) { + return [keyPath rangeOfString:@"@"].location != NSNotFound; +} + +NSString *get_collection_operation_name_from_key_path(NSString *keyPath, NSString **leadingKeyPath, + NSString **trailingKey) { + NSRange at = [keyPath rangeOfString:@"@"]; + if (at.location == NSNotFound || at.location >= keyPath.length - 1) { + @throw RLMPredicateException(@"Invalid key path", @"'%@' is not a valid key path'", keyPath); + } + + if (at.location == 0 || [keyPath characterAtIndex:at.location - 1] != '.') { + @throw RLMPredicateException(@"Invalid key path", @"'%@' is not a valid key path'", keyPath); + } + + NSRange trailingKeyRange = [keyPath rangeOfString:@"." options:0 range:{at.location, keyPath.length - at.location} locale:nil]; + + *leadingKeyPath = [keyPath substringToIndex:at.location - 1]; + if (trailingKeyRange.location == NSNotFound) { + *trailingKey = nil; + return [keyPath substringFromIndex:at.location]; + } else { + *trailingKey = [keyPath substringFromIndex:trailingKeyRange.location + 1]; + return [keyPath substringWithRange:{at.location, trailingKeyRange.location - at.location}]; + } +} + +CollectionOperation QueryBuilder::collection_operation_from_key_path(RLMObjectSchema *desc, NSString *keyPath) { + NSString *leadingKeyPath; + NSString *trailingKey; + NSString *collectionOperationName = get_collection_operation_name_from_key_path(keyPath, &leadingKeyPath, &trailingKey); + + ColumnReference linkColumn = column_reference_from_key_path(desc, leadingKeyPath, true); + util::Optional column; + if (trailingKey) { + RLMPrecondition([trailingKey rangeOfString:@"."].location == NSNotFound, @"Invalid key path", + @"Right side of collection operator may only have a single level key"); + NSString *fullKeyPath = [leadingKeyPath stringByAppendingFormat:@".%@", trailingKey]; + column = column_reference_from_key_path(desc, fullKeyPath, true); + } + + return {collectionOperationName, std::move(linkColumn), std::move(column)}; +} + +void QueryBuilder::apply_collection_operator_expression(RLMObjectSchema *desc, + NSString *keyPath, id value, + NSComparisonPredicate *pred) { + CollectionOperation operation = collection_operation_from_key_path(desc, keyPath); + operation.validate_comparison(value); + + if (pred.leftExpression.expressionType == NSKeyPathExpressionType) { + add_collection_operation_constraint(pred.predicateOperatorType, operation, operation, value); + } else { + add_collection_operation_constraint(pred.predicateOperatorType, operation, value, operation); + } +} + +void QueryBuilder::apply_value_expression(RLMObjectSchema *desc, + NSString *keyPath, id value, + NSComparisonPredicate *pred) +{ + if (key_path_contains_collection_operator(keyPath)) { + apply_collection_operator_expression(desc, keyPath, value, pred); + return; + } + + bool isAny = pred.comparisonPredicateModifier == NSAnyPredicateModifier; + ColumnReference column = column_reference_from_key_path(desc, keyPath, isAny); + + // check to see if this is a between query + if (pred.predicateOperatorType == NSBetweenPredicateOperatorType) { + add_between_constraint(std::move(column), value); + return; + } + + // turn "key.path IN collection" into ored together ==. "collection IN key.path" is handled elsewhere. + if (pred.predicateOperatorType == NSInPredicateOperatorType) { + process_or_group(m_query, value, [&](id item) { + id normalized = value_from_constant_expression_or_value(item); + validate_property_value(column, normalized, + @"Expected object of type %@ in IN clause for property '%@' on object of type '%@', but received: %@", desc, keyPath); + add_constraint(column.type(), NSEqualToPredicateOperatorType, pred.options, column, normalized); + }); + return; + } + + validate_property_value(column, value, @"Expected object of type %@ for property '%@' on object of type '%@', but received: %@", desc, keyPath); + if (pred.leftExpression.expressionType == NSKeyPathExpressionType) { + add_constraint(column.type(), pred.predicateOperatorType, pred.options, std::move(column), value); + } else { + add_constraint(column.type(), pred.predicateOperatorType, pred.options, value, std::move(column)); + } +} + +void QueryBuilder::apply_column_expression(RLMObjectSchema *desc, + NSString *leftKeyPath, NSString *rightKeyPath, + NSComparisonPredicate *predicate) +{ + bool left_key_path_contains_collection_operator = key_path_contains_collection_operator(leftKeyPath); + bool right_key_path_contains_collection_operator = key_path_contains_collection_operator(rightKeyPath); + if (left_key_path_contains_collection_operator && right_key_path_contains_collection_operator) { + @throw RLMPredicateException(@"Unsupported predicate", @"Key paths including aggregate operations cannot be compared with other aggregate operations."); + } + + if (left_key_path_contains_collection_operator) { + CollectionOperation left = collection_operation_from_key_path(desc, leftKeyPath); + ColumnReference right = column_reference_from_key_path(desc, rightKeyPath, false); + left.validate_comparison(right); + add_collection_operation_constraint(predicate.predicateOperatorType, left, left, std::move(right)); + return; + } + if (right_key_path_contains_collection_operator) { + ColumnReference left = column_reference_from_key_path(desc, leftKeyPath, false); + CollectionOperation right = collection_operation_from_key_path(desc, rightKeyPath); + right.validate_comparison(left); + add_collection_operation_constraint(predicate.predicateOperatorType, right, std::move(left), right); + return; + } + + bool isAny = false; + ColumnReference left = column_reference_from_key_path(desc, leftKeyPath, isAny); + ColumnReference right = column_reference_from_key_path(desc, rightKeyPath, isAny); + + // NOTE: It's assumed that column type must match and no automatic type conversion is supported. + RLMPrecondition(left.type() == right.type(), + RLMPropertiesComparisonTypeMismatchException, + RLMPropertiesComparisonTypeMismatchReason, + RLMTypeToString(left.type()), + RLMTypeToString(right.type())); + + // TODO: Should we handle special case where left row is the same as right row (tautology) + add_constraint(left.type(), predicate.predicateOperatorType, predicate.options, + std::move(left), std::move(right)); +} + +// Identify expressions of the form [SELF valueForKeyPath:] +bool is_self_value_for_key_path_function_expression(NSExpression *expression) +{ + if (expression.expressionType != NSFunctionExpressionType) + return false; + + if (expression.operand.expressionType != NSEvaluatedObjectExpressionType) + return false; + + return [expression.function isEqualToString:@"valueForKeyPath:"]; +} + +// -[NSPredicate predicateWithSubtitutionVariables:] results in function expressions of the form [SELF valueForKeyPath:] +// that apply_predicate cannot handle. Replace such expressions with equivalent NSKeyPathExpressionType expressions. +NSExpression *simplify_self_value_for_key_path_function_expression(NSExpression *expression) { + if (is_self_value_for_key_path_function_expression(expression)) { + if (NSString *keyPath = [expression.arguments.firstObject keyPath]) { + return [NSExpression expressionForKeyPath:keyPath]; + } + } + return expression; +} + +void QueryBuilder::apply_subquery_count_expression(RLMObjectSchema *objectSchema, + NSExpression *subqueryExpression, NSPredicateOperatorType operatorType, NSExpression *right) { + if (right.expressionType != NSConstantValueExpressionType || ![right.constantValue isKindOfClass:[NSNumber class]]) { + @throw RLMPredicateException(@"Invalid predicate expression", @"SUBQUERY(…).@count is only supported when compared with a constant number."); + } + int64_t value = [right.constantValue integerValue]; + + ColumnReference collectionColumn = column_reference_from_key_path(objectSchema, [subqueryExpression.collection keyPath], true); + RLMObjectSchema *collectionMemberObjectSchema = m_schema[collectionColumn.property().objectClassName]; + + // Eliminate references to the iteration variable in the subquery. + NSPredicate *subqueryPredicate = [subqueryExpression.predicate predicateWithSubstitutionVariables:@{ subqueryExpression.variable : [NSExpression expressionForEvaluatedObject] }]; + subqueryPredicate = transformPredicate(subqueryPredicate, simplify_self_value_for_key_path_function_expression); + + Query subquery = RLMPredicateToQuery(subqueryPredicate, collectionMemberObjectSchema, m_schema, m_group); + add_numeric_constraint(RLMPropertyTypeInt, operatorType, + collectionColumn.resolve(std::move(subquery)).count(), value); +} + +void QueryBuilder::apply_function_subquery_expression(RLMObjectSchema *objectSchema, NSExpression *functionExpression, + NSPredicateOperatorType operatorType, NSExpression *right) { + if (![functionExpression.function isEqualToString:@"valueForKeyPath:"] || functionExpression.arguments.count != 1) { + @throw RLMPredicateException(@"Invalid predicate", @"The '%@' function is not supported on the result of a SUBQUERY.", functionExpression.function); + } + + NSExpression *keyPathExpression = functionExpression.arguments.firstObject; + if ([keyPathExpression.keyPath isEqualToString:@"@count"]) { + apply_subquery_count_expression(objectSchema, functionExpression.operand, operatorType, right); + } else { + @throw RLMPredicateException(@"Invalid predicate", @"SUBQUERY is only supported when immediately followed by .@count that is compared with a constant number."); + } +} + +void QueryBuilder::apply_function_expression(RLMObjectSchema *objectSchema, NSExpression *functionExpression, + NSPredicateOperatorType operatorType, NSExpression *right) { + if (functionExpression.operand.expressionType == NSSubqueryExpressionType) { + apply_function_subquery_expression(objectSchema, functionExpression, operatorType, right); + } else { + @throw RLMPredicateException(@"Invalid predicate", @"The '%@' function is not supported.", functionExpression.function); + } +} + + +void QueryBuilder::apply_predicate(NSPredicate *predicate, RLMObjectSchema *objectSchema) +{ + // Compound predicates. + if ([predicate isMemberOfClass:[NSCompoundPredicate class]]) { + NSCompoundPredicate *comp = (NSCompoundPredicate *)predicate; + + switch ([comp compoundPredicateType]) { + case NSAndPredicateType: + if (comp.subpredicates.count) { + // Add all of the subpredicates. + m_query.group(); + for (NSPredicate *subp in comp.subpredicates) { + apply_predicate(subp, objectSchema); + } + m_query.end_group(); + } else { + // NSCompoundPredicate's documentation states that an AND predicate with no subpredicates evaluates to TRUE. + m_query.and_query(std::unique_ptr(new TrueExpression)); + } + break; + + case NSOrPredicateType: { + // Add all of the subpredicates with ors inbetween. + process_or_group(m_query, comp.subpredicates, [&](__unsafe_unretained NSPredicate *const subp) { + apply_predicate(subp, objectSchema); + }); + break; + } + + case NSNotPredicateType: + // Add the negated subpredicate + m_query.Not(); + apply_predicate(comp.subpredicates.firstObject, objectSchema); + break; + + default: + @throw RLMPredicateException(@"Invalid compound predicate type", + @"Only support AND, OR and NOT predicate types"); + } + } + else if ([predicate isMemberOfClass:[NSComparisonPredicate class]]) { + NSComparisonPredicate *compp = (NSComparisonPredicate *)predicate; + + // check modifier + RLMPrecondition(compp.comparisonPredicateModifier != NSAllPredicateModifier, + @"Invalid predicate", @"ALL modifier not supported"); + + NSExpressionType exp1Type = compp.leftExpression.expressionType; + NSExpressionType exp2Type = compp.rightExpression.expressionType; + + if (compp.comparisonPredicateModifier == NSAnyPredicateModifier) { + // for ANY queries + RLMPrecondition(exp1Type == NSKeyPathExpressionType && exp2Type == NSConstantValueExpressionType, + @"Invalid predicate", + @"Predicate with ANY modifier must compare a KeyPath with RLMArray with a value"); + } + + if (compp.predicateOperatorType == NSBetweenPredicateOperatorType || compp.predicateOperatorType == NSInPredicateOperatorType) { + // Inserting an array via %@ gives NSConstantValueExpressionType, but including it directly gives NSAggregateExpressionType + if (exp1Type == NSKeyPathExpressionType && (exp2Type == NSAggregateExpressionType || exp2Type == NSConstantValueExpressionType)) { + // "key.path IN %@", "key.path IN {…}", "key.path BETWEEN %@", or "key.path BETWEEN {…}". + exp2Type = NSConstantValueExpressionType; + } + else if (compp.predicateOperatorType == NSInPredicateOperatorType && exp1Type == NSConstantValueExpressionType && exp2Type == NSKeyPathExpressionType) { + // "%@ IN key.path" is equivalent to "ANY key.path IN %@". Rewrite the former into the latter. + compp = [NSComparisonPredicate predicateWithLeftExpression:compp.rightExpression rightExpression:compp.leftExpression + modifier:NSAnyPredicateModifier type:NSEqualToPredicateOperatorType options:0]; + exp1Type = NSKeyPathExpressionType; + exp2Type = NSConstantValueExpressionType; + } + else { + if (compp.predicateOperatorType == NSBetweenPredicateOperatorType) { + @throw RLMPredicateException(@"Invalid predicate", + @"Predicate with BETWEEN operator must compare a KeyPath with an aggregate with two values"); + } + else if (compp.predicateOperatorType == NSInPredicateOperatorType) { + @throw RLMPredicateException(@"Invalid predicate", + @"Predicate with IN operator must compare a KeyPath with an aggregate"); + } + } + } + + if (exp1Type == NSKeyPathExpressionType && exp2Type == NSKeyPathExpressionType) { + // both expression are KeyPaths + apply_column_expression(objectSchema, compp.leftExpression.keyPath, compp.rightExpression.keyPath, compp); + } + else if (exp1Type == NSKeyPathExpressionType && exp2Type == NSConstantValueExpressionType) { + // comparing keypath to value + apply_value_expression(objectSchema, compp.leftExpression.keyPath, compp.rightExpression.constantValue, compp); + } + else if (exp1Type == NSConstantValueExpressionType && exp2Type == NSKeyPathExpressionType) { + // comparing value to keypath + apply_value_expression(objectSchema, compp.rightExpression.keyPath, compp.leftExpression.constantValue, compp); + } + else if (exp1Type == NSFunctionExpressionType) { + apply_function_expression(objectSchema, compp.leftExpression, compp.predicateOperatorType, compp.rightExpression); + } + else if (exp1Type == NSSubqueryExpressionType) { + // The subquery expressions that we support are handled by the NSFunctionExpressionType case above. + @throw RLMPredicateException(@"Invalid predicate expression", @"SUBQUERY is only supported when immediately followed by .@count."); + } + else { + @throw RLMPredicateException(@"Invalid predicate expressions", + @"Predicate expressions must compare a keypath and another keypath or a constant value"); + } + } + else if ([predicate isEqual:[NSPredicate predicateWithValue:YES]]) { + m_query.and_query(std::unique_ptr(new TrueExpression)); + } else if ([predicate isEqual:[NSPredicate predicateWithValue:NO]]) { + m_query.and_query(std::unique_ptr(new FalseExpression)); + } + else { + // invalid predicate type + @throw RLMPredicateException(@"Invalid predicate", + @"Only support compound, comparison, and constant predicates"); + } +} +} // namespace + +realm::Query RLMPredicateToQuery(NSPredicate *predicate, RLMObjectSchema *objectSchema, + RLMSchema *schema, Group &group) +{ + auto query = get_table(group, objectSchema).where(); + + // passing a nil predicate is a no-op + if (!predicate) { + return query; + } + + @autoreleasepool { + QueryBuilder(query, group, schema).apply_predicate(predicate, objectSchema); + } + + // Test the constructed query in core + std::string validateMessage = query.validate(); + RLMPrecondition(validateMessage.empty(), @"Invalid query", @"%.*s", + (int)validateMessage.size(), validateMessage.c_str()); + return query; +} diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMRealm+Sync.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMRealm+Sync.mm new file mode 100644 index 0000000..8ae2287 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMRealm+Sync.mm @@ -0,0 +1,40 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2017 Realm Inc. +// +// 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 "RLMRealm+Sync.h" + +#import "RLMObjectBase.h" +#import "RLMQueryUtil.hpp" +#import "RLMObjectSchema.h" +#import "RLMRealm_Private.hpp" +#import "RLMResults_Private.hpp" +#import "RLMSchema.h" +#import "RLMSyncSession.h" + +#import "results.hpp" +#import "shared_realm.hpp" + +using namespace realm; + +@implementation RLMRealm (Sync) + +- (RLMSyncSession *)syncSession { + return [RLMSyncSession sessionForRealm:self]; +} + +@end diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMRealm.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMRealm.mm new file mode 100644 index 0000000..cab3957 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMRealm.mm @@ -0,0 +1,996 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// 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 "RLMRealm_Private.hpp" + +#import "RLMAnalytics.hpp" +#import "RLMArray_Private.hpp" +#import "RLMMigration_Private.h" +#import "RLMObject_Private.h" +#import "RLMObject_Private.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObjectStore.h" +#import "RLMObservation.hpp" +#import "RLMProperty.h" +#import "RLMProperty_Private.h" +#import "RLMQueryUtil.hpp" +#import "RLMRealmConfiguration+Sync.h" +#import "RLMRealmConfiguration_Private.hpp" +#import "RLMRealmUtil.hpp" +#import "RLMSchema_Private.hpp" +#import "RLMThreadSafeReference_Private.hpp" +#import "RLMUpdateChecker.hpp" +#import "RLMUtil.hpp" + +#include "impl/realm_coordinator.hpp" +#include "object_store.hpp" +#include "schema.hpp" +#include "shared_realm.hpp" +#include "thread_safe_reference.hpp" +#include "util/scheduler.hpp" + +#include +#include +#include + +#if REALM_ENABLE_SYNC +#import "RLMSyncManager_Private.hpp" +#import "RLMSyncSession_Private.hpp" +#import "RLMSyncUtil_Private.hpp" + +#import "sync/async_open_task.hpp" +#import "sync/sync_session.hpp" +#endif + +using namespace realm; +using util::File; + +@interface RLMRealmNotificationToken : RLMNotificationToken +@property (nonatomic, strong) RLMRealm *realm; +@property (nonatomic, copy) RLMNotificationBlock block; +@end + +@interface RLMRealm () +@property (nonatomic, strong) NSHashTable *notificationHandlers; +- (void)sendNotifications:(RLMNotification)notification; +@end + +void RLMDisableSyncToDisk() { + realm::disable_sync_to_disk(); +} + +static std::atomic s_set_skip_backup_attribute{true}; +void RLMSetSkipBackupAttribute(bool value) { + s_set_skip_backup_attribute = value; +} + +static void RLMAddSkipBackupAttributeToItemAtPath(std::string_view path) { + [[NSURL fileURLWithPath:@(path.data())] setResourceValue:@YES forKey:NSURLIsExcludedFromBackupKey error:nil]; +} + +@implementation RLMRealmNotificationToken +- (void)invalidate { + [_realm verifyThread]; + [_realm.notificationHandlers removeObject:self]; + _realm = nil; + _block = nil; +} + +- (void)suppressNextNotification { + // Temporarily replace the block with one which restores the old block + // rather than producing a notification. + + // This briefly creates a retain cycle but it's fine because the block will + // be synchronously called shortly after this method is called. Unlike with + // collection notifications, this does not have to go through the object + // store or do fancy things to handle transaction coalescing because it's + // called synchronously by the obj-c code and not by the object store. + auto notificationBlock = _block; + _block = ^(RLMNotification, RLMRealm *) { + _block = notificationBlock; + }; +} + +- (void)dealloc { + if (_realm || _block) { + NSLog(@"RLMNotificationToken released without unregistering a notification. You must hold " + @"on to the RLMNotificationToken returned from addNotificationBlock and call " + @"-[RLMNotificationToken invalidate] when you no longer wish to receive RLMRealm notifications."); + } +} +@end + +#if !REALM_ENABLE_SYNC +@interface RLMAsyncOpenTask : NSObject +@end +@implementation RLMAsyncOpenTask +@end +#endif + +static bool shouldForciblyDisableEncryption() { + static bool disableEncryption = getenv("REALM_DISABLE_ENCRYPTION"); + return disableEncryption; +} + +NSData *RLMRealmValidatedEncryptionKey(NSData *key) { + if (shouldForciblyDisableEncryption()) { + return nil; + } + + if (key && key.length != 64) { + @throw RLMException(@"Encryption key must be exactly 64 bytes long"); + } + + return key; +} + +@implementation RLMRealm { + NSHashTable *_collectionEnumerators; + bool _sendingNotifications; +} + ++ (BOOL)isCoreDebug { + return realm::Version::has_feature(realm::feature_Debug); +} + ++ (void)initialize { + static bool initialized; + if (initialized) { + return; + } + initialized = true; + + RLMCheckForUpdates(); + RLMSendAnalytics(); +} + +- (instancetype)initPrivate { + self = [super init]; + return self; +} + +- (BOOL)isEmpty { + return realm::ObjectStore::is_empty(self.group); +} + +- (void)verifyThread { + try { + _realm->verify_thread(); + } + catch (std::exception const& e) { + @throw RLMException(e); + } +} + +- (BOOL)inWriteTransaction { + return _realm->is_in_transaction(); +} + +- (realm::Group &)group { + return _realm->read_group(); +} + +- (BOOL)autorefresh { + return _realm->auto_refresh(); +} + +- (void)setAutorefresh:(BOOL)autorefresh { + try { + _realm->set_auto_refresh(autorefresh); + } + catch (std::exception const& e) { + @throw RLMException(e); + } +} + ++ (instancetype)defaultRealm { + return [RLMRealm realmWithConfiguration:[RLMRealmConfiguration rawDefaultConfiguration] error:nil]; +} + ++ (instancetype)defaultRealmForQueue:(dispatch_queue_t)queue { + return [RLMRealm realmWithConfiguration:[RLMRealmConfiguration rawDefaultConfiguration] queue:queue error:nil]; +} + ++ (instancetype)realmWithURL:(NSURL *)fileURL { + RLMRealmConfiguration *configuration = [RLMRealmConfiguration defaultConfiguration]; + configuration.fileURL = fileURL; + return [RLMRealm realmWithConfiguration:configuration error:nil]; +} + +static dispatch_queue_t s_async_open_queue = dispatch_queue_create("io.realm.asyncOpenDispatchQueue", + DISPATCH_QUEUE_CONCURRENT); +void RLMSetAsyncOpenQueue(dispatch_queue_t queue) { + s_async_open_queue = queue; +} + ++ (RLMAsyncOpenTask *)asyncOpenWithConfiguration:(RLMRealmConfiguration *)configuration + callbackQueue:(dispatch_queue_t)callbackQueue + callback:(RLMAsyncOpenRealmCallback)callback { + auto openCompletion = [=](ThreadSafeReference, std::exception_ptr err) { + @autoreleasepool { + if (err) { + try { + std::rethrow_exception(err); + } + catch (...) { + NSError *error; + RLMRealmTranslateException(&error); + dispatch_async(callbackQueue, ^{ + callback(nil, error); + }); + } + return; + } + + dispatch_async(callbackQueue, ^{ + @autoreleasepool { + NSError *error; + RLMRealm *localRealm = [RLMRealm realmWithConfiguration:configuration + queue:callbackQueue + error:&error]; + callback(localRealm, error); + } + }); + } + }; + + RLMAsyncOpenTask *ret = [RLMAsyncOpenTask new]; + dispatch_async(s_async_open_queue, ^{ + @autoreleasepool { + Realm::Config& config = configuration.config; + if (config.sync_config) { +#if REALM_ENABLE_SYNC + auto task = realm::Realm::get_synchronized_realm(config); + ret.task = task; + task->start(openCompletion); +#else + @throw RLMException(@"Realm was not built with sync enabled"); +#endif + } + else { + try { + openCompletion(realm::_impl::RealmCoordinator::get_coordinator(config)->get_unbound_realm(), nullptr); + } + catch (...) { + openCompletion({}, std::current_exception()); + } + } + } + }); + return ret; +} + +// ARC tries to eliminate calls to autorelease when the value is then immediately +// returned, but this results in significantly different semantics between debug +// and release builds for RLMRealm, so force it to always autorelease. +static id RLMAutorelease(__unsafe_unretained id value) { + // +1 __bridge_retained, -1 CFAutorelease + return value ? (__bridge id)CFAutorelease((__bridge_retained CFTypeRef)value) : nil; +} + ++ (instancetype)realmWithSharedRealm:(SharedRealm)sharedRealm schema:(RLMSchema *)schema { + RLMRealm *realm = [[RLMRealm alloc] initPrivate]; + realm->_realm = sharedRealm; + realm->_dynamic = YES; + realm->_schema = schema; + realm->_info = RLMSchemaInfo(realm); + return RLMAutorelease(realm); +} + +REALM_NOINLINE void RLMRealmTranslateException(NSError **error) { + try { + throw; + } + catch (RealmFileException const& ex) { + switch (ex.kind()) { + case RealmFileException::Kind::PermissionDenied: + RLMSetErrorOrThrow(RLMMakeError(RLMErrorFilePermissionDenied, ex), error); + break; + case RealmFileException::Kind::IncompatibleLockFile: { + NSString *err = @"Realm file is currently open in another process " + "which cannot share access with this process. All " + "processes sharing a single file must be the same " + "architecture. For sharing files between the Realm " + "Browser and an iOS simulator, this means that you " + "must use a 64-bit simulator."; + RLMSetErrorOrThrow(RLMMakeError(RLMErrorIncompatibleLockFile, + File::PermissionDenied(err.UTF8String, ex.path())), error); + break; + } + case RealmFileException::Kind::NotFound: + RLMSetErrorOrThrow(RLMMakeError(RLMErrorFileNotFound, ex), error); + break; + case RealmFileException::Kind::Exists: + RLMSetErrorOrThrow(RLMMakeError(RLMErrorFileExists, ex), error); + break; + case RealmFileException::Kind::BadHistoryError: { + NSString *err = @"Realm file's history format is incompatible with the " + "settings in the configuration object being used to open " + "the Realm. Note that Realms configured for sync cannot be " + "opened as non-synced Realms, and vice versa. Otherwise, the " + "file may be corrupt."; + RLMSetErrorOrThrow(RLMMakeError(RLMErrorFileAccess, + File::AccessError(err.UTF8String, ex.path())), error); + break; + } + case RealmFileException::Kind::AccessError: + RLMSetErrorOrThrow(RLMMakeError(RLMErrorFileAccess, ex), error); + break; + case RealmFileException::Kind::FormatUpgradeRequired: + RLMSetErrorOrThrow(RLMMakeError(RLMErrorFileFormatUpgradeRequired, ex), error); + break; + default: + RLMSetErrorOrThrow(RLMMakeError(RLMErrorFail, ex), error); + break; + } + } + catch (AddressSpaceExhausted const &ex) { + RLMSetErrorOrThrow(RLMMakeError(RLMErrorAddressSpaceExhausted, ex), error); + } + catch (SchemaMismatchException const& ex) { + RLMSetErrorOrThrow(RLMMakeError(RLMErrorSchemaMismatch, ex), error); + } + catch (std::system_error const& ex) { + RLMSetErrorOrThrow(RLMMakeError(ex), error); + } + catch (const std::exception &exp) { + RLMSetErrorOrThrow(RLMMakeError(RLMErrorFail, exp), error); + } +} + +REALM_NOINLINE static void translateSharedGroupOpenException(NSError **error) { + try { + throw; + } + catch (...) { + RLMRealmTranslateException(error); + } +} + + ++ (instancetype)realmWithConfiguration:(RLMRealmConfiguration *)configuration error:(NSError **)error { + return [self realmWithConfiguration:configuration queue:nil error:error]; +} + ++ (instancetype)realmWithConfiguration:(RLMRealmConfiguration *)configuration + queue:(dispatch_queue_t)queue + error:(NSError **)error { + bool dynamic = configuration.dynamic; + bool cache = configuration.cache; + bool readOnly = configuration.readOnly; + + // The main thread and main queue share a cache key of 1 so that they give + // the same instance. Other Realms are keyed on either the thread or the queue. + // Note that despite being a void* the cache key is not actually a pointer; + // this is just an artifact of NSMapTable's strange API. + void *cacheKey = reinterpret_cast(1); + if (queue) { + if (queue != dispatch_get_main_queue()) { + cacheKey = (__bridge void *)queue; + } + } + else { + if (!pthread_main_np()) { + cacheKey = pthread_self(); + } + } + + { + Realm::Config const& config = configuration.config; + + // try to reuse existing realm first + if (cache || dynamic) { + if (RLMRealm *realm = RLMGetThreadLocalCachedRealmForPath(config.path, cacheKey)) { + auto const& old_config = realm->_realm->config(); + if (old_config.immutable() != config.immutable() + || old_config.read_only_alternative() != config.read_only_alternative()) { + @throw RLMException(@"Realm at path '%s' already opened with different read permissions", config.path.c_str()); + } + if (old_config.in_memory != config.in_memory) { + @throw RLMException(@"Realm at path '%s' already opened with different inMemory settings", config.path.c_str()); + } + if (realm->_dynamic != dynamic) { + @throw RLMException(@"Realm at path '%s' already opened with different dynamic settings", config.path.c_str()); + } + if (old_config.encryption_key != config.encryption_key) { + @throw RLMException(@"Realm at path '%s' already opened with different encryption key", config.path.c_str()); + } + return RLMAutorelease(realm); + } + } + } + + configuration = [configuration copy]; + Realm::Config& config = configuration.config; + + RLMRealm *realm = [[self alloc] initPrivate]; + realm->_dynamic = dynamic; + + // protects the realm cache and accessors cache + static std::mutex& initLock = *new std::mutex(); + std::lock_guard lock(initLock); + + try { + if (queue) { + if (queue == dispatch_get_main_queue()) { + config.scheduler = realm::util::Scheduler::make_runloop(CFRunLoopGetMain()); + } + else { + config.scheduler = realm::util::Scheduler::make_dispatch((__bridge void *)queue); + } + if (!config.scheduler->is_on_thread()) { + throw RLMException(@"Realm opened from incorrect dispatch queue."); + } + } + else { + // If the source config was read from a Realm it may already have a + // scheduler, and we don't want to reuse it. + config.scheduler = nullptr; + } + realm->_realm = Realm::get_shared_realm(config); + } + catch (...) { + translateSharedGroupOpenException(error); + return nil; + } + + // if we have a cached realm on another thread we can skip a few steps and + // just grab its schema + @autoreleasepool { + // ensure that cachedRealm doesn't end up in this thread's autorelease pool + if (auto cachedRealm = RLMGetAnyCachedRealmForPath(config.path)) { + realm->_realm->set_schema_subset(cachedRealm->_realm->schema()); + realm->_schema = cachedRealm.schema; + realm->_info = cachedRealm->_info.clone(cachedRealm->_realm->schema(), realm); + } + } + + if (realm->_schema) { } + else if (dynamic) { + realm->_schema = [RLMSchema dynamicSchemaFromObjectStoreSchema:realm->_realm->schema()]; + realm->_info = RLMSchemaInfo(realm); + } + else { + // set/align schema or perform migration if needed + RLMSchema *schema = configuration.customSchema ?: RLMSchema.sharedSchema; + + Realm::MigrationFunction migrationFunction; + auto migrationBlock = configuration.migrationBlock; + if (migrationBlock && configuration.schemaVersion > 0) { + migrationFunction = [=](SharedRealm old_realm, SharedRealm realm, Schema& mutableSchema) { + RLMSchema *oldSchema = [RLMSchema dynamicSchemaFromObjectStoreSchema:old_realm->schema()]; + RLMRealm *oldRealm = [RLMRealm realmWithSharedRealm:old_realm schema:oldSchema]; + + // The destination RLMRealm can't just use the schema from the + // SharedRealm because it doesn't have information about whether or + // not a class was defined in Swift, which effects how new objects + // are created + RLMRealm *newRealm = [RLMRealm realmWithSharedRealm:realm schema:schema.copy]; + + [[[RLMMigration alloc] initWithRealm:newRealm oldRealm:oldRealm schema:mutableSchema] execute:migrationBlock]; + + oldRealm->_realm = nullptr; + newRealm->_realm = nullptr; + }; + } + + try { + realm->_realm->update_schema(schema.objectStoreCopy, config.schema_version, + std::move(migrationFunction)); + } + catch (...) { + RLMRealmTranslateException(error); + return nil; + } + + realm->_schema = schema; + realm->_info = RLMSchemaInfo(realm); + RLMRealmCreateAccessors(realm.schema); + + if (!readOnly) { + REALM_ASSERT(!realm->_realm->is_in_read_transaction()); + + if (s_set_skip_backup_attribute) { + RLMAddSkipBackupAttributeToItemAtPath(config.path + ".management"); + RLMAddSkipBackupAttributeToItemAtPath(config.path + ".lock"); + RLMAddSkipBackupAttributeToItemAtPath(config.path + ".note"); + } + } + } + + if (cache) { + RLMCacheRealm(config.path, cacheKey, realm); + } + + if (!readOnly) { + realm->_realm->m_binding_context = RLMCreateBindingContext(realm); + realm->_realm->m_binding_context->realm = realm->_realm; + } + + return RLMAutorelease(realm); +} + ++ (void)resetRealmState { + RLMClearRealmCache(); + realm::_impl::RealmCoordinator::clear_cache(); + [RLMRealmConfiguration resetRealmConfigurationState]; +} + +- (void)verifyNotificationsAreSupported:(bool)isCollection { + [self verifyThread]; + if (_realm->config().immutable()) { + @throw RLMException(@"Read-only Realms do not change and do not have change notifications."); + } + if (_realm->is_frozen()) { + @throw RLMException(@"Frozen Realms do not change and do not have change notifications."); + } + if (!_realm->can_deliver_notifications()) { + @throw RLMException(@"Can only add notification blocks from within runloops."); + } + if (isCollection && _realm->is_in_transaction()) { + @throw RLMException(@"Cannot register notification blocks from within write transactions."); + } +} + +- (RLMNotificationToken *)addNotificationBlock:(RLMNotificationBlock)block { + if (!block) { + @throw RLMException(@"The notification block should not be nil"); + } + [self verifyNotificationsAreSupported:false]; + + _realm->read_group(); + + if (!_notificationHandlers) { + _notificationHandlers = [NSHashTable hashTableWithOptions:NSPointerFunctionsWeakMemory]; + } + + RLMRealmNotificationToken *token = [[RLMRealmNotificationToken alloc] init]; + token.realm = self; + token.block = block; + [_notificationHandlers addObject:token]; + return token; +} + +- (void)sendNotifications:(RLMNotification)notification { + NSAssert(!_realm->config().immutable(), @"Read-only realms do not have notifications"); + if (_sendingNotifications) { + return; + } + NSUInteger count = _notificationHandlers.count; + if (count == 0) { + return; + } + + _sendingNotifications = true; + auto cleanup = realm::util::make_scope_exit([&]() noexcept { + _sendingNotifications = false; + }); + + // call this realm's notification blocks + if (count == 1) { + if (auto block = [_notificationHandlers.anyObject block]) { + block(notification, self); + } + } + else { + for (RLMRealmNotificationToken *token in _notificationHandlers.allObjects) { + if (auto block = token.block) { + block(notification, self); + } + } + } +} + +- (RLMRealmConfiguration *)configuration { + RLMRealmConfiguration *configuration = [[RLMRealmConfiguration alloc] init]; + configuration.config = _realm->config(); + configuration.dynamic = _dynamic; + configuration.customSchema = _schema; + return configuration; +} + +- (void)beginWriteTransaction { + [self beginWriteTransactionWithError:nil]; +} + +- (BOOL)beginWriteTransactionWithError:(NSError **)error { + try { + _realm->begin_transaction(); + return YES; + } + catch (...) { + RLMRealmTranslateException(error); + return NO; + } +} + +- (void)commitWriteTransaction { + [self commitWriteTransaction:nil]; +} + +- (BOOL)commitWriteTransaction:(NSError **)error { + return [self commitWriteTransactionWithoutNotifying:@[] error:error]; +} + +- (BOOL)commitWriteTransactionWithoutNotifying:(NSArray *)tokens error:(NSError **)error { + for (RLMNotificationToken *token in tokens) { + if (token.realm != self) { + @throw RLMException(@"Incorrect Realm: only notifications for the Realm being modified can be skipped."); + } + [token suppressNextNotification]; + } + + try { + _realm->commit_transaction(); + return YES; + } + catch (...) { + RLMRealmTranslateException(error); + return NO; + } +} + +- (void)transactionWithBlock:(__attribute__((noescape)) void(^)(void))block { + [self transactionWithBlock:block error:nil]; +} + +- (BOOL)transactionWithBlock:(__attribute__((noescape)) void(^)(void))block error:(NSError **)outError { + return [self transactionWithoutNotifying:@[] block:block error:outError]; +} + +- (void)transactionWithoutNotifying:(NSArray *)tokens block:(__attribute__((noescape)) void(^)(void))block { + [self transactionWithoutNotifying:tokens block:block error:nil]; +} + +- (BOOL)transactionWithoutNotifying:(NSArray *)tokens block:(__attribute__((noescape)) void(^)(void))block error:(NSError **)error { + [self beginWriteTransactionWithError:error]; + block(); + if (_realm->is_in_transaction()) { + return [self commitWriteTransactionWithoutNotifying:tokens error:error]; + } + return YES; +} + +- (void)cancelWriteTransaction { + try { + _realm->cancel_transaction(); + } + catch (std::exception &ex) { + @throw RLMException(ex); + } +} + +- (void)invalidate { + if (_realm->is_in_transaction()) { + NSLog(@"WARNING: An RLMRealm instance was invalidated during a write " + "transaction and all pending changes have been rolled back."); + } + + [self detachAllEnumerators]; + + for (auto& objectInfo : _info) { + for (RLMObservationInfo *info : objectInfo.second.observedObjects) { + info->willChange(RLMInvalidatedKey); + } + } + + _realm->invalidate(); + + for (auto& objectInfo : _info) { + for (RLMObservationInfo *info : objectInfo.second.observedObjects) { + info->didChange(RLMInvalidatedKey); + } + } + + if (_realm->is_frozen()) { + _realm->close(); + } +} + +- (nullable id)resolveThreadSafeReference:(RLMThreadSafeReference *)reference { + return [reference resolveReferenceInRealm:self]; +} + +/** + Replaces all string columns in this Realm with a string enumeration column and compacts the + database file. + + Cannot be called from a write transaction. + + Compaction will not occur if other `RLMRealm` instances exist. + + While compaction is in progress, attempts by other threads or processes to open the database will + wait. + + Be warned that resource requirements for compaction is proportional to the amount of live data in + the database. + + Compaction works by writing the database contents to a temporary database file and then replacing + the database with the temporary one. The name of the temporary file is formed by appending + `.tmp_compaction_space` to the name of the database. + + @return YES if the compaction succeeded. + */ +- (BOOL)compact { + // compact() automatically ends the read transaction, but we need to clean + // up cached state and send invalidated notifications when that happens, so + // explicitly end it first unless we're in a write transaction (in which + // case compact() will throw an exception) + if (!_realm->is_in_transaction()) { + [self invalidate]; + } + + try { + return _realm->compact(); + } + catch (std::exception const& ex) { + @throw RLMException(ex); + } +} + +- (void)dealloc { + if (_realm) { + if (_realm->is_in_transaction()) { + [self cancelWriteTransaction]; + NSLog(@"WARNING: An RLMRealm instance was deallocated during a write transaction and all " + "pending changes have been rolled back. Make sure to retain a reference to the " + "RLMRealm for the duration of the write transaction."); + } + } +} + +- (BOOL)refresh { + try { + return _realm->refresh(); + } + catch (std::exception const& e) { + @throw RLMException(e); + } +} + +- (void)addObject:(__unsafe_unretained RLMObject *const)object { + RLMAddObjectToRealm(object, self, RLMUpdatePolicyError); +} + +- (void)addObjects:(id)objects { + for (RLMObject *obj in objects) { + if (![obj isKindOfClass:RLMObjectBase.class]) { + @throw RLMException(@"Cannot insert objects of type %@ with addObjects:. Only RLMObjects are supported.", + NSStringFromClass(obj.class)); + } + [self addObject:obj]; + } +} + +- (void)addOrUpdateObject:(RLMObject *)object { + // verify primary key + if (!object.objectSchema.primaryKeyProperty) { + @throw RLMException(@"'%@' does not have a primary key and can not be updated", object.objectSchema.className); + } + + RLMAddObjectToRealm(object, self, RLMUpdatePolicyUpdateAll); +} + +- (void)addOrUpdateObjects:(id)objects { + for (RLMObject *obj in objects) { + if (![obj isKindOfClass:RLMObjectBase.class]) { + @throw RLMException(@"Cannot add or update objects of type %@ with addOrUpdateObjects:. Only RLMObjects are" + " supported.", + NSStringFromClass(obj.class)); + } + [self addOrUpdateObject:obj]; + } +} + +- (void)deleteObject:(RLMObject *)object { + RLMDeleteObjectFromRealm(object, self); +} + +- (void)deleteObjects:(id)objects { + id idObjects = objects; + if ([idObjects respondsToSelector:@selector(realm)] + && [idObjects respondsToSelector:@selector(deleteObjectsFromRealm)]) { + if (self != (RLMRealm *)[idObjects realm]) { + @throw RLMException(@"Can only delete objects from the Realm they belong to."); + } + [idObjects deleteObjectsFromRealm]; + return; + } + if (auto array = RLMDynamicCast(objects)) { + if (array.type != RLMPropertyTypeObject) { + @throw RLMException(@"Cannot delete objects from RLMArray<%@>: only RLMObjects can be deleted.", + RLMTypeToString(array.type)); + } + } + for (RLMObject *obj in objects) { + if (![obj isKindOfClass:RLMObjectBase.class]) { + @throw RLMException(@"Cannot delete objects of type %@ with deleteObjects:. Only RLMObjects can be deleted.", + NSStringFromClass(obj.class)); + } + RLMDeleteObjectFromRealm(obj, self); + } +} + +- (void)deleteAllObjects { + RLMDeleteAllObjectsFromRealm(self); +} + +- (RLMResults *)allObjects:(NSString *)objectClassName { + return RLMGetObjects(self, objectClassName, nil); +} + +- (RLMResults *)objects:(NSString *)objectClassName where:(NSString *)predicateFormat, ... { + va_list args; + va_start(args, predicateFormat); + RLMResults *results = [self objects:objectClassName where:predicateFormat args:args]; + va_end(args); + return results; +} + +- (RLMResults *)objects:(NSString *)objectClassName where:(NSString *)predicateFormat args:(va_list)args { + return [self objects:objectClassName withPredicate:[NSPredicate predicateWithFormat:predicateFormat arguments:args]]; +} + +- (RLMResults *)objects:(NSString *)objectClassName withPredicate:(NSPredicate *)predicate { + return RLMGetObjects(self, objectClassName, predicate); +} + +- (RLMObject *)objectWithClassName:(NSString *)className forPrimaryKey:(id)primaryKey { + return RLMGetObject(self, className, primaryKey); +} + ++ (uint64_t)schemaVersionAtURL:(NSURL *)fileURL encryptionKey:(NSData *)key error:(NSError **)error { + RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init]; + try { + config.fileURL = fileURL; + config.encryptionKey = RLMRealmValidatedEncryptionKey(key); + + uint64_t version = Realm::get_schema_version(config.config); + if (version == realm::ObjectStore::NotVersioned) { + RLMSetErrorOrThrow([NSError errorWithDomain:RLMErrorDomain code:RLMErrorFail userInfo:@{NSLocalizedDescriptionKey:@"Cannot open an uninitialized realm in read-only mode"}], error); + } + return version; + } + catch (...) { + translateSharedGroupOpenException(error); + return RLMNotVersioned; + } +} + ++ (BOOL)performMigrationForConfiguration:(RLMRealmConfiguration *)configuration error:(NSError **)error { + if (RLMGetAnyCachedRealmForPath(configuration.config.path)) { + @throw RLMException(@"Cannot migrate Realms that are already open."); + } + + NSError *localError; // Prevents autorelease + BOOL success; + @autoreleasepool { + success = [RLMRealm realmWithConfiguration:configuration error:&localError] != nil; + } + if (!success && error) { + *error = localError; // Must set outside pool otherwise will free anyway + } + return success; +} + +- (RLMObject *)createObject:(NSString *)className withValue:(id)value { + return (RLMObject *)RLMCreateObjectInRealmWithValue(self, className, value, RLMUpdatePolicyError); +} + +- (BOOL)writeCopyToURL:(NSURL *)fileURL encryptionKey:(NSData *)key error:(NSError **)error { + key = RLMRealmValidatedEncryptionKey(key); + NSString *path = fileURL.path; + + try { + _realm->write_copy(path.UTF8String, {static_cast(key.bytes), key.length}); + return YES; + } + catch (...) { + __autoreleasing NSError *dummyError; + if (!error) { + error = &dummyError; + } + RLMRealmTranslateException(error); + return NO; + } + + return NO; +} + ++ (BOOL)fileExistsForConfiguration:(RLMRealmConfiguration *)config { + return [NSFileManager.defaultManager fileExistsAtPath:config.pathOnDisk]; +} + ++ (BOOL)deleteFilesForConfiguration:(RLMRealmConfiguration *)config error:(NSError **)error { + auto& path = config.config.path; + bool anyDeleted = false; + NSError *localError; + bool didCall = DB::call_with_lock(path, [&](auto const& path) { + NSURL *url = [NSURL fileURLWithPath:@(path.c_str())]; + NSFileManager *fm = NSFileManager.defaultManager; + + anyDeleted = [fm removeItemAtURL:url error:&localError]; + if (localError && localError.code != NSFileNoSuchFileError) { + return; + } + + [fm removeItemAtURL:[url URLByAppendingPathExtension:@"management"] error:&localError]; + if (localError && localError.code != NSFileNoSuchFileError) { + return; + } + + [fm removeItemAtURL:[url URLByAppendingPathExtension:@"note"] error:&localError]; + }); + if (error && localError && localError.code != NSFileNoSuchFileError) { + *error = localError; + } + else if (!didCall) { + if (error) { + NSString *msg = [NSString stringWithFormat:@"Realm file at path %s cannot be deleted because it is currently opened.", path.c_str()]; + *error = [NSError errorWithDomain:RLMErrorDomain + code:RLMErrorAlreadyOpen + userInfo:@{NSLocalizedDescriptionKey: msg}]; + } + } + return anyDeleted; +} + +- (BOOL)isFrozen { + return _realm->is_frozen(); +} + +- (RLMRealm *)freeze { + [self verifyThread]; + return self.isFrozen ? self : RLMGetFrozenRealmForSourceRealm(self); +} + +- (RLMRealm *)frozenCopy { + try { + RLMRealm *realm = [[RLMRealm alloc] initPrivate]; + realm->_realm = _realm->freeze(); + realm->_realm->set_schema_subset(_realm->schema()); + realm->_realm->read_group(); + realm->_dynamic = _dynamic; + realm->_schema = _schema; + realm->_info = RLMSchemaInfo(realm); + return realm; + } + catch (std::exception const& e) { + @throw RLMException(e); + } +} + +- (void)registerEnumerator:(RLMFastEnumerator *)enumerator { + if (!_collectionEnumerators) { + _collectionEnumerators = [NSHashTable hashTableWithOptions:NSPointerFunctionsWeakMemory]; + } + [_collectionEnumerators addObject:enumerator]; +} + +- (void)unregisterEnumerator:(RLMFastEnumerator *)enumerator { + [_collectionEnumerators removeObject:enumerator]; +} + +- (void)detachAllEnumerators { + for (RLMFastEnumerator *enumerator in _collectionEnumerators) { + [enumerator detach]; + } + _collectionEnumerators = nil; +} + +@end diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMRealmConfiguration+Sync.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMRealmConfiguration+Sync.mm new file mode 100644 index 0000000..5351931 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMRealmConfiguration+Sync.mm @@ -0,0 +1,78 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// 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 "RLMRealmConfiguration+Sync.h" +#import "RLMApp.h" +#import "RLMBSON_Private.hpp" +#import "RLMRealmConfiguration_Private.hpp" +#import "RLMSyncConfiguration_Private.hpp" +#import "RLMUser_Private.hpp" +#import "RLMSyncManager_Private.hpp" +#import "RLMSyncUtil_Private.hpp" +#import "RLMUtil.hpp" + +#import "util/bson/bson.hpp" +#import "sync/sync_config.hpp" +#import "sync/sync_manager.hpp" + +@implementation RLMRealmConfiguration (Sync) + +#pragma mark - API + +- (void)setSyncConfiguration:(RLMSyncConfiguration *)syncConfiguration { + if (syncConfiguration == nil) { + self.config.sync_config = nullptr; + return; + } + if (self.config.should_compact_on_launch_function) { + @throw RLMException(@"Cannot set `syncConfiguration` when `shouldCompactOnLaunch` is set."); + } + RLMUser *user = syncConfiguration.user; + if (user.state == RLMUserStateRemoved) { + @throw RLMException(@"Cannot set a sync configuration which has an errored-out user."); + } + + NSAssert(user.identifier, @"Cannot call this method on a user that doesn't have an identifier."); + self.config.in_memory = false; + self.config.sync_config = std::make_shared([syncConfiguration rawConfiguration]); + self.config.schema_mode = realm::SchemaMode::Additive; + + if (syncConfiguration.customFileURL) { + self.config.path = syncConfiguration.customFileURL.path.UTF8String; + } else { + RLMConvertBsonToRLMBSON(realm::bson::parse(self.config.sync_config->partition_value)); + self.config.path = self.config.sync_config->user->sync_manager()->path_for_realm(*[user _syncUser], + [[user pathForPartitionValue:RLMConvertBsonToRLMBSON(realm::bson::parse(self.config.sync_config->partition_value))] UTF8String]); + } + + if (!self.config.encryption_key.empty()) { + auto& sync_encryption_key = self.config.sync_config->realm_encryption_key; + sync_encryption_key = std::array(); + std::copy_n(self.config.encryption_key.begin(), 64, sync_encryption_key->begin()); + } +} + +- (RLMSyncConfiguration *)syncConfiguration { + if (!self.config.sync_config) { + return nil; + } + realm::SyncConfig& sync_config = *self.config.sync_config; + return [[RLMSyncConfiguration alloc] initWithRawConfig:sync_config]; +} + +@end diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMRealmConfiguration.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMRealmConfiguration.mm new file mode 100644 index 0000000..ae02dfd --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMRealmConfiguration.mm @@ -0,0 +1,318 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// 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 "RLMRealmConfiguration_Private.h" + +#import "RLMObjectSchema_Private.hpp" +#import "RLMRealm_Private.h" +#import "RLMSchema_Private.hpp" +#import "RLMUtil.hpp" + +#import "schema.hpp" +#import "shared_realm.hpp" + +#if REALM_ENABLE_SYNC +#import "sync/sync_config.hpp" +#else +@class RLMSyncConfiguration; +#endif + +static NSString *const c_RLMRealmConfigurationProperties[] = { + @"fileURL", + @"inMemoryIdentifier", + @"encryptionKey", + @"readOnly", + @"schemaVersion", + @"migrationBlock", + @"deleteRealmIfMigrationNeeded", + @"shouldCompactOnLaunch", + @"dynamic", + @"customSchema", +}; + +static NSString *const c_defaultRealmFileName = @"default.realm"; +RLMRealmConfiguration *s_defaultConfiguration; + +NSString *RLMRealmPathForFileAndBundleIdentifier(NSString *fileName, NSString *bundleIdentifier) { + return [RLMDefaultDirectoryForBundleIdentifier(bundleIdentifier) + stringByAppendingPathComponent:fileName]; +} + +NSString *RLMRealmPathForFile(NSString *fileName) { + static NSString *directory = RLMDefaultDirectoryForBundleIdentifier(nil); + return [directory stringByAppendingPathComponent:fileName]; +} + +@implementation RLMRealmConfiguration { + realm::Realm::Config _config; +} + +- (realm::Realm::Config&)config { + return _config; +} + ++ (instancetype)defaultConfiguration { + return [[self rawDefaultConfiguration] copy]; +} + ++ (void)setDefaultConfiguration:(RLMRealmConfiguration *)configuration { + if (!configuration) { + @throw RLMException(@"Cannot set the default configuration to nil."); + } + @synchronized(c_defaultRealmFileName) { + s_defaultConfiguration = [configuration copy]; + } +} + ++ (RLMRealmConfiguration *)rawDefaultConfiguration { + RLMRealmConfiguration *configuration; + @synchronized(c_defaultRealmFileName) { + if (!s_defaultConfiguration) { + s_defaultConfiguration = [[RLMRealmConfiguration alloc] init]; + } + configuration = s_defaultConfiguration; + } + return configuration; +} + ++ (void)resetRealmConfigurationState { + @synchronized(c_defaultRealmFileName) { + s_defaultConfiguration = nil; + } +} + +- (instancetype)init { + self = [super init]; + if (self) { + static NSURL *defaultRealmURL = [NSURL fileURLWithPath:RLMRealmPathForFile(c_defaultRealmFileName)]; + self.fileURL = defaultRealmURL; + self.schemaVersion = 0; + self.cache = YES; + } + + return self; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + RLMRealmConfiguration *configuration = [[[self class] allocWithZone:zone] init]; + configuration->_config = _config; + configuration->_cache = _cache; + configuration->_dynamic = _dynamic; + configuration->_migrationBlock = _migrationBlock; + configuration->_shouldCompactOnLaunch = _shouldCompactOnLaunch; + configuration->_customSchema = _customSchema; + return configuration; +} + +- (NSString *)description { + NSMutableString *string = [NSMutableString stringWithFormat:@"%@ {\n", self.class]; + for (NSString *key : c_RLMRealmConfigurationProperties) { + NSString *description = [[self valueForKey:key] description]; + description = [description stringByReplacingOccurrencesOfString:@"\n" withString:@"\n\t"]; + + [string appendFormat:@"\t%@ = %@;\n", key, description]; + } + return [string stringByAppendingString:@"}"]; +} + +- (NSURL *)fileURL { + if (_config.in_memory) { + return nil; + } + return [NSURL fileURLWithPath:@(_config.path.c_str())]; +} + +- (void)setFileURL:(NSURL *)fileURL { + NSString *path = fileURL.path; + if (path.length == 0) { + @throw RLMException(@"Realm path must not be empty"); + } + + RLMNSStringToStdString(_config.path, path); + _config.in_memory = false; +} + +- (NSString *)inMemoryIdentifier { + if (!_config.in_memory) { + return nil; + } + return [@(_config.path.c_str()) lastPathComponent]; +} + +- (void)setInMemoryIdentifier:(NSString *)inMemoryIdentifier { + if (inMemoryIdentifier.length == 0) { + @throw RLMException(@"In-memory identifier must not be empty"); + } + _config.sync_config = nullptr; + + RLMNSStringToStdString(_config.path, [NSTemporaryDirectory() stringByAppendingPathComponent:inMemoryIdentifier]); + _config.in_memory = true; +} + +- (NSData *)encryptionKey { + return _config.encryption_key.empty() ? nil : [NSData dataWithBytes:_config.encryption_key.data() length:_config.encryption_key.size()]; +} + +- (void)setEncryptionKey:(NSData * __nullable)encryptionKey { + if (NSData *key = RLMRealmValidatedEncryptionKey(encryptionKey)) { + auto bytes = static_cast(key.bytes); + _config.encryption_key.assign(bytes, bytes + key.length); +#if REALM_ENABLE_SYNC + if (_config.sync_config) { + auto& sync_encryption_key = self.config.sync_config->realm_encryption_key; + sync_encryption_key = std::array(); + std::copy_n(_config.encryption_key.begin(), 64, sync_encryption_key->begin()); + } +#endif + } + else { + _config.encryption_key.clear(); +#if REALM_ENABLE_SYNC + if (_config.sync_config) + _config.sync_config->realm_encryption_key = realm::util::none; +#endif + } +} + +- (BOOL)readOnly { + return _config.immutable() || _config.read_only_alternative(); +} + +static bool isSync(realm::Realm::Config const& config) { +#if REALM_ENABLE_SYNC + return !!config.sync_config; +#endif + return false; +} + +- (void)setReadOnly:(BOOL)readOnly { + if (readOnly) { + if (self.deleteRealmIfMigrationNeeded) { + @throw RLMException(@"Cannot set `readOnly` when `deleteRealmIfMigrationNeeded` is set."); + } else if (self.shouldCompactOnLaunch) { + @throw RLMException(@"Cannot set `readOnly` when `shouldCompactOnLaunch` is set."); + } + _config.schema_mode = isSync(_config) ? realm::SchemaMode::ReadOnlyAlternative : realm::SchemaMode::Immutable; + } + else if (self.readOnly) { + _config.schema_mode = isSync(_config) ? realm::SchemaMode::Additive : realm::SchemaMode::Automatic; + } +} + +- (uint64_t)schemaVersion { + return _config.schema_version; +} + +- (void)setSchemaVersion:(uint64_t)schemaVersion { + if (schemaVersion == RLMNotVersioned) { + @throw RLMException(@"Cannot set schema version to %llu (RLMNotVersioned)", RLMNotVersioned); + } + _config.schema_version = schemaVersion; +} + +- (BOOL)deleteRealmIfMigrationNeeded { + return _config.schema_mode == realm::SchemaMode::ResetFile; +} + +- (void)setDeleteRealmIfMigrationNeeded:(BOOL)deleteRealmIfMigrationNeeded { + if (deleteRealmIfMigrationNeeded) { + if (self.readOnly) { + @throw RLMException(@"Cannot set `deleteRealmIfMigrationNeeded` when `readOnly` is set."); + } + _config.schema_mode = realm::SchemaMode::ResetFile; + } + else if (self.deleteRealmIfMigrationNeeded) { + _config.schema_mode = realm::SchemaMode::Automatic; + } +} + +- (NSArray *)objectClasses { + return [_customSchema.objectSchema valueForKeyPath:@"objectClass"]; +} + +- (void)setObjectClasses:(NSArray *)objectClasses { + self.customSchema = [RLMSchema schemaWithObjectClasses:objectClasses]; +} + +- (NSUInteger)maximumNumberOfActiveVersions { + if (_config.max_number_of_active_versions > std::numeric_limits::max()) { + return std::numeric_limits::max(); + } + return static_cast(_config.max_number_of_active_versions); +} + +- (void)setMaximumNumberOfActiveVersions:(NSUInteger)maximumNumberOfActiveVersions { + if (maximumNumberOfActiveVersions == 0) { + _config.max_number_of_active_versions = std::numeric_limits::max(); + } + else { + _config.max_number_of_active_versions = maximumNumberOfActiveVersions; + } +} + +- (void)setDynamic:(bool)dynamic { + _dynamic = dynamic; + self.cache = !dynamic; +} + +- (bool)disableFormatUpgrade { + return _config.disable_format_upgrade; +} + +- (void)setDisableFormatUpgrade:(bool)disableFormatUpgrade { + _config.disable_format_upgrade = disableFormatUpgrade; +} + +- (realm::SchemaMode)schemaMode { + return _config.schema_mode; +} + +- (void)setSchemaMode:(realm::SchemaMode)mode { + _config.schema_mode = mode; +} + +- (NSString *)pathOnDisk { + return @(_config.path.c_str()); +} + +- (void)setShouldCompactOnLaunch:(RLMShouldCompactOnLaunchBlock)shouldCompactOnLaunch { + if (shouldCompactOnLaunch) { + if (_config.immutable()) { + @throw RLMException(@"Cannot set `shouldCompactOnLaunch` when `readOnly` is set."); + } + _config.should_compact_on_launch_function = [=](size_t totalBytes, size_t usedBytes) { + return shouldCompactOnLaunch(totalBytes, usedBytes); + }; + } + else { + _config.should_compact_on_launch_function = nullptr; + } + _shouldCompactOnLaunch = shouldCompactOnLaunch; +} + +- (void)setCustomSchemaWithoutCopying:(RLMSchema *)schema { + _customSchema = schema; +} + +#if !REALM_ENABLE_SYNC +- (RLMSyncConfiguration *)syncConfiguration { + return nil; +} +#endif + +@end diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMRealmUtil.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMRealmUtil.mm new file mode 100644 index 0000000..5a7489c --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMRealmUtil.mm @@ -0,0 +1,156 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// 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 "RLMRealmUtil.hpp" + +#import "RLMObjectSchema_Private.hpp" +#import "RLMObservation.hpp" +#import "RLMRealm_Private.hpp" +#import "RLMUtil.hpp" + +#import +#import + +#import "binding_context.hpp" +#import "shared_realm.hpp" +#import "util/scheduler.hpp" + +#import +#import + +// Global realm state +static auto& s_realmCacheMutex = *new std::mutex(); +static auto& s_realmsPerPath = *new std::map(); +static auto& s_frozenRealms = *new std::map(); + +void RLMCacheRealm(std::string const& path, void *key, __unsafe_unretained RLMRealm *const realm) { + std::lock_guard lock(s_realmCacheMutex); + NSMapTable *realms = s_realmsPerPath[path]; + if (!realms) { + s_realmsPerPath[path] = realms = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsOpaquePersonality|NSPointerFunctionsOpaqueMemory + valueOptions:NSPointerFunctionsWeakMemory]; + } + [realms setObject:realm forKey:(__bridge id)key]; +} + +RLMRealm *RLMGetAnyCachedRealmForPath(std::string const& path) { + std::lock_guard lock(s_realmCacheMutex); + return [s_realmsPerPath[path] objectEnumerator].nextObject; +} + +RLMRealm *RLMGetThreadLocalCachedRealmForPath(std::string const& path, void *key) { + std::lock_guard lock(s_realmCacheMutex); + RLMRealm *realm = [s_realmsPerPath[path] objectForKey:(__bridge id)key]; + if (realm && !realm->_realm->scheduler()->is_on_thread()) { + // We can get here in two cases: if the user is trying to open a + // queue-bound Realm from the wrong queue, or if we have a stale cached + // Realm which is bound to a thread that no longer exists. In the first + // case we'll throw an error later on; in the second we'll just create + // a new RLMRealm and replace the cache entry with one bound to the + // thread that now exists. + realm = nil; + } + return realm; +} + +void RLMClearRealmCache() { + std::lock_guard lock(s_realmCacheMutex); + s_realmsPerPath.clear(); + s_frozenRealms.clear(); +} + +RLMRealm *RLMGetFrozenRealmForSourceRealm(__unsafe_unretained RLMRealm *const sourceRealm) { + std::lock_guard lock(s_realmCacheMutex); + auto& r = *sourceRealm->_realm; + auto& path = r.config().path; + NSMapTable *realms = s_realmsPerPath[path]; + if (!realms) { + s_realmsPerPath[path] = realms = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsIntegerPersonality|NSPointerFunctionsOpaqueMemory + valueOptions:NSPointerFunctionsWeakMemory]; + } + r.read_group(); + auto version = reinterpret_cast(r.read_transaction_version().version); + RLMRealm *realm = [realms objectForKey:(__bridge id)version]; + if (!realm) { + realm = [sourceRealm frozenCopy]; + [realms setObject:realm forKey:(__bridge id)version]; + } + return realm; +} + +namespace { +class RLMNotificationHelper : public realm::BindingContext { +public: + RLMNotificationHelper(RLMRealm *realm) : _realm(realm) { } + + void changes_available() override { + @autoreleasepool { + auto realm = _realm; + if (realm && !realm.autorefresh) { + [realm sendNotifications:RLMRealmRefreshRequiredNotification]; + } + } + } + + std::vector get_observed_rows() override { + @autoreleasepool { + if (auto realm = _realm) { + [realm detachAllEnumerators]; + return RLMGetObservedRows(realm->_info); + } + return {}; + } + } + + void will_change(std::vector const& observed, std::vector const& invalidated) override { + @autoreleasepool { + RLMWillChange(observed, invalidated); + } + } + + void did_change(std::vector const& observed, std::vector const& invalidated, bool version_changed) override { + try { + @autoreleasepool { + RLMDidChange(observed, invalidated); + if (version_changed) { + [_realm sendNotifications:RLMRealmDidChangeNotification]; + } + } + } + catch (...) { + // This can only be called during a write transaction if it was + // called due to the transaction beginning, so cancel it to ensure + // exceptions thrown here behave the same as exceptions thrown when + // actually beginning the write + if (_realm.inWriteTransaction) { + [_realm cancelWriteTransaction]; + } + throw; + } + } + +private: + // This is owned by the realm, so it needs to not retain the realm + __weak RLMRealm *const _realm; +}; +} // anonymous namespace + + +std::unique_ptr RLMCreateBindingContext(__unsafe_unretained RLMRealm *const realm) { + return std::unique_ptr(new RLMNotificationHelper(realm)); +} diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMResults.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMResults.mm new file mode 100644 index 0000000..4dc094c --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMResults.mm @@ -0,0 +1,559 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// 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 "RLMResults_Private.hpp" + +#import "RLMAccessor.hpp" +#import "RLMArray_Private.hpp" +#import "RLMCollection_Private.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObjectStore.h" +#import "RLMObject_Private.hpp" +#import "RLMObservation.hpp" +#import "RLMProperty_Private.h" +#import "RLMQueryUtil.hpp" +#import "RLMRealm_Private.hpp" +#import "RLMSchema_Private.h" +#import "RLMThreadSafeReference_Private.hpp" +#import "RLMUtil.hpp" + +#import "results.hpp" +#import "shared_realm.hpp" + +#import +#import + +using namespace realm; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wincomplete-implementation" +@implementation RLMNotificationToken +@end +#pragma clang diagnostic pop + +@interface RLMResults () +@end + +// +// RLMResults implementation +// +@implementation RLMResults { + RLMRealm *_realm; + RLMClassInfo *_info; +} + +- (instancetype)initPrivate { + self = [super init]; + return self; +} + +- (instancetype)initWithResults:(Results)results { + if (self = [super init]) { + _results = std::move(results); + } + return self; +} + +static void assertKeyPathIsNotNested(NSString *keyPath) { + if ([keyPath rangeOfString:@"."].location != NSNotFound) { + @throw RLMException(@"Nested key paths are not supported yet for KVC collection operators."); + } +} + +void RLMThrowResultsError(NSString *aggregateMethod) { + try { + throw; + } + catch (realm::InvalidTransactionException const&) { + @throw RLMException(@"Cannot modify Results outside of a write transaction."); + } + catch (realm::IncorrectThreadException const&) { + @throw RLMException(@"Realm accessed from incorrect thread."); + } + catch (realm::Results::InvalidatedException const&) { + @throw RLMException(@"RLMResults has been invalidated."); + } + catch (realm::Results::DetatchedAccessorException const&) { + @throw RLMException(@"Object has been invalidated."); + } + catch (realm::Results::IncorrectTableException const& e) { + @throw RLMException(@"Object of type '%s' does not match RLMResults type '%s'.", + e.actual.data(), e.expected.data()); + } + catch (realm::Results::OutOfBoundsIndexException const& e) { + @throw RLMException(@"Index %zu is out of bounds (must be less than %zu).", + e.requested, e.valid_count); + } + catch (realm::Results::UnsupportedColumnTypeException const& e) { + @throw RLMException(@"%@ is not supported for %s%s property '%s'.", + aggregateMethod, + string_for_property_type(e.property_type), + is_nullable(e.property_type) ? "?" : "", + e.column_name.data()); + } + catch (std::exception const& e) { + @throw RLMException(e); + } +} + +- (instancetype)initWithObjectInfo:(RLMClassInfo&)info + results:(realm::Results&&)results { + if (self = [super init]) { + _results = std::move(results); + _realm = info.realm; + _info = &info; + } + return self; +} + ++ (instancetype)resultsWithObjectInfo:(RLMClassInfo&)info + results:(realm::Results&&)results { + return [[self alloc] initWithObjectInfo:info results:std::move(results)]; +} + ++ (instancetype)emptyDetachedResults { + return [[self alloc] initPrivate]; +} + +- (instancetype)subresultsWithResults:(realm::Results)results { + return [self.class resultsWithObjectInfo:*_info results:std::move(results)]; +} + +static inline void RLMResultsValidateInWriteTransaction(__unsafe_unretained RLMResults *const ar) { + ar->_realm->_realm->verify_thread(); + ar->_realm->_realm->verify_in_write(); +} + +- (BOOL)isInvalidated { + return translateRLMResultsErrors([&] { return !_results.is_valid(); }); +} + +- (NSUInteger)count { + return translateRLMResultsErrors([&] { return _results.size(); }); +} + +- (RLMPropertyType)type { + return translateRLMResultsErrors([&] { + return static_cast(_results.get_type() & ~realm::PropertyType::Nullable); + }); +} + +- (BOOL)isOptional { + return translateRLMResultsErrors([&] { + return is_nullable(_results.get_type()); + }); +} + +- (NSString *)objectClassName { + return translateRLMResultsErrors([&] { + if (_info && _results.get_type() == realm::PropertyType::Object) { + return _info->rlmObjectSchema.className; + } + return (NSString *)nil; + }); +} + +- (RLMClassInfo *)objectInfo { + return _info; +} + +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state + objects:(__unused __unsafe_unretained id [])buffer + count:(NSUInteger)len { + if (!_info) { + return 0; + } + if (state->state == 0) { + translateRLMResultsErrors([&] { + _results.evaluate_query_if_needed(); + }); + } + return RLMFastEnumerate(state, len, self); +} + +- (NSUInteger)indexOfObjectWhere:(NSString *)predicateFormat, ... { + va_list args; + va_start(args, predicateFormat); + NSUInteger index = [self indexOfObjectWhere:predicateFormat args:args]; + va_end(args); + return index; +} + +- (NSUInteger)indexOfObjectWhere:(NSString *)predicateFormat args:(va_list)args { + return [self indexOfObjectWithPredicate:[NSPredicate predicateWithFormat:predicateFormat + arguments:args]]; +} + +- (NSUInteger)indexOfObjectWithPredicate:(NSPredicate *)predicate { + if (_results.get_mode() == Results::Mode::Empty) { + return NSNotFound; + } + + return translateRLMResultsErrors([&] { + if (_results.get_type() != realm::PropertyType::Object) { + @throw RLMException(@"Querying is currently only implemented for arrays of Realm Objects"); + } + return RLMConvertNotFound(_results.index_of(RLMPredicateToQuery(predicate, _info->rlmObjectSchema, _realm.schema, _realm.group))); + }); +} + +- (id)objectAtIndex:(NSUInteger)index { + RLMAccessorContext ctx(*_info); + return translateRLMResultsErrors([&] { + return _results.get(ctx, index); + }); +} + +- (id)firstObject { + if (!_info) { + return nil; + } + RLMAccessorContext ctx(*_info); + return translateRLMResultsErrors([&] { + return _results.first(ctx); + }); +} + +- (id)lastObject { + if (!_info) { + return nil; + } + RLMAccessorContext ctx(*_info); + return translateRLMResultsErrors([&] { + return _results.last(ctx); + }); +} + +- (NSUInteger)indexOfObject:(id)object { + if (!_info || !object) { + return NSNotFound; + } + if (RLMObjectBase *obj = RLMDynamicCast(object)) { + // Unmanaged objects are considered not equal to all managed objects + if (!obj->_realm && !obj.invalidated) { + return NSNotFound; + } + } + RLMAccessorContext ctx(*_info); + return translateRLMResultsErrors([&] { + return RLMConvertNotFound(_results.index_of(ctx, object)); + }); +} + +- (id)valueForKeyPath:(NSString *)keyPath { + if ([keyPath characterAtIndex:0] != '@') { + return [super valueForKeyPath:keyPath]; + } + if ([keyPath isEqualToString:@"@count"]) { + return @(self.count); + } + + NSRange operatorRange = [keyPath rangeOfString:@"." options:NSLiteralSearch]; + NSUInteger keyPathLength = keyPath.length; + NSUInteger separatorIndex = operatorRange.location != NSNotFound ? operatorRange.location : keyPathLength; + NSString *operatorName = [keyPath substringWithRange:NSMakeRange(1, separatorIndex - 1)]; + SEL opSelector = NSSelectorFromString([NSString stringWithFormat:@"_%@ForKeyPath:", operatorName]); + if (![self respondsToSelector:opSelector]) { + @throw RLMException(@"Unsupported KVC collection operator found in key path '%@'", keyPath); + } + if (separatorIndex >= keyPathLength - 1) { + @throw RLMException(@"Missing key path for KVC collection operator %@ in key path '%@'", + operatorName, keyPath); + } + NSString *operatorKeyPath = [keyPath substringFromIndex:separatorIndex + 1]; + return ((id(*)(id, SEL, id))objc_msgSend)(self, opSelector, operatorKeyPath); +} + +- (id)valueForKey:(NSString *)key { + if (!_info) { + return @[]; + } + return translateRLMResultsErrors([&] { + return RLMCollectionValueForKey(_results, key, *_info); + }); +} + +- (void)setValue:(id)value forKey:(NSString *)key { + translateRLMResultsErrors([&] { RLMResultsValidateInWriteTransaction(self); }); + RLMCollectionSetValueForKey(self, key, value); +} + +- (NSNumber *)_aggregateForKeyPath:(NSString *)keyPath + method:(util::Optional (Results::*)(ColKey))method + methodName:(NSString *)methodName returnNilForEmpty:(BOOL)returnNilForEmpty { + assertKeyPathIsNotNested(keyPath); + return [self aggregate:keyPath method:method methodName:methodName returnNilForEmpty:returnNilForEmpty]; +} + +- (NSNumber *)_minForKeyPath:(NSString *)keyPath { + return [self _aggregateForKeyPath:keyPath method:&Results::min methodName:@"@min" returnNilForEmpty:YES]; +} + +- (NSNumber *)_maxForKeyPath:(NSString *)keyPath { + return [self _aggregateForKeyPath:keyPath method:&Results::max methodName:@"@max" returnNilForEmpty:YES]; +} + +- (NSNumber *)_sumForKeyPath:(NSString *)keyPath { + return [self _aggregateForKeyPath:keyPath method:&Results::sum methodName:@"@sum" returnNilForEmpty:NO]; +} + +- (NSNumber *)_avgForKeyPath:(NSString *)keyPath { + assertKeyPathIsNotNested(keyPath); + return [self averageOfProperty:keyPath]; +} + +- (NSArray *)_unionOfObjectsForKeyPath:(NSString *)keyPath { + assertKeyPathIsNotNested(keyPath); + return translateRLMResultsErrors([&] { + return RLMCollectionValueForKey(_results, keyPath, *_info); + }); +} + +- (NSArray *)_distinctUnionOfObjectsForKeyPath:(NSString *)keyPath { + return [NSSet setWithArray:[self _unionOfObjectsForKeyPath:keyPath]].allObjects; +} + +- (NSArray *)_unionOfArraysForKeyPath:(NSString *)keyPath { + assertKeyPathIsNotNested(keyPath); + if ([keyPath isEqualToString:@"self"]) { + @throw RLMException(@"self is not a valid key-path for a KVC array collection operator as 'unionOfArrays'."); + } + + return translateRLMResultsErrors([&] { + NSMutableArray *flatArray = [NSMutableArray new]; + for (id array in RLMCollectionValueForKey(_results, keyPath, *_info)) { + for (id value in array) { + [flatArray addObject:value]; + } + } + return flatArray; + }); +} + +- (NSArray *)_distinctUnionOfArraysForKeyPath:(__unused NSString *)keyPath { + return [NSSet setWithArray:[self _unionOfArraysForKeyPath:keyPath]].allObjects; +} + +- (RLMResults *)objectsWhere:(NSString *)predicateFormat, ... { + va_list args; + va_start(args, predicateFormat); + RLMResults *results = [self objectsWhere:predicateFormat args:args]; + va_end(args); + return results; +} + +- (RLMResults *)objectsWhere:(NSString *)predicateFormat args:(va_list)args { + return [self objectsWithPredicate:[NSPredicate predicateWithFormat:predicateFormat arguments:args]]; +} + +- (RLMResults *)objectsWithPredicate:(NSPredicate *)predicate { + return translateRLMResultsErrors([&] { + if (_results.get_mode() == Results::Mode::Empty) { + return self; + } + if (_results.get_type() != realm::PropertyType::Object) { + @throw RLMException(@"Querying is currently only implemented for arrays of Realm Objects"); + } + auto query = RLMPredicateToQuery(predicate, _info->rlmObjectSchema, _realm.schema, _realm.group); + return [self subresultsWithResults:_results.filter(std::move(query))]; + }); +} + +- (RLMResults *)sortedResultsUsingKeyPath:(NSString *)keyPath ascending:(BOOL)ascending { + return [self sortedResultsUsingDescriptors:@[[RLMSortDescriptor sortDescriptorWithKeyPath:keyPath ascending:ascending]]]; +} + +- (RLMResults *)sortedResultsUsingDescriptors:(NSArray *)properties { + if (properties.count == 0) { + return self; + } + return translateRLMResultsErrors([&] { + if (_results.get_mode() == Results::Mode::Empty) { + return self; + } + return [self subresultsWithResults:_results.sort(RLMSortDescriptorsToKeypathArray(properties))]; + }); +} + +- (RLMResults *)distinctResultsUsingKeyPaths:(NSArray *)keyPaths { + for (NSString *keyPath in keyPaths) { + if ([keyPath rangeOfString:@"@"].location != NSNotFound) { + @throw RLMException(@"Cannot distinct on keypath '%@': KVC collection operators are not supported.", keyPath); + } + } + + return translateRLMResultsErrors([&] { + if (_results.get_mode() == Results::Mode::Empty) { + return self; + } + + std::vector keyPathsVector; + for (NSString *keyPath in keyPaths) { + keyPathsVector.push_back(keyPath.UTF8String); + } + + return [self subresultsWithResults:_results.distinct(keyPathsVector)]; + }); +} + +- (id)objectAtIndexedSubscript:(NSUInteger)index { + return [self objectAtIndex:index]; +} + +- (id)aggregate:(NSString *)property method:(util::Optional (Results::*)(ColKey))method + methodName:(NSString *)methodName returnNilForEmpty:(BOOL)returnNilForEmpty { + if (_results.get_mode() == Results::Mode::Empty) { + return returnNilForEmpty ? nil : @0; + } + ColKey column; + if (self.type == RLMPropertyTypeObject || ![property isEqualToString:@"self"]) { + column = _info->tableColumn(property); + } + + auto value = translateRLMResultsErrors([&] { return (_results.*method)(column); }, methodName); + return value ? RLMMixedToObjc(*value) : nil; +} + +- (id)minOfProperty:(NSString *)property { + return [self aggregate:property method:&Results::min + methodName:@"minOfProperty" returnNilForEmpty:YES]; +} + +- (id)maxOfProperty:(NSString *)property { + return [self aggregate:property method:&Results::max + methodName:@"maxOfProperty" returnNilForEmpty:YES]; +} + +- (id)sumOfProperty:(NSString *)property { + return [self aggregate:property method:&Results::sum + methodName:@"sumOfProperty" returnNilForEmpty:NO]; +} + +- (id)averageOfProperty:(NSString *)property { + if (_results.get_mode() == Results::Mode::Empty) { + return nil; + } + ColKey column; + if (self.type == RLMPropertyTypeObject || ![property isEqualToString:@"self"]) { + column = _info->tableColumn(property); + } + auto value = translateRLMResultsErrors([&] { return _results.average(column); }, @"averageOfProperty"); + return value ? RLMMixedToObjc(*value) : nil; +} + +- (void)deleteObjectsFromRealm { + if (self.type != RLMPropertyTypeObject) { + @throw RLMException(@"Cannot delete objects from RLMResults<%@>: only RLMObjects can be deleted.", + RLMTypeToString(self.type)); + } + return translateRLMResultsErrors([&] { + if (_results.get_mode() == Results::Mode::Table) { + RLMResultsValidateInWriteTransaction(self); + RLMClearTable(*_info); + } + else { + RLMObservationTracker tracker(_realm, true); + _results.clear(); + } + }); +} + +- (NSString *)description { + return RLMDescriptionWithMaxDepth(@"RLMResults", self, RLMDescriptionMaxDepth); +} + +- (realm::TableView)tableView { + return translateRLMResultsErrors([&] { return _results.get_tableview(); }); +} + +- (RLMFastEnumerator *)fastEnumerator { + return translateRLMResultsErrors([&] { + return [[RLMFastEnumerator alloc] initWithResults:_results collection:self + classInfo:*_info]; + }); +} + +- (RLMResults *)snapshot { + return translateRLMResultsErrors([&] { + return [self subresultsWithResults:_results.snapshot()]; + }); +} + +- (instancetype)freeze { + if (self.frozen) { + return self; + } + + RLMRealm *frozenRealm = [_realm freeze]; + return translateRLMResultsErrors([&] { + return [self.class resultsWithObjectInfo:_info->freeze(frozenRealm) + results:_results.freeze(frozenRealm->_realm)]; + }); +} + +- (BOOL)isFrozen { + return _realm.frozen; +} + +// The compiler complains about the method's argument type not matching due to +// it not having the generic type attached, but it doesn't seem to be possible +// to actually include the generic type +// http://www.openradar.me/radar?id=6135653276319744 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wmismatched-parameter-types" +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMResults *, RLMCollectionChange *, NSError *))block { + return RLMAddNotificationBlock(self, block, nil); +} +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMResults *, RLMCollectionChange *, NSError *))block queue:(dispatch_queue_t)queue { + return RLMAddNotificationBlock(self, block, queue); +} +#pragma clang diagnostic pop + +realm::Results& RLMGetBackingCollection(RLMResults *self) { + return self->_results; +} + +- (BOOL)isAttached { + return !!_realm; +} + +#pragma mark - Thread Confined Protocol Conformance + +- (realm::ThreadSafeReference)makeThreadSafeReference { + return _results; +} + +- (id)objectiveCMetadata { + return nil; +} + ++ (instancetype)objectWithThreadSafeReference:(realm::ThreadSafeReference)reference + metadata:(__unused id)metadata + realm:(RLMRealm *)realm { + auto results = reference.resolve(realm->_realm); + return [RLMResults resultsWithObjectInfo:realm->_info[RLMStringDataToNSString(results.get_object_type())] + results:std::move(results)]; +} + +@end + +@implementation RLMLinkingObjects +- (NSString *)description { + return RLMDescriptionWithMaxDepth(@"RLMLinkingObjects", self, RLMDescriptionMaxDepth); +} +@end diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMSchema.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMSchema.mm new file mode 100644 index 0000000..0787125 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMSchema.mm @@ -0,0 +1,378 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// 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 "RLMSchema_Private.h" + +#import "RLMAccessor.h" +#import "RLMObjectBase_Private.h" +#import "RLMObject_Private.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMProperty_Private.h" +#import "RLMRealm_Private.hpp" +#import "RLMSwiftSupport.h" +#import "RLMUtil.hpp" + +#import "object_schema.hpp" +#import "object_store.hpp" +#import "schema.hpp" + +#import + +#import +#include + +using namespace realm; + +const uint64_t RLMNotVersioned = realm::ObjectStore::NotVersioned; + +// RLMSchema private properties +@interface RLMSchema () +@property (nonatomic, readwrite) NSMutableDictionary *objectSchemaByName; +@end + +// Private RLMSchema subclass that skips class registration on lookup +@interface RLMPrivateSchema : RLMSchema +@end +@implementation RLMPrivateSchema +- (RLMObjectSchema *)schemaForClassName:(NSString *)className { + return self.objectSchemaByName[className]; +} + +- (RLMObjectSchema *)objectForKeyedSubscript:(__unsafe_unretained NSString *const)className { + return [self schemaForClassName:className]; +} +@end + +static RLMSchema *s_sharedSchema = [[RLMSchema alloc] init]; +static NSMutableDictionary *s_localNameToClass = [[NSMutableDictionary alloc] init]; +static RLMSchema *s_privateSharedSchema = [[RLMPrivateSchema alloc] init]; + +static enum class SharedSchemaState { + Uninitialized, + Initializing, + Initialized +} s_sharedSchemaState = SharedSchemaState::Uninitialized; + +@implementation RLMSchema { + NSArray *_objectSchema; + realm::Schema _objectStoreSchema; +} + +// Caller must @synchronize on s_localNameToClass +static RLMObjectSchema *RLMRegisterClass(Class cls) { + if (RLMObjectSchema *schema = s_privateSharedSchema[[cls className]]) { + return schema; + } + + auto prevState = s_sharedSchemaState; + s_sharedSchemaState = SharedSchemaState::Initializing; + RLMObjectSchema *schema = [RLMObjectSchema schemaForObjectClass:cls]; + s_sharedSchemaState = prevState; + + // set unmanaged class on shared shema for unmanaged object creation + schema.unmanagedClass = RLMUnmanagedAccessorClassForObjectClass(schema.objectClass, schema); + + // override sharedSchema class methods for performance + RLMReplaceSharedSchemaMethod(cls, schema); + + s_privateSharedSchema.objectSchemaByName[schema.className] = schema; + if ([cls shouldIncludeInDefaultSchema] && prevState != SharedSchemaState::Initialized) { + s_sharedSchema.objectSchemaByName[schema.className] = schema; + } + + return schema; +} + +// Caller must @synchronize on s_localNameToClass +static void RLMRegisterClassLocalNames(Class *classes, NSUInteger count) { + for (NSUInteger i = 0; i < count; i++) { + Class cls = classes[i]; + if (!RLMIsObjectSubclass(cls)) { + continue; + } + if ([cls _realmIgnoreClass]) { + continue; + } + + NSString *className = NSStringFromClass(cls); + if ([className hasPrefix:@"RLM:"] || [className hasPrefix:@"NSKVONotifying"]) { + continue; + } + + if ([RLMSwiftSupport isSwiftClassName:className]) { + className = [RLMSwiftSupport demangleClassName:className]; + } + // NSStringFromClass demangles the names for top-level Swift classes + // but not for nested classes. _T indicates it's a Swift symbol, t + // indicates it's a type, and C indicates it's a class. + else if ([className hasPrefix:@"_TtC"]) { + @throw RLMException(@"RLMObject subclasses cannot be nested within other declarations. Please move %@ to global scope.", className); + } + + if (Class existingClass = s_localNameToClass[className]) { + if (existingClass != cls) { + @throw RLMException(@"RLMObject subclasses with the same name cannot be included twice in the same target. " + @"Please make sure '%@' is only linked once to your current target.", className); + } + continue; + } + + s_localNameToClass[className] = cls; + RLMReplaceClassNameMethod(cls, className); + } +} + +- (instancetype)init { + self = [super init]; + if (self) { + _objectSchemaByName = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (NSArray *)objectSchema { + if (!_objectSchema) { + _objectSchema = [_objectSchemaByName allValues]; + } + return _objectSchema; +} + +- (void)setObjectSchema:(NSArray *)objectSchema { + _objectSchema = objectSchema; + _objectSchemaByName = [NSMutableDictionary dictionaryWithCapacity:objectSchema.count]; + for (RLMObjectSchema *object in objectSchema) { + [_objectSchemaByName setObject:object forKey:object.className]; + } +} + +- (RLMObjectSchema *)schemaForClassName:(NSString *)className { + if (RLMObjectSchema *schema = _objectSchemaByName[className]) { + return schema; // fast path for already-initialized schemas + } else if (Class cls = [RLMSchema classForString:className]) { + [cls sharedSchema]; // initialize the schema + return _objectSchemaByName[className]; // try again + } else { + return nil; + } +} + +- (RLMObjectSchema *)objectForKeyedSubscript:(__unsafe_unretained NSString *const)className { + RLMObjectSchema *schema = [self schemaForClassName:className]; + if (!schema) { + @throw RLMException(@"Object type '%@' not managed by the Realm", className); + } + return schema; +} + ++ (instancetype)schemaWithObjectClasses:(NSArray *)classes { + NSUInteger count = classes.count; + auto classArray = std::make_unique<__unsafe_unretained Class[]>(count); + [classes getObjects:classArray.get() range:NSMakeRange(0, count)]; + + RLMSchema *schema = [[self alloc] init]; + @synchronized(s_localNameToClass) { + RLMRegisterClassLocalNames(classArray.get(), count); + + schema->_objectSchemaByName = [NSMutableDictionary dictionaryWithCapacity:count]; + for (Class cls in classes) { + if (!RLMIsObjectSubclass(cls)) { + @throw RLMException(@"Can't add non-Object type '%@' to a schema.", cls); + } + schema->_objectSchemaByName[[cls className]] = RLMRegisterClass(cls); + } + } + + NSMutableArray *errors = [NSMutableArray new]; + // Verify that all of the targets of links are included in the class list + [schema->_objectSchemaByName enumerateKeysAndObjectsUsingBlock:^(id, RLMObjectSchema *objectSchema, BOOL *) { + for (RLMProperty *prop in objectSchema.properties) { + if (prop.type != RLMPropertyTypeObject) { + continue; + } + if (!schema->_objectSchemaByName[prop.objectClassName]) { + [errors addObject:[NSString stringWithFormat:@"- '%@.%@' links to class '%@', which is missing from the list of classes managed by the Realm", objectSchema.className, prop.name, prop.objectClassName]]; + } + } + }]; + if (errors.count) { + @throw RLMException(@"Invalid class subset list:\n%@", [errors componentsJoinedByString:@"\n"]); + } + + return schema; +} + ++ (RLMObjectSchema *)sharedSchemaForClass:(Class)cls { + @synchronized(s_localNameToClass) { + // We create instances of Swift objects during schema init, and they + // obviously need to not also try to initialize the schema + if (s_sharedSchemaState == SharedSchemaState::Initializing) { + return nil; + } + + RLMRegisterClassLocalNames(&cls, 1); + RLMObjectSchema *objectSchema = RLMRegisterClass(cls); + [cls initializeLinkedObjectSchemas]; + return objectSchema; + } +} + ++ (instancetype)partialSharedSchema { + return s_sharedSchema; +} + ++ (instancetype)partialPrivateSharedSchema { + return s_privateSharedSchema; +} + +// schema based on runtime objects ++ (instancetype)sharedSchema { + @synchronized(s_localNameToClass) { + // We replace this method with one which just returns s_sharedSchema + // once initialization is complete, but we still need to check if it's + // already complete because it may have been done by another thread + // while we were waiting for the lock + if (s_sharedSchemaState == SharedSchemaState::Initialized) { + return s_sharedSchema; + } + + if (s_sharedSchemaState == SharedSchemaState::Initializing) { + @throw RLMException(@"Illegal recursive call of +[%@ %@]. Note: Properties of Swift `Object` classes must not be prepopulated with queried results from a Realm.", self, NSStringFromSelector(_cmd)); + } + + s_sharedSchemaState = SharedSchemaState::Initializing; + try { + // Make sure we've discovered all classes + { + unsigned int numClasses; + using malloc_ptr = std::unique_ptr<__unsafe_unretained Class[], decltype(&free)>; + malloc_ptr classes(objc_copyClassList(&numClasses), &free); + RLMRegisterClassLocalNames(classes.get(), numClasses); + } + + [s_localNameToClass enumerateKeysAndObjectsUsingBlock:^(NSString *, Class cls, BOOL *) { + RLMRegisterClass(cls); + }]; + } + catch (...) { + s_sharedSchemaState = SharedSchemaState::Uninitialized; + throw; + } + + // Replace this method with one that doesn't need to acquire a lock + Class metaClass = objc_getMetaClass(class_getName(self)); + IMP imp = imp_implementationWithBlock(^{ return s_sharedSchema; }); + class_replaceMethod(metaClass, @selector(sharedSchema), imp, "@@:"); + + s_sharedSchemaState = SharedSchemaState::Initialized; + } + + return s_sharedSchema; +} + +// schema based on tables in a realm ++ (instancetype)dynamicSchemaFromObjectStoreSchema:(Schema const&)objectStoreSchema { + // cache descriptors for all subclasses of RLMObject + NSMutableArray *schemaArray = [NSMutableArray arrayWithCapacity:objectStoreSchema.size()]; + for (auto &objectSchema : objectStoreSchema) { + RLMObjectSchema *schema = [RLMObjectSchema objectSchemaForObjectStoreSchema:objectSchema]; + [schemaArray addObject:schema]; + } + + // set class array and mapping + RLMSchema *schema = [RLMSchema new]; + schema.objectSchema = schemaArray; + return schema; +} + ++ (Class)classForString:(NSString *)className { + if (Class cls = s_localNameToClass[className]) { + return cls; + } + + if (Class cls = NSClassFromString(className)) { + return RLMIsObjectSubclass(cls) ? cls : nil; + } + + // className might be the local name of a Swift class we haven't registered + // yet, so scan them all then recheck + { + unsigned int numClasses; + std::unique_ptr<__unsafe_unretained Class[], decltype(&free)> classes(objc_copyClassList(&numClasses), &free); + RLMRegisterClassLocalNames(classes.get(), numClasses); + } + + return s_localNameToClass[className]; +} + +- (id)copyWithZone:(NSZone *)zone { + RLMSchema *schema = [[RLMSchema allocWithZone:zone] init]; + schema->_objectSchemaByName = [[NSMutableDictionary allocWithZone:zone] + initWithDictionary:_objectSchemaByName copyItems:YES]; + return schema; +} + +- (BOOL)isEqualToSchema:(RLMSchema *)schema { + if (_objectSchemaByName.count != schema->_objectSchemaByName.count) { + return NO; + } + __block BOOL matches = YES; + [_objectSchemaByName enumerateKeysAndObjectsUsingBlock:^(NSString *name, RLMObjectSchema *objectSchema, BOOL *stop) { + if (![schema->_objectSchemaByName[name] isEqualToObjectSchema:objectSchema]) { + *stop = YES; + matches = NO; + } + }]; + return matches; +} + +- (NSString *)description { + NSMutableString *objectSchemaString = [NSMutableString string]; + NSArray *sort = @[[NSSortDescriptor sortDescriptorWithKey:@"className" ascending:YES]]; + for (RLMObjectSchema *objectSchema in [self.objectSchema sortedArrayUsingDescriptors:sort]) { + [objectSchemaString appendFormat:@"\t%@\n", + [objectSchema.description stringByReplacingOccurrencesOfString:@"\n" withString:@"\n\t"]]; + } + return [NSString stringWithFormat:@"Schema {\n%@}", objectSchemaString]; +} + +- (Schema)objectStoreCopy { + if (_objectStoreSchema.size() == 0) { + std::vector schema; + schema.reserve(_objectSchemaByName.count); + [_objectSchemaByName enumerateKeysAndObjectsUsingBlock:[&](NSString *, RLMObjectSchema *objectSchema, BOOL *) { + schema.push_back([objectSchema objectStoreCopy:self]); + }]; + + // Having both obj-c and Swift classes for the same tables results in + // duplicate ObjectSchemas that we need to filter out + std::sort(begin(schema), end(schema), [](auto&& a, auto&& b) { return a.name < b.name; }); + schema.erase(std::unique(begin(schema), end(schema), [](auto&& a, auto&& b) { + if (a.name == b.name) { + // If we make _realmObjectName public this needs to be turned into an exception + REALM_ASSERT_DEBUG(a.persisted_properties == b.persisted_properties); + return true; + } + return false; + }), end(schema)); + + _objectStoreSchema = std::move(schema); + } + return _objectStoreSchema; +} + +@end diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMSwiftSupport.m b/Darner-dan-uh/Pods/Realm/Realm/RLMSwiftSupport.m new file mode 100644 index 0000000..e16c79e --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMSwiftSupport.m @@ -0,0 +1,31 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// 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 "RLMSwiftSupport.h" + +@implementation RLMSwiftSupport + ++ (BOOL)isSwiftClassName:(NSString *)className { + return [className rangeOfString:@"."].location != NSNotFound; +} + ++ (NSString *)demangleClassName:(NSString *)className { + return [className substringFromIndex:[className rangeOfString:@"."].location + 1]; +} + +@end diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMSyncConfiguration.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMSyncConfiguration.mm new file mode 100644 index 0000000..2edca00 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMSyncConfiguration.mm @@ -0,0 +1,217 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// 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 "RLMApp_Private.hpp" +#import "RLMRealmConfiguration+Sync.h" +#import "RLMSyncConfiguration_Private.hpp" +#import "RLMSyncManager_Private.hpp" +#import "RLMSyncSession_Private.hpp" +#import "RLMUser_Private.hpp" +#import "RLMSyncUtil_Private.hpp" +#import "RLMUtil.hpp" +#import "RLMBSON_Private.hpp" + +#import "sync/sync_manager.hpp" +#import "sync/sync_config.hpp" +#import "sync/sync_session.hpp" + +#import + +using namespace realm; + +namespace { +using ProtocolError = realm::sync::ProtocolError; + +RLMSyncSystemErrorKind errorKindForSyncError(SyncError error) { + if (error.is_client_reset_requested()) { + return RLMSyncSystemErrorKindClientReset; + } else if (error.error_code == ProtocolError::permission_denied) { + return RLMSyncSystemErrorKindPermissionDenied; + } else if (error.error_code == ProtocolError::bad_authentication) { + return RLMSyncSystemErrorKindUser; + } else if (error.is_session_level_protocol_error()) { + return RLMSyncSystemErrorKindSession; + } else if (error.is_connection_level_protocol_error()) { + return RLMSyncSystemErrorKindConnection; + } else if (error.is_client_error()) { + return RLMSyncSystemErrorKindClient; + } else { + return RLMSyncSystemErrorKindUnknown; + } +} +} + +@interface RLMSyncConfiguration () { + std::unique_ptr _config; +} + +@end + +@implementation RLMSyncConfiguration + +@dynamic stopPolicy; + +- (instancetype)initWithRawConfig:(realm::SyncConfig)config { + if (self = [super init]) { + _config = std::make_unique(std::move(config)); + } + return self; +} + +- (BOOL)isEqual:(id)object { + if (![object isKindOfClass:[RLMSyncConfiguration class]]) { + return NO; + } + RLMSyncConfiguration *that = (RLMSyncConfiguration *)object; + return [self.partitionValue isEqual:that.partitionValue] + && [self.user isEqual:that.user] + && self.stopPolicy == that.stopPolicy; +} + +- (realm::SyncConfig&)rawConfiguration { + return *_config; +} + +- (RLMUser *)user { + RLMApp *app = [RLMApp appWithId:@(_config->user->sync_manager()->app().lock()->config().app_id.data())]; + return [[RLMUser alloc] initWithUser:_config->user app:app]; +} + +- (RLMSyncStopPolicy)stopPolicy { + return translateStopPolicy(_config->stop_policy); +} + +- (void)setStopPolicy:(RLMSyncStopPolicy)stopPolicy { + _config->stop_policy = translateStopPolicy(stopPolicy); +} + +- (id)partitionValue { + if (!_config->partition_value.empty()) { + return RLMConvertBsonToRLMBSON(realm::bson::parse(_config->partition_value.c_str())); + } + return nil; +} + +- (bool)cancelAsyncOpenOnNonFatalErrors { + return _config->cancel_waits_on_nonfatal_error; +} + +- (void)setCancelAsyncOpenOnNonFatalErrors:(bool)cancelAsyncOpenOnNonFatalErrors { + _config->cancel_waits_on_nonfatal_error = cancelAsyncOpenOnNonFatalErrors; +} + +- (instancetype)initWithUser:(RLMUser *)user + partitionValue:(nullable id)partitionValue { + return [self initWithUser:user + partitionValue:partitionValue + customFileURL:nil + stopPolicy:RLMSyncStopPolicyAfterChangesUploaded]; +} + +- (instancetype)initWithUser:(RLMUser *)user + partitionValue:(nullable id)partitionValue + stopPolicy:(RLMSyncStopPolicy)stopPolicy{ + auto config = [self initWithUser:user + partitionValue:partitionValue + customFileURL:nil + stopPolicy:stopPolicy]; + return config; +} + +- (instancetype)initWithUser:(RLMUser *)user + partitionValue:(id)partitionValue + customFileURL:(nullable NSURL *)customFileURL + stopPolicy:(RLMSyncStopPolicy)stopPolicy { + if (self = [super init]) { + std::stringstream s; + s << RLMConvertRLMBSONToBson(partitionValue); + _config = std::make_unique( + [user _syncUser], + s.str() + ); + _config->stop_policy = translateStopPolicy(stopPolicy); + RLMApp *app = user.app; + _config->error_handler = [app](std::shared_ptr errored_session, SyncError error) { + NSString *recoveryPath; + RLMSyncErrorActionToken *token; + for (auto& pair : error.user_info) { + if (pair.first == realm::SyncError::c_original_file_path_key) { + token = [[RLMSyncErrorActionToken alloc] initWithOriginalPath:pair.second]; + } + else if (pair.first == realm::SyncError::c_recovery_file_path_key) { + recoveryPath = @(pair.second.c_str()); + } + } + + BOOL shouldMakeError = YES; + NSDictionary *custom = nil; + // Note that certain types of errors are 'interactive'; users have several options + // as to how to proceed after the error is reported. + auto errorClass = errorKindForSyncError(error); + switch (errorClass) { + case RLMSyncSystemErrorKindClientReset: { + custom = @{kRLMSyncPathOfRealmBackupCopyKey: recoveryPath, kRLMSyncErrorActionTokenKey: token}; + break; + } + case RLMSyncSystemErrorKindPermissionDenied: { + custom = @{kRLMSyncErrorActionTokenKey: token}; + break; + } + case RLMSyncSystemErrorKindUser: + case RLMSyncSystemErrorKindSession: + break; + case RLMSyncSystemErrorKindConnection: + case RLMSyncSystemErrorKindClient: + case RLMSyncSystemErrorKindUnknown: + // Report the error. There's nothing the user can do about it, though. + shouldMakeError = error.is_fatal; + break; + } + + RLMSyncManager *manager = [app syncManager]; + auto errorHandler = manager.errorHandler; + if (!shouldMakeError || !errorHandler) { + return; + } + NSError *nsError = make_sync_error(errorClass, @(error.message.c_str()), error.error_code.value(), custom); + RLMSyncSession *session = [[RLMSyncSession alloc] initWithSyncSession:errored_session]; + dispatch_async(dispatch_get_main_queue(), ^{ + errorHandler(nsError, session); + }); + }; + _config->client_resync_mode = realm::ClientResyncMode::Manual; + + RLMSyncManager *manager = [user.app syncManager]; + if (NSString *authorizationHeaderName = manager.authorizationHeaderName) { + _config->authorization_header_name.emplace(authorizationHeaderName.UTF8String); + } + if (NSDictionary *customRequestHeaders = manager.customRequestHeaders) { + for (NSString *key in customRequestHeaders) { + _config->custom_http_headers.emplace(key.UTF8String, customRequestHeaders[key].UTF8String); + } + } + + self.customFileURL = customFileURL; + return self; + } + return nil; +} + +@end diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMSyncManager.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMSyncManager.mm new file mode 100644 index 0000000..fc57bf9 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMSyncManager.mm @@ -0,0 +1,275 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// 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 "RLMSyncManager_Private.hpp" + +#import "RLMApp_Private.hpp" +#import "RLMRealmConfiguration+Sync.h" +#import "RLMSyncConfiguration_Private.hpp" +#import "RLMSyncSession_Private.hpp" +#import "RLMUser_Private.hpp" +#import "RLMSyncUtil_Private.hpp" +#import "RLMUtil.hpp" + +#import "sync/sync_config.hpp" +#import "sync/sync_manager.hpp" +#import "sync/sync_session.hpp" + +#if !defined(REALM_COCOA_VERSION) +#import "RLMVersion.h" +#endif + +using namespace realm; + +using Level = realm::util::Logger::Level; + +namespace { + +Level levelForSyncLogLevel(RLMSyncLogLevel logLevel) { + switch (logLevel) { + case RLMSyncLogLevelOff: return Level::off; + case RLMSyncLogLevelFatal: return Level::fatal; + case RLMSyncLogLevelError: return Level::error; + case RLMSyncLogLevelWarn: return Level::warn; + case RLMSyncLogLevelInfo: return Level::info; + case RLMSyncLogLevelDetail: return Level::detail; + case RLMSyncLogLevelDebug: return Level::debug; + case RLMSyncLogLevelTrace: return Level::trace; + case RLMSyncLogLevelAll: return Level::all; + } + REALM_UNREACHABLE(); // Unrecognized log level. +} + +RLMSyncLogLevel logLevelForLevel(Level logLevel) { + switch (logLevel) { + case Level::off: return RLMSyncLogLevelOff; + case Level::fatal: return RLMSyncLogLevelFatal; + case Level::error: return RLMSyncLogLevelError; + case Level::warn: return RLMSyncLogLevelWarn; + case Level::info: return RLMSyncLogLevelInfo; + case Level::detail: return RLMSyncLogLevelDetail; + case Level::debug: return RLMSyncLogLevelDebug; + case Level::trace: return RLMSyncLogLevelTrace; + case Level::all: return RLMSyncLogLevelAll; + } + REALM_UNREACHABLE(); // Unrecognized log level. +} + +#pragma mark - Loggers + +struct CocoaSyncLogger : public realm::util::RootLogger { + void do_log(Level, std::string message) override { + NSLog(@"Sync: %@", RLMStringDataToNSString(message)); + } +}; + +struct CocoaSyncLoggerFactory : public realm::SyncLoggerFactory { + std::unique_ptr make_logger(realm::util::Logger::Level level) override { + auto logger = std::make_unique(); + logger->set_level_threshold(level); + return std::move(logger); + } +} s_syncLoggerFactory; + +struct CallbackLogger : public realm::util::RootLogger { + RLMSyncLogFunction logFn; + void do_log(Level level, std::string message) override { + @autoreleasepool { + logFn(logLevelForLevel(level), RLMStringDataToNSString(message)); + } + } +}; +struct CallbackLoggerFactory : public realm::SyncLoggerFactory { + RLMSyncLogFunction logFn; + std::unique_ptr make_logger(realm::util::Logger::Level level) override { + auto logger = std::make_unique(); + logger->logFn = logFn; + logger->set_level_threshold(level); + return std::move(logger); // not a redundant move because it's a different type + } + + CallbackLoggerFactory(RLMSyncLogFunction logFn) : logFn(logFn) { } +}; + +} // anonymous namespace + +#pragma mark - RLMSyncManager + +@interface RLMSyncTimeoutOptions () { + @public + realm::SyncClientTimeouts _options; +} +@end + +@implementation RLMSyncManager { + std::unique_ptr _loggerFactory; + std::shared_ptr _syncManager; +} + +- (instancetype)initWithSyncManager:(std::shared_ptr)syncManager { + if (self = [super init]) { + [RLMUser _setUpBindingContextFactory]; + _syncManager = syncManager; + return self; + } + return nil; +} + ++ (SyncClientConfig)configurationWithRootDirectory:(NSURL *)rootDirectory appId:(NSString *)appId { + SyncClientConfig config; + bool should_encrypt = !getenv("REALM_DISABLE_METADATA_ENCRYPTION") && !RLMIsRunningInPlayground(); + config.logger_factory = &s_syncLoggerFactory; + config.metadata_mode = should_encrypt ? SyncManager::MetadataMode::Encryption + : SyncManager::MetadataMode::NoEncryption; + @autoreleasepool { + rootDirectory = rootDirectory ?: [NSURL fileURLWithPath:RLMDefaultDirectoryForBundleIdentifier(nil)]; + config.base_file_path = rootDirectory.path.UTF8String; + + bool isSwift = !!NSClassFromString(@"RealmSwiftObjectUtil"); + config.user_agent_binding_info = + util::format("Realm%1/%2", isSwift ? "Swift" : "ObjectiveC", + RLMStringDataWithNSString(REALM_COCOA_VERSION)); + config.user_agent_application_info = RLMStringDataWithNSString(appId); + } + + return config; +} + +- (std::weak_ptr)app { + return _syncManager->app(); +} + +- (NSString *)appID { + if (!_appID) { + _appID = [[NSBundle mainBundle] bundleIdentifier] ?: @"(none)"; + } + return _appID; +} + +- (void)setUserAgent:(NSString *)userAgent { + _syncManager->set_user_agent(RLMStringDataWithNSString(userAgent)); + _userAgent = userAgent; +} + +- (void)setCustomRequestHeaders:(NSDictionary *)customRequestHeaders { + _customRequestHeaders = customRequestHeaders.copy; + + for (auto&& user : _syncManager->all_users()) { + for (auto&& session : user->all_sessions()) { + auto config = session->config(); + config.custom_http_headers.clear();; + for (NSString *key in customRequestHeaders) { + config.custom_http_headers.emplace(key.UTF8String, customRequestHeaders[key].UTF8String); + } + session->update_configuration(std::move(config)); + } + } +} + +- (void)setLogger:(RLMSyncLogFunction)logFn { + _logger = logFn; + if (_logger) { + _loggerFactory = std::make_unique(logFn); + _syncManager->set_logger_factory(*_loggerFactory); + } + else { + _loggerFactory = nullptr; + _syncManager->set_logger_factory(s_syncLoggerFactory); + } +} + +- (void)setTimeoutOptions:(RLMSyncTimeoutOptions *)timeoutOptions { + _timeoutOptions = timeoutOptions; + _syncManager->set_timeouts(timeoutOptions->_options); +} + +#pragma mark - Passthrough properties + +- (RLMSyncLogLevel)logLevel { + return logLevelForLevel(_syncManager->log_level()); +} + +- (void)setLogLevel:(RLMSyncLogLevel)logLevel { + _syncManager->set_log_level(levelForSyncLogLevel(logLevel)); +} + +#pragma mark - Private API + +- (void)_fireError:(NSError *)error { + dispatch_async(dispatch_get_main_queue(), ^{ + if (self.errorHandler) { + self.errorHandler(error, nil); + } + }); +} + +- (void)resetForTesting { + _errorHandler = nil; + _appID = nil; + _userAgent = nil; + _logger = nil; + _authorizationHeaderName = nil; + _customRequestHeaders = nil; + _timeoutOptions = nil; + _syncManager->reset_for_testing(); +} + +- (std::shared_ptr)syncManager { + return _syncManager; +} +@end + +#pragma mark - RLMSyncTimeoutOptions + +@implementation RLMSyncTimeoutOptions +- (NSUInteger)connectTimeout { + return static_cast(_options.connect_timeout); +} +- (void)setConnectTimeout:(NSUInteger)connectTimeout { + _options.connect_timeout = connectTimeout; +} + +- (NSUInteger)connectLingerTime { + return static_cast(_options.connection_linger_time); +} +- (void)setConnectionLingerTime:(NSUInteger)connectionLingerTime { + _options.connection_linger_time = connectionLingerTime; +} + +- (NSUInteger)pingKeepalivePeriod { + return static_cast(_options.ping_keepalive_period); +} +- (void)setPingKeepalivePeriod:(NSUInteger)pingKeepalivePeriod { + _options.ping_keepalive_period = pingKeepalivePeriod; +} + +- (NSUInteger)pongKeepaliveTimeout { + return static_cast(_options.pong_keepalive_timeout); +} +- (void)setPongKeepaliveTimeout:(NSUInteger)pongKeepaliveTimeout { + _options.pong_keepalive_timeout = pongKeepaliveTimeout; +} + +- (NSUInteger)fastReconnectLimit { + return static_cast(_options.fast_reconnect_limit); +} +- (void)setFastReconnectLimit:(NSUInteger)fastReconnectLimit { + _options.fast_reconnect_limit = fastReconnectLimit; +} + +@end diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMSyncSession.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMSyncSession.mm new file mode 100644 index 0000000..d598378 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMSyncSession.mm @@ -0,0 +1,327 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// 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 "RLMSyncSession_Private.hpp" + +#import "RLMApp.h" +#import "RLMRealm_Private.hpp" +#import "RLMSyncConfiguration_Private.hpp" +#import "RLMUser_Private.hpp" +#import "RLMSyncManager_Private.hpp" +#import "RLMSyncUtil_Private.hpp" + +#import "sync/async_open_task.hpp" +#import "sync/sync_session.hpp" + +using namespace realm; + +@interface RLMSyncErrorActionToken () { +@public + std::string _originalPath; + BOOL _isValid; +} +@end + +@interface RLMProgressNotificationToken() { + uint64_t _token; + std::weak_ptr _session; +} +@end + +@implementation RLMProgressNotificationToken + +- (void)suppressNextNotification { + // No-op, but implemented in case this token is passed to + // `-[RLMRealm commitWriteTransactionWithoutNotifying:]`. +} + +- (void)invalidate { + if (auto session = _session.lock()) { + session->unregister_progress_notifier(_token); + _session.reset(); + _token = 0; + } +} + +- (void)dealloc { + if (_token != 0) { + NSLog(@"RLMProgressNotificationToken released without unregistering a notification. " + @"You must hold on to the RLMProgressNotificationToken and call " + @"-[RLMProgressNotificationToken invalidate] when you no longer wish to receive " + @"progress update notifications."); + } +} + +- (nullable instancetype)initWithTokenValue:(uint64_t)token + session:(std::shared_ptr)session { + if (token == 0) { + return nil; + } + if (self = [super init]) { + _token = token; + _session = session; + return self; + } + return nil; +} + +@end + +@interface RLMSyncSession () +@property (class, nonatomic, readonly) dispatch_queue_t notificationsQueue; +@property (atomic, readwrite) RLMSyncConnectionState connectionState; +@end + +@implementation RLMSyncSession + ++ (dispatch_queue_t)notificationsQueue { + static dispatch_queue_t queue; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + queue = dispatch_queue_create("io.realm.sync.sessionsNotificationQueue", DISPATCH_QUEUE_SERIAL); + }); + return queue; +} + +static RLMSyncConnectionState convertConnectionState(SyncSession::ConnectionState state) { + switch (state) { + case SyncSession::ConnectionState::Disconnected: return RLMSyncConnectionStateDisconnected; + case SyncSession::ConnectionState::Connecting: return RLMSyncConnectionStateConnecting; + case SyncSession::ConnectionState::Connected: return RLMSyncConnectionStateConnected; + } +} + +- (instancetype)initWithSyncSession:(std::shared_ptr const&)session { + if (self = [super init]) { + _session = session; + _connectionState = convertConnectionState(session->connection_state()); + // No need to save the token as RLMSyncSession always outlives the + // underlying SyncSession + session->register_connection_change_callback([=](auto, auto newState) { + dispatch_async(dispatch_get_main_queue(), ^{ + self.connectionState = convertConnectionState(newState); + }); + }); + return self; + } + return nil; +} + +- (RLMSyncConfiguration *)configuration { + if (auto session = _session.lock()) { + return [[RLMSyncConfiguration alloc] initWithRawConfig:session->config()]; + } + return nil; +} + +- (NSURL *)realmURL { + if (auto session = _session.lock()) { + if (auto url = session->full_realm_url()) { + return [NSURL URLWithString:@(url->c_str())]; + } + } + return nil; +} + +- (RLMUser *)parentUser { + if (auto session = _session.lock()) { + if (auto app = session->user()->sync_manager()->app().lock()) { + auto rlmApp = [RLMApp appWithId:@(app->config().app_id.data())]; + return [[RLMUser alloc] initWithUser:session->user() app:rlmApp]; + } + } + return nil; +} + +- (RLMSyncSessionState)state { + if (auto session = _session.lock()) { + if (session->state() == SyncSession::PublicState::Inactive) { + return RLMSyncSessionStateInactive; + } + return RLMSyncSessionStateActive; + } + return RLMSyncSessionStateInvalid; +} + +- (void)suspend { + if (auto session = _session.lock()) { + session->log_out(); + } +} + +- (void)resume { + if (auto session = _session.lock()) { + session->revive_if_needed(); + } +} + +- (BOOL)waitForUploadCompletionOnQueue:(dispatch_queue_t)queue callback:(void(^)(NSError *))callback { + if (auto session = _session.lock()) { + queue = queue ?: dispatch_get_main_queue(); + session->wait_for_upload_completion([=](std::error_code err) { + NSError *error = (err == std::error_code{}) ? nil : make_sync_error(err); + dispatch_async(queue, ^{ + callback(error); + }); + }); + return YES; + } + return NO; +} + +- (BOOL)waitForDownloadCompletionOnQueue:(dispatch_queue_t)queue callback:(void(^)(NSError *))callback { + if (auto session = _session.lock()) { + queue = queue ?: dispatch_get_main_queue(); + session->wait_for_download_completion([=](std::error_code err) { + NSError *error = (err == std::error_code{}) ? nil : make_sync_error(err); + dispatch_async(queue, ^{ + callback(error); + }); + }); + return YES; + } + return NO; +} + +- (RLMProgressNotificationToken *)addProgressNotificationForDirection:(RLMSyncProgressDirection)direction + mode:(RLMSyncProgressMode)mode + block:(RLMProgressNotificationBlock)block { + if (auto session = _session.lock()) { + dispatch_queue_t queue = RLMSyncSession.notificationsQueue; + auto notifier_direction = (direction == RLMSyncProgressDirectionUpload + ? SyncSession::NotifierType::upload + : SyncSession::NotifierType::download); + bool is_streaming = (mode == RLMSyncProgressModeReportIndefinitely); + uint64_t token = session->register_progress_notifier([=](uint64_t transferred, uint64_t transferrable) { + dispatch_async(queue, ^{ + block((NSUInteger)transferred, (NSUInteger)transferrable); + }); + }, notifier_direction, is_streaming); + return [[RLMProgressNotificationToken alloc] initWithTokenValue:token session:std::move(session)]; + } + return nil; +} + ++ (void)immediatelyHandleError:(RLMSyncErrorActionToken *)token syncManager:(RLMSyncManager *)syncManager { + if (!token->_isValid) { + return; + } + token->_isValid = NO; + + [syncManager syncManager]->immediately_run_file_actions(std::move(token->_originalPath)); +} + ++ (nullable RLMSyncSession *)sessionForRealm:(RLMRealm *)realm { + auto& config = realm->_realm->config().sync_config; + if (!config) { + return nil; + } + if (auto session = config->user->session_for_on_disk_path(realm->_realm->config().path)) { + return [[RLMSyncSession alloc] initWithSyncSession:session]; + } + return nil; +} + +- (NSString *)description { + return [NSString stringWithFormat: + @" {\n" + "\tstate = %d;\n" + "\tconnectionState = %d;\n" + "\trealmURL = %@;\n" + "\tuser = %@;\n" + "}", + (__bridge void *)self, + static_cast(self.state), + static_cast(self.connectionState), + self.realmURL, + self.parentUser.identifier]; +} + +@end + +// MARK: - Error action token + +@implementation RLMSyncErrorActionToken + +- (instancetype)initWithOriginalPath:(std::string)originalPath { + if (self = [super init]) { + _isValid = YES; + _originalPath = std::move(originalPath); + return self; + } + return nil; +} + +@end + +@implementation RLMAsyncOpenTask { + bool _cancel; + NSMutableArray *_blocks; +} + +- (void)addProgressNotificationOnQueue:(dispatch_queue_t)queue block:(RLMProgressNotificationBlock)block { + auto wrappedBlock = ^(NSUInteger transferred_bytes, NSUInteger transferrable_bytes) { + dispatch_async(queue, ^{ + @autoreleasepool { + block(transferred_bytes, transferrable_bytes); + } + }); + }; + + @synchronized (self) { + if (_task) { + _task->register_download_progress_notifier(wrappedBlock); + } + else if (!_cancel) { + if (!_blocks) { + _blocks = [NSMutableArray new]; + } + [_blocks addObject:wrappedBlock]; + } + } +} + +- (void)addProgressNotificationBlock:(RLMProgressNotificationBlock)block { + [self addProgressNotificationOnQueue:dispatch_get_main_queue() block:block]; +} + +- (void)cancel { + @synchronized (self) { + if (_task) { + _task->cancel(); + } + else { + _cancel = true; + _blocks = nil; + } + } +} + +- (void)setTask:(std::shared_ptr)task { + @synchronized (self) { + _task = task; + if (_cancel) { + _task->cancel(); + } + for (RLMProgressNotificationBlock block in _blocks) { + _task->register_download_progress_notifier(block); + } + _blocks = nil; + } +} +@end diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMSyncUtil.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMSyncUtil.mm new file mode 100644 index 0000000..438c1ac --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMSyncUtil.mm @@ -0,0 +1,127 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// 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 "RLMSyncUtil_Private.hpp" + +#import "RLMObject_Private.hpp" +#import "RLMRealmConfiguration+Sync.h" +#import "RLMRealmConfiguration_Private.hpp" +#import "RLMRealm_Private.hpp" +#import "RLMSyncConfiguration_Private.hpp" +#import "RLMUser_Private.hpp" +#import "RLMUtil.hpp" + +#import "shared_realm.hpp" + +#import "sync/sync_config.hpp" +#import "sync/sync_user.hpp" + +NSString *const RLMSyncErrorDomain = @"io.realm.sync"; +NSString *const RLMSyncAuthErrorDomain = @"io.realm.sync.auth"; +NSString *const RLMAppErrorDomain = @"io.realm.app"; + +NSString *const kRLMSyncPathOfRealmBackupCopyKey = @"recovered_realm_location_path"; +NSString *const kRLMSyncErrorActionTokenKey = @"error_action_token"; + +NSString *const kRLMSyncErrorStatusCodeKey = @"statusCode"; +NSString *const kRLMSyncUnderlyingErrorKey = @"underlying_error"; + +#pragma mark - C++ APIs + +using namespace realm; + +SyncSessionStopPolicy translateStopPolicy(RLMSyncStopPolicy stopPolicy) { + switch (stopPolicy) { + case RLMSyncStopPolicyImmediately: return SyncSessionStopPolicy::Immediately; + case RLMSyncStopPolicyLiveIndefinitely: return SyncSessionStopPolicy::LiveIndefinitely; + case RLMSyncStopPolicyAfterChangesUploaded: return SyncSessionStopPolicy::AfterChangesUploaded; + } + REALM_UNREACHABLE(); // Unrecognized stop policy. +} + +RLMSyncStopPolicy translateStopPolicy(SyncSessionStopPolicy stop_policy) { + switch (stop_policy) { + case SyncSessionStopPolicy::Immediately: return RLMSyncStopPolicyImmediately; + case SyncSessionStopPolicy::LiveIndefinitely: return RLMSyncStopPolicyLiveIndefinitely; + case SyncSessionStopPolicy::AfterChangesUploaded: return RLMSyncStopPolicyAfterChangesUploaded; + } + REALM_UNREACHABLE(); +} + +std::shared_ptr sync_session_for_realm(RLMRealm *realm) { + Realm::Config realmConfig = realm.configuration.config; + if (auto config = realmConfig.sync_config) { + std::shared_ptr user = config->user; + if (user && user->state() != SyncUser::State::Removed) { + return user->session_for_on_disk_path(realmConfig.path); + } + } + return nullptr; +} + +CocoaSyncUserContext& context_for(const std::shared_ptr& user) +{ + return *std::static_pointer_cast(user->binding_context()); +} + +NSError *make_sync_error(RLMSyncSystemErrorKind kind, NSString *description, NSInteger code, NSDictionary *custom) { + NSMutableDictionary *buffer = [custom ?: @{} mutableCopy]; + buffer[NSLocalizedDescriptionKey] = description; + if (code != NSNotFound) { + buffer[kRLMSyncErrorStatusCodeKey] = @(code); + } + + RLMSyncError errorCode; + switch (kind) { + case RLMSyncSystemErrorKindClientReset: + errorCode = RLMSyncErrorClientResetError; + break; + case RLMSyncSystemErrorKindPermissionDenied: + errorCode = RLMSyncErrorPermissionDeniedError; + break; + case RLMSyncSystemErrorKindUser: + errorCode = RLMSyncErrorClientUserError; + break; + case RLMSyncSystemErrorKindSession: + errorCode = RLMSyncErrorClientSessionError; + break; + case RLMSyncSystemErrorKindConnection: + case RLMSyncSystemErrorKindClient: + case RLMSyncSystemErrorKindUnknown: + errorCode = RLMSyncErrorClientInternalError; + break; + } + return [NSError errorWithDomain:RLMSyncErrorDomain + code:errorCode + userInfo:[buffer copy]]; +} + +NSError *make_sync_error(NSError *wrapped_auth_error) { + return [NSError errorWithDomain:RLMSyncErrorDomain + code:RLMSyncErrorUnderlyingAuthError + userInfo:@{kRLMSyncUnderlyingErrorKey: wrapped_auth_error}]; +} + +NSError *make_sync_error(std::error_code sync_error, RLMSyncSystemErrorKind kind) { + return [NSError errorWithDomain:RLMSyncErrorDomain + code:kind + userInfo:@{ + NSLocalizedDescriptionKey: @(sync_error.message().c_str()), + kRLMSyncErrorStatusCodeKey: @(sync_error.value()) + }]; +} diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMThreadSafeReference.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMThreadSafeReference.mm new file mode 100644 index 0000000..d582332 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMThreadSafeReference.mm @@ -0,0 +1,69 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// 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 "RLMThreadSafeReference_Private.hpp" +#import "RLMUtil.hpp" + +@implementation RLMThreadSafeReference { + realm::ThreadSafeReference _reference; + id _metadata; + Class _type; +} + +- (instancetype)initWithThreadConfined:(id)threadConfined { + if (!(self = [super init])) { + return nil; + } + + REALM_ASSERT_DEBUG([threadConfined conformsToProtocol:@protocol(RLMThreadConfined)]); + if (![threadConfined conformsToProtocol:@protocol(RLMThreadConfined_Private)]) { + @throw RLMException(@"Illegal custom conformance to `RLMThreadConfined` by `%@`", threadConfined.class); + } else if (threadConfined.invalidated) { + @throw RLMException(@"Cannot construct reference to invalidated object"); + } else if (!threadConfined.realm) { + @throw RLMException(@"Cannot construct reference to unmanaged object, " + "which can be passed across threads directly"); + } + + RLMTranslateError([&] { + _reference = [(id)threadConfined makeThreadSafeReference]; + _metadata = ((id)threadConfined).objectiveCMetadata; + }); + _type = threadConfined.class; + + return self; +} + ++ (instancetype)referenceWithThreadConfined:(id)threadConfined { + return [[self alloc] initWithThreadConfined:threadConfined]; +} + +- (id)resolveReferenceInRealm:(RLMRealm *)realm { + if (!_reference) { + @throw RLMException(@"Can only resolve a thread safe reference once."); + } + return RLMTranslateError([&] { + return [_type objectWithThreadSafeReference:std::move(_reference) metadata:_metadata realm:realm]; + }); +} + +- (BOOL)isInvalidated { + return !_reference; +} + +@end diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMUpdateChecker.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMUpdateChecker.mm new file mode 100644 index 0000000..4ff0dd6 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMUpdateChecker.mm @@ -0,0 +1,60 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// 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 "RLMUpdateChecker.hpp" + +#import "RLMRealm.h" +#import "RLMUtil.hpp" + +#if TARGET_IPHONE_SIMULATOR && !defined(REALM_COCOA_VERSION) +#import "RLMVersion.h" +#endif + +void RLMCheckForUpdates() { +#if TARGET_IPHONE_SIMULATOR + if (getenv("REALM_DISABLE_UPDATE_CHECKER") || RLMIsRunningInPlayground()) { + return; + } + + NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"alpha|beta|rc" + options:(NSRegularExpressionOptions)0 + error:nil]; + NSUInteger numberOfMatches = [regex numberOfMatchesInString:REALM_COCOA_VERSION + options:(NSMatchingOptions)0 + range:NSMakeRange(0, REALM_COCOA_VERSION.length)]; + + if (numberOfMatches > 0) { + // pre-release version, skip update checking + return; + } + + auto handler = ^(NSData *data, NSURLResponse *response, NSError *error) { + if (error || ((NSHTTPURLResponse *)response).statusCode != 200) { + return; + } + + NSString *latestVersion = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + if (![REALM_COCOA_VERSION isEqualToString:latestVersion]) { + NSLog(@"Version %@ of Realm is now available: https://github.com/realm/realm-cocoa/blob/v%@/CHANGELOG.md", latestVersion, latestVersion); + } + }; + + NSString *url = [NSString stringWithFormat:@"https://static.realm.io/update/cocoa?%@", REALM_COCOA_VERSION]; + [[NSURLSession.sharedSession dataTaskWithURL:[NSURL URLWithString:url] completionHandler:handler] resume]; +#endif +} diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMUpdateResult.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMUpdateResult.mm new file mode 100644 index 0000000..21fd604 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMUpdateResult.mm @@ -0,0 +1,35 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 "RLMUpdateResult_Private.hpp" +#import "RLMObjectId_Private.hpp" + +@implementation RLMUpdateResult + +- (instancetype)initWithUpdateResult:(realm::app::MongoCollection::UpdateResult)UpdateResult { + if (self = [super init]) { + _matchedCount = UpdateResult.matched_count; + _modifiedCount = UpdateResult.modified_count; + if (UpdateResult.upserted_id) { + _objectId = [[RLMObjectId alloc] initWithValue:*UpdateResult.upserted_id]; + } + } + return self; +} + +@end diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMUser.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMUser.mm new file mode 100644 index 0000000..0bdec95 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMUser.mm @@ -0,0 +1,285 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// 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 "RLMUser_Private.hpp" + +#import "RLMCredentials_Private.hpp" +#import "RLMApp_Private.hpp" +#import "RLMBSON_Private.hpp" +#import "RLMNetworkTransport.h" +#import "RLMRealmConfiguration+Sync.h" +#import "RLMRealmConfiguration_Private.hpp" +#import "RLMRealmUtil.hpp" +#import "RLMResults_Private.hpp" +#import "RLMSyncConfiguration.h" +#import "RLMSyncConfiguration_Private.hpp" +#import "RLMSyncManager_Private.hpp" +#import "RLMSyncSession_Private.hpp" +#import "RLMSyncUtil_Private.hpp" +#import "RLMUtil.hpp" +#import "RLMAPIKeyAuth.h" +#import "RLMMongoClient_Private.hpp" + +#import "util/bson/bson.hpp" +#import "sync/sync_manager.hpp" +#import "sync/sync_session.hpp" +#import "sync/sync_user.hpp" + +using namespace realm; + +@interface RLMUser () { + std::shared_ptr _user; +} +@end + +@implementation RLMUser + +#pragma mark - API + +- (instancetype)initWithUser:(std::shared_ptr)user + app:(RLMApp *)app { + if (self = [super init]) { + _user = user; + _app = app; + return self; + } + return nil; +} + +- (BOOL)isEqual:(id)object { + if (![object isKindOfClass:[RLMUser class]]) { + return NO; + } + return _user == ((RLMUser *)object)->_user; +} + +- (RLMRealmConfiguration *)configurationWithPartitionValue:(nullable id)partitionValue { + auto syncConfig = [[RLMSyncConfiguration alloc] initWithUser:self + partitionValue:partitionValue + customFileURL:nil + stopPolicy:RLMSyncStopPolicyAfterChangesUploaded]; + RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init]; + config.syncConfiguration = syncConfig; + return config; +} + +- (void)logOut { + if (!_user) { + return; + } + _user->log_out(); +} + +- (BOOL)isLoggedIn { + return _user->is_logged_in(); +} + +- (void)invalidate { + if (!_user) { + return; + } + _user = nullptr; +} + +- (NSString *)pathForPartitionValue:(id)partitionValue { + std::stringstream s; + s << RLMConvertRLMBSONToBson(partitionValue); + NSString *encodedPartitionValue = [@(s.str().c_str()) stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLPathAllowedCharacterSet]]; + return [[NSString alloc] initWithFormat:@"%@/%@", [self identifier], encodedPartitionValue]; +} + +- (nullable RLMSyncSession *)sessionForPartitionValue:(id)partitionValue { + if (!_user) { + return nil; + } + + auto path = _user->sync_manager()->path_for_realm(*_user, [[self pathForPartitionValue:partitionValue] UTF8String]); + if (auto session = _user->session_for_on_disk_path(path)) { + return [[RLMSyncSession alloc] initWithSyncSession:session]; + } + return nil; +} + +- (NSArray *)allSessions { + if (!_user) { + return @[]; + } + NSMutableArray *buffer = [NSMutableArray array]; + auto sessions = _user->all_sessions(); + for (auto session : sessions) { + [buffer addObject:[[RLMSyncSession alloc] initWithSyncSession:std::move(session)]]; + } + return [buffer copy]; +} + +- (NSString *)identifier { + if (!_user) { + return @""; + } + return @(_user->identity().c_str()); +} + +- (NSArray *)identities { + if (!_user) { + return @[]; + } + NSMutableArray *buffer = [NSMutableArray array]; + auto identities = _user->identities(); + for (auto& identity : identities) { + [buffer addObject: [[RLMUserIdentity alloc] initUserIdentityWithProviderType:@(identity.provider_type.c_str()) + identifier:@(identity.id.c_str())]]; + } + + return [buffer copy]; +} + +- (RLMUserState)state { + if (!_user) { + return RLMUserStateRemoved; + } + switch (_user->state()) { + case SyncUser::State::LoggedIn: + return RLMUserStateLoggedIn; + case SyncUser::State::LoggedOut: + return RLMUserStateLoggedOut; + case SyncUser::State::Removed: + return RLMUserStateRemoved; + } +} + +- (void)refreshCustomDataWithCompletion:(RLMUserCustomDataBlock)completion { + _user->refresh_custom_data([completion, self](util::Optional error) { + if (!error) { + return completion([self customData], nil); + } + + completion(nil, RLMAppErrorToNSError(*error)); + }); +} + +- (void)linkUserWithCredentials:(RLMCredentials *)credentials + completion:(RLMOptionalUserBlock)completion { + _app._realmApp->link_user(_user, credentials.appCredentials, + ^(std::shared_ptr user, util::Optional error) { + if (error && error->error_code) { + return completion(nil, RLMAppErrorToNSError(*error)); + } + + completion([[RLMUser alloc] initWithUser:user app:_app], nil); + }); +} + +- (void)removeWithCompletion:(RLMOptionalErrorBlock)completion { + _app._realmApp->remove_user(_user, ^(realm::util::Optional error) { + [self handleResponse:error completion:completion]; + }); +} + +- (void)logOutWithCompletion:(RLMOptionalErrorBlock)completion { + _app._realmApp->log_out(_user, ^(realm::util::Optional error) { + [self handleResponse:error completion:completion]; + }); +} + +- (RLMAPIKeyAuth *)apiKeysAuth { + return [[RLMAPIKeyAuth alloc] initWithApp: _app]; +} + +- (RLMMongoClient *)mongoClientWithServiceName:(NSString *)serviceName { + return [[RLMMongoClient alloc] initWithUser:self serviceName:serviceName]; +} + +- (void)callFunctionNamed:(NSString *)name + arguments:(NSArray> *)arguments + completionBlock:(RLMCallFunctionCompletionBlock)completionBlock { + bson::BsonArray args; + + for (id argument in arguments) { + args.push_back(RLMConvertRLMBSONToBson(argument)); + } + + _app._realmApp->call_function(_user, + std::string(name.UTF8String), + args, [completionBlock](util::Optional error, + util::Optional response) { + if (error) { + return completionBlock(nil, RLMAppErrorToNSError(*error)); + } + + completionBlock(RLMConvertBsonToRLMBSON(*response), nil); + }); +} + +- (void)handleResponse:(realm::util::Optional)error + completion:(RLMOptionalErrorBlock)completion { + if (error && error->error_code) { + return completion(RLMAppErrorToNSError(*error)); + } + completion(nil); +} + +#pragma mark - Private API + ++ (void)_setUpBindingContextFactory { + SyncUser::set_binding_context_factory([] { + return std::make_shared(); + }); +} + +- (NSString *)refreshToken { + if (!_user || _user->refresh_token().empty()) { + return nil; + } + return @(_user->refresh_token().c_str()); +} + +- (NSString *)accessToken { + if (!_user || _user->access_token().empty()) { + return nil; + } + return @(_user->access_token().c_str()); +} + +- (NSDictionary *)customData { + if (!_user || !_user->custom_data()) { + return @{}; + } + + return (NSDictionary *)RLMConvertBsonToRLMBSON(*_user->custom_data()); +} + +- (std::shared_ptr)_syncUser { + return _user; +} + +@end + +#pragma mark - RLMUserIdentity + +@implementation RLMUserIdentity + +- (instancetype)initUserIdentityWithProviderType:(NSString *)providerType + identifier:(NSString *)identifier { + if (self = [super init]) { + _providerType = providerType; + _identifier = identifier; + } + return self; +} + +@end diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMUserAPIKey.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMUserAPIKey.mm new file mode 100644 index 0000000..de97262 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMUserAPIKey.mm @@ -0,0 +1,68 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 "RLMUserAPIKey.h" +#import "RLMUserAPIKey_Private.hpp" +#import "RLMUtil.hpp" +#import "RLMObjectId_Private.hpp" + +@interface RLMUserAPIKey() { + realm::app::App::UserAPIKey _userAPIKey; +} +@end + +@implementation RLMUserAPIKey + +- (instancetype)initWithUserAPIKey:(realm::app::App::UserAPIKey)userAPIKey { + if (self = [super init]) { + _userAPIKey = userAPIKey; + return self; + } + + return nil; +} + +// Indicates if the API key is disabled or not +- (BOOL)disabled { + return _userAPIKey.disabled; +} + +// The name of the key. +- (NSString *)name { + return @(_userAPIKey.name.c_str()); +} + +// The actual key. Will only be included in +// the response when an API key is first created. +- (NSString *)key { + if (_userAPIKey.key) { + return @(_userAPIKey.name.c_str()); + } + + return nil; +} + +- (RLMObjectId *)objectId { + return [[RLMObjectId alloc] initWithValue:_userAPIKey.id]; +} + +- (realm::app::App::UserAPIKey)_apiKey { + return _userAPIKey; +} + +@end diff --git a/Darner-dan-uh/Pods/Realm/Realm/RLMUtil.mm b/Darner-dan-uh/Pods/Realm/Realm/RLMUtil.mm new file mode 100644 index 0000000..66a1992 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/RLMUtil.mm @@ -0,0 +1,513 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// 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 "RLMUtil.hpp" + +#import "RLMArray_Private.hpp" +#import "RLMDecimal128_Private.hpp" +#import "RLMListBase.h" +#import "RLMObjectId_Private.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObjectStore.h" +#import "RLMObject_Private.hpp" +#import "RLMProperty_Private.h" +#import "RLMSchema_Private.h" +#import "RLMSwiftSupport.h" + +#import "shared_realm.hpp" + +#if REALM_ENABLE_SYNC +#import "RLMSyncUtil.h" +#endif + +#import +#import + +#include +#include + +#if !defined(REALM_COCOA_VERSION) +#import "RLMVersion.h" +#endif + +static inline bool numberIsInteger(__unsafe_unretained NSNumber *const obj) { + char data_type = [obj objCType][0]; + return data_type == *@encode(bool) || + data_type == *@encode(char) || + data_type == *@encode(short) || + data_type == *@encode(int) || + data_type == *@encode(long) || + data_type == *@encode(long long) || + data_type == *@encode(unsigned short) || + data_type == *@encode(unsigned int) || + data_type == *@encode(unsigned long) || + data_type == *@encode(unsigned long long); +} + +static inline bool numberIsBool(__unsafe_unretained NSNumber *const obj) { + // @encode(BOOL) is 'B' on iOS 64 and 'c' + // objcType is always 'c'. Therefore compare to "c". + if ([obj objCType][0] == 'c') { + return true; + } + + if (numberIsInteger(obj)) { + int value = [obj intValue]; + return value == 0 || value == 1; + } + + return false; +} + +static inline bool numberIsFloat(__unsafe_unretained NSNumber *const obj) { + char data_type = [obj objCType][0]; + return data_type == *@encode(float) || + data_type == *@encode(short) || + data_type == *@encode(int) || + data_type == *@encode(long) || + data_type == *@encode(long long) || + data_type == *@encode(unsigned short) || + data_type == *@encode(unsigned int) || + data_type == *@encode(unsigned long) || + data_type == *@encode(unsigned long long) || + // A double is like float if it fits within float bounds or is NaN. + (data_type == *@encode(double) && (ABS([obj doubleValue]) <= FLT_MAX || isnan([obj doubleValue]))); +} + +static inline bool numberIsDouble(__unsafe_unretained NSNumber *const obj) { + char data_type = [obj objCType][0]; + return data_type == *@encode(double) || + data_type == *@encode(float) || + data_type == *@encode(short) || + data_type == *@encode(int) || + data_type == *@encode(long) || + data_type == *@encode(long long) || + data_type == *@encode(unsigned short) || + data_type == *@encode(unsigned int) || + data_type == *@encode(unsigned long) || + data_type == *@encode(unsigned long long); +} + +static inline RLMArray *asRLMArray(__unsafe_unretained id const value) { + return RLMDynamicCast(value) ?: RLMDynamicCast(value)._rlmArray; +} + +static inline bool checkArrayType(__unsafe_unretained RLMArray *const array, + RLMPropertyType type, bool optional, + __unsafe_unretained NSString *const objectClassName) { + return array.type == type && array.optional == optional + && (type != RLMPropertyTypeObject || [array.objectClassName isEqualToString:objectClassName]); +} + +id (*RLMSwiftAsFastEnumeration)(id); +id RLMAsFastEnumeration(__unsafe_unretained id obj) { + if (!obj) { + return nil; + } + if ([obj conformsToProtocol:@protocol(NSFastEnumeration)]) { + return obj; + } + if (RLMSwiftAsFastEnumeration) { + return RLMSwiftAsFastEnumeration(obj); + } + return nil; +} + +bool RLMIsSwiftObjectClass(Class cls) { + static Class s_swiftObjectClass = NSClassFromString(@"RealmSwiftObject"); + static Class s_swiftEmbeddedObjectClass = NSClassFromString(@"RealmSwiftEmbeddedObject"); + return [cls isSubclassOfClass:s_swiftObjectClass] || [cls isSubclassOfClass:s_swiftEmbeddedObjectClass]; +} + +BOOL RLMValidateValue(__unsafe_unretained id const value, + RLMPropertyType type, bool optional, bool array, + __unsafe_unretained NSString *const objectClassName) { + if (optional && !RLMCoerceToNil(value)) { + return YES; + } + if (array) { + if (auto rlmArray = asRLMArray(value)) { + return checkArrayType(rlmArray, type, optional, objectClassName); + } + if (id enumeration = RLMAsFastEnumeration(value)) { + // check each element for compliance + for (id el in enumeration) { + if (!RLMValidateValue(el, type, optional, false, objectClassName)) { + return NO; + } + } + return YES; + } + if (!value || value == NSNull.null) { + return YES; + } + return NO; + } + + switch (type) { + case RLMPropertyTypeString: + return [value isKindOfClass:[NSString class]]; + case RLMPropertyTypeBool: + if ([value isKindOfClass:[NSNumber class]]) { + return numberIsBool(value); + } + return NO; + case RLMPropertyTypeDate: + return [value isKindOfClass:[NSDate class]]; + case RLMPropertyTypeInt: + if (NSNumber *number = RLMDynamicCast(value)) { + return numberIsInteger(number); + } + return NO; + case RLMPropertyTypeFloat: + if (NSNumber *number = RLMDynamicCast(value)) { + return numberIsFloat(number); + } + return NO; + case RLMPropertyTypeDouble: + if (NSNumber *number = RLMDynamicCast(value)) { + return numberIsDouble(number); + } + return NO; + case RLMPropertyTypeData: + return [value isKindOfClass:[NSData class]]; + case RLMPropertyTypeAny: + return NO; + case RLMPropertyTypeLinkingObjects: + return YES; + case RLMPropertyTypeObject: { + // only NSNull, nil, or objects which derive from RLMObject and match the given + // object class are valid + RLMObjectBase *objBase = RLMDynamicCast(value); + return objBase && [objBase->_objectSchema.className isEqualToString:objectClassName]; + } + case RLMPropertyTypeObjectId: + return [value isKindOfClass:[RLMObjectId class]]; + case RLMPropertyTypeDecimal128: + return [value isKindOfClass:[NSNumber class]] + || [value isKindOfClass:[RLMDecimal128 class]] + || ([value isKindOfClass:[NSString class]] && realm::Decimal128::is_valid_str([value UTF8String])); + } + @throw RLMException(@"Invalid RLMPropertyType specified"); +} + +void RLMThrowTypeError(__unsafe_unretained id const obj, + __unsafe_unretained RLMObjectSchema *const objectSchema, + __unsafe_unretained RLMProperty *const prop) { + @throw RLMException(@"Invalid value '%@' of type '%@' for '%@%s'%s property '%@.%@'.", + obj, [obj class], + prop.objectClassName ?: RLMTypeToString(prop.type), prop.optional ? "?" : "", + prop.array ? " array" : "", objectSchema.className, prop.name); +} + +void RLMValidateValueForProperty(__unsafe_unretained id const obj, + __unsafe_unretained RLMObjectSchema *const objectSchema, + __unsafe_unretained RLMProperty *const prop, + bool validateObjects) { + // This duplicates a lot of the checks in RLMIsObjectValidForProperty() + // for the sake of more specific error messages + if (prop.array) { + // nil is considered equivalent to an empty array for historical reasons + // since we don't support null arrays (only arrays containing null), + // it's not worth the BC break to change this + if (!obj || obj == NSNull.null) { + return; + } + id enumeration = RLMAsFastEnumeration(obj); + if (!enumeration) { + @throw RLMException(@"Invalid value (%@) for '%@%s' array property '%@.%@': value is not enumerable.", + obj, prop.objectClassName ?: RLMTypeToString(prop.type), prop.optional ? "?" : "", + objectSchema.className, prop.name); + } + if (!validateObjects && prop.type == RLMPropertyTypeObject) { + return; + } + + if (RLMArray *array = asRLMArray(obj)) { + if (!checkArrayType(array, prop.type, prop.optional, prop.objectClassName)) { + @throw RLMException(@"RLMArray<%@%s> does not match expected type '%@%s' for property '%@.%@'.", + array.objectClassName ?: RLMTypeToString(array.type), array.optional ? "?" : "", + prop.objectClassName ?: RLMTypeToString(prop.type), prop.optional ? "?" : "", + objectSchema.className, prop.name); + } + return; + } + + for (id value in enumeration) { + if (!RLMValidateValue(value, prop.type, prop.optional, false, prop.objectClassName)) { + RLMThrowTypeError(value, objectSchema, prop); + } + } + return; + } + + // For create() we want to skip the validation logic for objects because + // we allow much fuzzier matching (any KVC-compatible object with at least + // all the non-defaulted fields), and all the logic for that lives in the + // object store rather than here + if (prop.type == RLMPropertyTypeObject && !validateObjects) { + return; + } + if (RLMIsObjectValidForProperty(obj, prop)) { + return; + } + + RLMThrowTypeError(obj, objectSchema, prop); +} + +BOOL RLMIsObjectValidForProperty(__unsafe_unretained id const obj, + __unsafe_unretained RLMProperty *const property) { + return RLMValidateValue(obj, property.type, property.optional, property.array, property.objectClassName); +} + +NSDictionary *RLMDefaultValuesForObjectSchema(__unsafe_unretained RLMObjectSchema *const objectSchema) { + if (!objectSchema.isSwiftClass) { + return [objectSchema.objectClass defaultPropertyValues]; + } + + NSMutableDictionary *defaults = nil; + if ([objectSchema.objectClass isSubclassOfClass:RLMObject.class]) { + defaults = [NSMutableDictionary dictionaryWithDictionary:[objectSchema.objectClass defaultPropertyValues]]; + } + else { + defaults = [NSMutableDictionary dictionary]; + } + RLMObject *defaultObject = [[objectSchema.objectClass alloc] init]; + for (RLMProperty *prop in objectSchema.properties) { + if (!defaults[prop.name] && defaultObject[prop.name]) { + defaults[prop.name] = defaultObject[prop.name]; + } + } + return defaults; +} + +static NSException *RLMException(NSString *reason, NSDictionary *additionalUserInfo) { + NSMutableDictionary *userInfo = @{RLMRealmVersionKey: REALM_COCOA_VERSION, + RLMRealmCoreVersionKey: @REALM_VERSION}.mutableCopy; + if (additionalUserInfo != nil) { + [userInfo addEntriesFromDictionary:additionalUserInfo]; + } + NSException *e = [NSException exceptionWithName:RLMExceptionName + reason:reason + userInfo:userInfo]; + return e; +} + +NSException *RLMException(NSString *fmt, ...) { + va_list args; + va_start(args, fmt); + NSException *e = RLMException([[NSString alloc] initWithFormat:fmt arguments:args], @{}); + va_end(args); + return e; +} + +NSException *RLMException(std::exception const& exception) { + return RLMException(@"%s", exception.what()); +} + +NSError *RLMMakeError(RLMError code, std::exception const& exception) { + return [NSError errorWithDomain:RLMErrorDomain + code:code + userInfo:@{NSLocalizedDescriptionKey: @(exception.what()), + @"Error Code": @(code)}]; +} + +NSError *RLMMakeError(RLMError code, const realm::util::File::AccessError& exception) { + return [NSError errorWithDomain:RLMErrorDomain + code:code + userInfo:@{NSLocalizedDescriptionKey: @(exception.what()), + NSFilePathErrorKey: @(exception.get_path().c_str()), + @"Error Code": @(code)}]; +} + +NSError *RLMMakeError(RLMError code, const realm::RealmFileException& exception) { + NSString *underlying = @(exception.underlying().c_str()); + return [NSError errorWithDomain:RLMErrorDomain + code:code + userInfo:@{NSLocalizedDescriptionKey: @(exception.what()), + NSFilePathErrorKey: @(exception.path().c_str()), + @"Error Code": @(code), + @"Underlying": underlying.length == 0 ? @"n/a" : underlying}]; +} + +NSError *RLMMakeError(std::system_error const& exception) { + int code = exception.code().value(); + BOOL isGenericCategoryError = (exception.code().category() == std::generic_category()); + NSString *category = @(exception.code().category().name()); + NSString *errorDomain = isGenericCategoryError ? NSPOSIXErrorDomain : RLMUnknownSystemErrorDomain; +#if REALM_ENABLE_SYNC + if (exception.code().category() == realm::sync::client_error_category()) { + if (exception.code().value() == static_cast(realm::sync::Client::Error::connect_timeout)) { + errorDomain = NSPOSIXErrorDomain; + code = ETIMEDOUT; + } + else { + errorDomain = RLMSyncErrorDomain; + } + } +#endif + + return [NSError errorWithDomain:errorDomain code:code + userInfo:@{NSLocalizedDescriptionKey: @(exception.what()), + @"Error Code": @(exception.code().value()), + @"Category": category}]; +} + +void RLMSetErrorOrThrow(NSError *error, NSError **outError) { + if (outError) { + *outError = error; + } + else { + NSString *msg = error.localizedDescription; + if (error.userInfo[NSFilePathErrorKey]) { + msg = [NSString stringWithFormat:@"%@: %@", error.userInfo[NSFilePathErrorKey], error.localizedDescription]; + } + @throw RLMException(msg, @{NSUnderlyingErrorKey: error}); + } +} + +BOOL RLMIsDebuggerAttached() +{ + int name[] = { + CTL_KERN, + KERN_PROC, + KERN_PROC_PID, + getpid() + }; + + struct kinfo_proc info; + size_t info_size = sizeof(info); + if (sysctl(name, sizeof(name)/sizeof(name[0]), &info, &info_size, NULL, 0) == -1) { + NSLog(@"sysctl() failed: %s", strerror(errno)); + return false; + } + + return (info.kp_proc.p_flag & P_TRACED) != 0; +} + +BOOL RLMIsRunningInPlayground() { + return [[NSBundle mainBundle].bundleIdentifier hasPrefix:@"com.apple.dt.playground."]; +} + +id RLMMixedToObjc(realm::Mixed const& mixed) { + switch (mixed.get_type()) { + case realm::type_String: + return RLMStringDataToNSString(mixed.get_string()); + case realm::type_Int: + return @(mixed.get_int()); + case realm::type_Float: + return @(mixed.get_float()); + case realm::type_Double: + return @(mixed.get_double()); + case realm::type_Bool: + return @(mixed.get_bool()); + case realm::type_Timestamp: + return RLMTimestampToNSDate(mixed.get_timestamp()); + case realm::type_Binary: + return RLMBinaryDataToNSData(mixed.get()); + case realm::type_Decimal: + return [[RLMDecimal128 alloc] initWithDecimal128:mixed.get()]; + case realm::type_ObjectId: + return [[RLMObjectId alloc] initWithValue:mixed.get()]; + case realm::type_Link: + case realm::type_LinkList: + case realm::type_OldMixed: + case realm::type_OldTable: + case realm::type_OldDateTime: + REALM_UNREACHABLE(); + default: + @throw RLMException(@"Invalid data type for RLMPropertyTypeAny property."); + } +} + +realm::Decimal128 RLMObjcToDecimal128(__unsafe_unretained id const value) { + try { + if (!value || value == NSNull.null) { + return realm::Decimal128(realm::null()); + } + if (auto decimal = RLMDynamicCast(value)) { + return decimal.decimal128Value; + } + if (auto string = RLMDynamicCast(value)) { + return realm::Decimal128(string.UTF8String); + } + if (auto decimal = RLMDynamicCast(value)) { + return realm::Decimal128(decimal.stringValue.UTF8String); + } + if (auto number = RLMDynamicCast(value)) { + auto type = number.objCType[0]; + if (type == *@encode(double) || type == *@encode(float)) { + return realm::Decimal128(number.doubleValue); + } + else if (std::isupper(type)) { + return realm::Decimal128(number.unsignedLongLongValue); + } + else { + return realm::Decimal128(number.longLongValue); + } + } + } + catch (std::exception const& e) { + @throw RLMException(@"Cannot convert value '%@' of type '%@' to decimal128: %s", + value, [value class], e.what()); + } + @throw RLMException(@"Cannot convert value '%@' of type '%@' to decimal128", value, [value class]); +} + +NSString *RLMDefaultDirectoryForBundleIdentifier(NSString *bundleIdentifier) { +#if TARGET_OS_TV + (void)bundleIdentifier; + // tvOS prohibits writing to the Documents directory, so we use the Library/Caches directory instead. + return NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0]; +#elif TARGET_OS_IPHONE && !TARGET_OS_MACCATALYST + (void)bundleIdentifier; + // On iOS the Documents directory isn't user-visible, so put files there + return NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]; +#else + // On OS X it is, so put files in Application Support. If we aren't running + // in a sandbox, put it in a subdirectory based on the bundle identifier + // to avoid accidentally sharing files between applications + NSString *path = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES)[0]; + if (![[NSProcessInfo processInfo] environment][@"APP_SANDBOX_CONTAINER_ID"]) { + if (!bundleIdentifier) { + bundleIdentifier = [NSBundle mainBundle].bundleIdentifier; + } + if (!bundleIdentifier) { + bundleIdentifier = [NSBundle mainBundle].executablePath.lastPathComponent; + } + + path = [path stringByAppendingPathComponent:bundleIdentifier]; + + // create directory + [[NSFileManager defaultManager] createDirectoryAtPath:path + withIntermediateDirectories:YES + attributes:nil + error:nil]; + } + return path; +#endif +} + +NSDateFormatter *RLMISO8601Formatter() { + // note: NSISO8601DateFormatter can't be used as it doesn't support milliseconds + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; + dateFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]; + dateFormatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss.SSSZ"; + dateFormatter.calendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian]; + return dateFormatter; +} diff --git a/Darner-dan-uh/Pods/Realm/Realm/Realm.modulemap b/Darner-dan-uh/Pods/Realm/Realm/Realm.modulemap new file mode 100644 index 0000000..42845f6 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/Realm/Realm.modulemap @@ -0,0 +1,31 @@ +framework module Realm { + umbrella header "Realm.h" + + export * + module * { export * } + + explicit module Private { + header "RLMAccessor.h" + header "RLMArray_Private.h" + header "RLMCollection_Private.h" + header "RLMListBase.h" + header "RLMObject_Private.h" + header "RLMObjectBase_Dynamic.h" + header "RLMObjectBase_Private.h" + header "RLMObjectSchema_Private.h" + header "RLMObjectStore.h" + header "RLMOptionalBase.h" + header "RLMProperty_Private.h" + header "RLMRealm_Private.h" + header "RLMRealmConfiguration_Private.h" + header "RLMResults_Private.h" + header "RLMSchema_Private.h" + header "RLMSyncConfiguration_Private.h" + header "RLMSyncUtil_Private.h" + } + + explicit module Dynamic { + header "RLMRealm_Dynamic.h" + header "RLMObjectBase_Dynamic.h" + } +} diff --git a/Darner-dan-uh/Pods/Realm/build.sh b/Darner-dan-uh/Pods/Realm/build.sh new file mode 100755 index 0000000..5a1fd90 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/build.sh @@ -0,0 +1,1577 @@ +#!/bin/bash + +################################################################################## +# Custom build tool for Realm Objective-C binding. +# +# (C) Copyright 2011-2015 by realm.io. +################################################################################## + +# Warning: pipefail is not a POSIX compatible option, but on macOS it works just fine. +# macOS uses a POSIX complain version of bash as /bin/sh, but apparently it does +# not strip away this feature. Also, this will fail if somebody forces the script +# to be run with zsh. +set -o pipefail +set -e + +source_root="$(dirname "$0")" + +# You can override the version of the core library +: ${REALM_BASE_URL:="https://static.realm.io/downloads"} # set it if you need to use a remote repo + +: ${REALM_CORE_VERSION:=$(sed -n 's/^REALM_CORE_VERSION=\(.*\)$/\1/p' ${source_root}/dependencies.list)} # set to "current" to always use the current build + +: ${REALM_SYNC_VERSION:=$(sed -n 's/^REALM_SYNC_VERSION=\(.*\)$/\1/p' ${source_root}/dependencies.list)} + +: ${REALM_OBJECT_SERVER_VERSION:=$(sed -n 's/^MONGODB_STITCH_ADMIN_SDK_VERSION=\(.*\)$/\1/p' ${source_root}/dependencies.list)} + +# You can override the xcmode used +: ${XCMODE:=xcodebuild} # must be one of: xcodebuild (default), xcpretty, xctool + +# Provide a fallback value for TMPDIR, relevant for Xcode Bots +: ${TMPDIR:=$(getconf DARWIN_USER_TEMP_DIR)} + +PATH=/usr/libexec:$PATH + +if ! [ -z "${JENKINS_HOME}" ]; then + XCPRETTY_PARAMS="--no-utf --report junit --output build/reports/junit.xml" + CODESIGN_PARAMS="CODE_SIGN_IDENTITY= CODE_SIGNING_REQUIRED=NO" +fi + +usage() { +cat <> "$out_path/$product_name/Headers/$module_name-Swift.h" + fi + + # Verify that the combined library has bitcode and we didn't accidentally + # remove it somewhere along the line + if [[ "$config" == "Release" ]]; then + sh build.sh binary-has-bitcode "$LIPO_OUTPUT" + fi +} + +copy_realm_framework() { + local platform="$1" + rm -rf build/$platform/swift-$REALM_XCODE_VERSION/Realm.framework + cp -R build/$platform/Realm.framework build/$platform/swift-$REALM_XCODE_VERSION +} + +clean_retrieve() { + mkdir -p "$2" + rm -rf "$2/$3" + cp -R "$1" "$2" +} + +move_to_clean_dir() { + rm -rf "$2" + mkdir -p "$2" + mv "$1" "$2" +} + +test_ios_static() { + destination="$1" + xc "-scheme 'Realm iOS static' -configuration $CONFIGURATION -sdk iphonesimulator -destination '$destination' build-for-testing" + xc "-scheme 'Realm iOS static' -configuration $CONFIGURATION -sdk iphonesimulator -destination '$destination' test" +} + +plist_get() { + /usr/libexec/PlistBuddy -c "Print :$2" $1 2> /dev/null +} + +###################################### +# Device Test Helper +###################################### + +test_devices() { + local serial_numbers=() + local awk_script=" + /^ +Vendor ID: / { is_apple = 0; } + /^ +Vendor ID: 0x05[aA][cC] / { is_apple = 1; } + /^ +Serial Number: / { + if (is_apple) { + match(\$0, /^ +Serial Number: /); + print substr(\$0, RLENGTH + 1); + } + } + " + local serial_numbers_text=$(/usr/sbin/system_profiler SPUSBDataType | /usr/bin/awk "$awk_script") + while read -r number; do + if [[ "$number" != "" ]]; then + serial_numbers+=("$number") + fi + done <<< "$serial_numbers_text" + if [[ ${#serial_numbers[@]} == 0 ]]; then + echo "At least one iOS/tvOS device must be connected to this computer to run device tests" + if [ -z "${JENKINS_HOME}" ]; then + # Don't fail if running locally and there's no device + exit 0 + fi + exit 1 + fi + local sdk="$1" + local scheme="$2" + local configuration="$3" + local failed=0 + for device in "${serial_numbers[@]}"; do + xc "-scheme '$scheme' -configuration $configuration -destination 'id=$device' -sdk $sdk test" || failed=1 + done + return $failed +} + +###################################### +# Docs +###################################### + +build_docs() { + local language="$1" + local version=$(sh build.sh get-version) + + local xcodebuild_arguments="--objc,Realm/Realm.h,--,-x,objective-c,-isysroot,$(xcrun --show-sdk-path),-I,$(pwd)" + local module="Realm" + local objc="--objc" + + if [[ "$language" == "swift" ]]; then + sh build.sh set-swift-version + xcodebuild_arguments="-scheme,RealmSwift" + module="RealmSwift" + objc="" + fi + + touch Realm/RLMPlatform.h # jazzy will fail if it can't find all public header files + jazzy \ + ${objc} \ + --clean \ + --author Realm \ + --author_url https://realm.io \ + --github_url https://github.com/realm/realm-cocoa \ + --github-file-prefix https://github.com/realm/realm-cocoa/tree/v${version} \ + --module-version ${version} \ + --xcodebuild-arguments ${xcodebuild_arguments} \ + --module ${module} \ + --root-url https://realm.io/docs/${language}/${version}/api/ \ + --output docs/${language}_output \ + --head "$(cat docs/custom_head.html)" + + rm Realm/RLMPlatform.h +} + +###################################### +# Input Validation +###################################### + +if [ "$#" -eq 0 -o "$#" -gt 3 ]; then + usage + exit 1 +fi + +###################################### +# Downloading +###################################### + +copy_core() { + local src="$1" + if [ -d .git ]; then + git clean -xfdq core + else + rm -r core + mkdir core + fi + ditto "$src" core + + # XCFramework processing only copies the "realm" headers, so put the third-party ones in a known location + mkdir -p core/include + find "$src" -name external -exec ditto "{}" core/include/external \; -quit +} + +download_common() { + local download_type="$1" tries_left=3 version url error kind suffix + + if [ "$2" = xcframework ]; then + kind='-xcframework' + suffix='-xcframework' + else + kind='-cocoa' + suffix='' + fi + + if [ "$download_type" == "core" ]; then + version=$REALM_CORE_VERSION + url="${REALM_BASE_URL}/core/realm-core${kind}-${version}.tar.xz" + elif [ "$download_type" == "sync" ]; then + version=$REALM_SYNC_VERSION + url="${REALM_BASE_URL}/sync/realm-sync${kind}-${version}.tar.xz" + else + echo "Unknown dowload_type: $download_type" + exit 1 + fi + + # First check if we need to do anything + if [ -e core/version.txt ]; then + if [ "$(cat core/version.txt)" == "$version" ]; then + echo "Version ${version} already present" + exit 0 + else + echo "Switching from version $(cat core/version.txt) to ${version}" + fi + else + if [ "$(find core -name librealm-sync.a)" ]; then + echo 'Using existing custom core build without checking version' + exit 0 + fi + fi + + # We may already have this version downloaded and just need to set it as + # the active one + local versioned_dir="${download_type}-${version}${suffix}" + if [ -e "$versioned_dir/version.txt" ]; then + echo "Setting ${version} as the active version" + copy_core "$versioned_dir" + exit 0 + fi + + echo "Downloading dependency: ${download_type} ${version} from ${url}" + + if [ -z "$TMPDIR" ]; then + TMPDIR='/tmp' + fi + local temp_dir=$(dirname "$TMPDIR/waste")/realm-${download_type}-tmp + mkdir -p "$temp_dir" + local tar_path="${temp_dir}/${versioned_dir}.tar.xz" + local temp_path="${tar_path}.tmp" + + while [ 0 -lt $tries_left ] && [ ! -f "$tar_path" ]; do + if ! error=$(/usr/bin/curl --fail --silent --show-error --location "$url" --output "$temp_path" 2>&1); then + tries_left=$[$tries_left-1] + else + mv "$temp_path" "$tar_path" + fi + done + + if [ ! -f "$tar_path" ]; then + printf "Downloading ${download_type} failed:\n\t$url\n\t$error\n" + exit 1 + fi + + ( + cd "$temp_dir" + rm -rf core + tar xf "$tar_path" --xz + if [ ! -f core/version.txt ]; then + printf %s "${version}" > core/version.txt + fi + + # Xcode 11 dsymutil crashes when given debugging symbols created by + # Xcode 12. Check if this breaks, and strip them if so. + local test_lib=core/realm-sync-dbg.xcframework/ios-*-simulator/librealm-sync-dbg.a + if ! [ -f $test_lib ]; then + test_lib="core/librealm-sync-ios-dbg.a" + fi + clang++ -Wl,-all_load -g -arch x86_64 -shared -target ios13.0 \ + -isysroot $(xcrun --sdk iphonesimulator --show-sdk-path) -o tmp.dylib \ + $test_lib -lz -framework Security + if ! dsymutil tmp.dylib -o tmp.dSYM 2> /dev/null; then + find core -name '*.a' -exec strip -x "{}" \; 2> /dev/null + fi + rm -r tmp.dylib tmp.dSYM + + mv core "${versioned_dir}" + ) + + rm -rf "${versioned_dir}" + mv "${temp_dir}/${versioned_dir}" . + copy_core "$versioned_dir" +} + +###################################### +# Variables +###################################### + +COMMAND="$1" + +# Use Debug config if command ends with -debug, otherwise default to Release +case "$COMMAND" in + *-debug) + COMMAND="${COMMAND%-debug}" + CONFIGURATION="Debug" + ;; +esac +export CONFIGURATION=${CONFIGURATION:-Release} + +# Pre-choose Xcode and Swift versions for those operations that do not set them +REALM_XCODE_VERSION=${xcode_version:-$REALM_XCODE_VERSION} +REALM_SWIFT_VERSION=${swift_version:-$REALM_SWIFT_VERSION} +source "${source_root}/scripts/swift-version.sh" +set_xcode_and_swift_versions + +###################################### +# Commands +###################################### + +case "$COMMAND" in + + ###################################### + # Clean + ###################################### + "clean") + find . -type d -name build -exec rm -r "{}" + + exit 0 + ;; + + ###################################### + # Core + ###################################### + "download-core") + download_common "core" "$2" + exit 0 + ;; + + ###################################### + # Sync + ###################################### + "download-sync") + download_common "sync" "$2" + exit 0 + ;; + + ###################################### + # Swift versioning + ###################################### + "set-swift-version") + version=${2:-$REALM_SWIFT_VERSION} + + SWIFT_VERSION_FILE="RealmSwift/SwiftVersion.swift" + CONTENTS="let swiftLanguageVersion = \"$version\"" + if [ ! -f "$SWIFT_VERSION_FILE" ] || ! grep -q "$CONTENTS" "$SWIFT_VERSION_FILE"; then + echo "$CONTENTS" > "$SWIFT_VERSION_FILE" + fi + + exit 0 + ;; + + "prelaunch-simulator") + if [ -z "$REALM_SKIP_PRELAUNCH" ]; then + sh ${source_root}/scripts/reset-simulators.sh "$1" + fi + ;; + + ###################################### + # Building + ###################################### + "build") + sh build.sh ios-static + sh build.sh ios-dynamic + sh build.sh ios-swift + sh build.sh watchos + sh build.sh watchos-swift + sh build.sh tvos + sh build.sh tvos-swift + sh build.sh osx + sh build.sh osx-swift + exit 0 + ;; + + "ios-static") + build_combined 'Realm iOS static' Realm iphoneos iphonesimulator "-static" + exit 0 + ;; + + "ios-dynamic") + build_combined Realm Realm iphoneos iphonesimulator + exit 0 + ;; + + "ios-swift") + sh build.sh ios-dynamic + build_combined RealmSwift RealmSwift iphoneos iphonesimulator '' "/swift-$REALM_XCODE_VERSION" + copy_realm_framework ios + exit 0 + ;; + + "watchos") + build_combined Realm Realm watchos watchsimulator + exit 0 + ;; + + "watchos-swift") + sh build.sh watchos + build_combined RealmSwift RealmSwift watchos watchsimulator '' "/swift-$REALM_XCODE_VERSION" + copy_realm_framework watchos + exit 0 + ;; + + "tvos") + build_combined Realm Realm appletvos appletvsimulator + exit 0 + ;; + + "tvos-swift") + sh build.sh tvos + build_combined RealmSwift RealmSwift appletvos appletvsimulator '' "/swift-$REALM_XCODE_VERSION" + copy_realm_framework tvos + exit 0 + ;; + + "osx") + xc "-scheme Realm -configuration $CONFIGURATION" + clean_retrieve "build/DerivedData/Realm/Build/Products/$CONFIGURATION/Realm.framework" "build/osx" "Realm.framework" + exit 0 + ;; + + "osx-swift") + sh build.sh osx + xc "-scheme 'RealmSwift' -configuration $CONFIGURATION build" + destination="build/osx/swift-$REALM_XCODE_VERSION" + clean_retrieve "build/DerivedData/Realm/Build/Products/$CONFIGURATION/RealmSwift.framework" "$destination" "RealmSwift.framework" + clean_retrieve "build/osx/Realm.framework" "$destination" "Realm.framework" + exit 0 + ;; + + "catalyst") + export REALM_SDKROOT=iphoneos + xc "-scheme Realm -configuration $CONFIGURATION -destination variant='Mac Catalyst'" + clean_retrieve "build/DerivedData/Realm/Build/Products/$CONFIGURATION-maccatalyst/Realm.framework" "build/catalyst" "Realm.framework" + ;; + + "catalyst-swift") + sh build.sh catalyst + export REALM_SDKROOT=iphoneos + xc "-scheme 'RealmSwift' -configuration $CONFIGURATION -destination variant='Mac Catalyst' build" + destination="build/catalyst/swift-$REALM_XCODE_VERSION" + clean_retrieve "build/DerivedData/Realm/Build/Products/$CONFIGURATION-maccatalyst/RealmSwift.framework" "$destination" "RealmSwift.framework" + clean_retrieve "build/catalyst/Realm.framework" "$destination" "Realm.framework" + ;; + + "xcframework") + export REALM_EXTRA_BUILD_ARGUMENTS="$REALM_EXTRA_BUILD_ARGUMENTS BUILD_LIBRARY_FOR_DISTRIBUTION=YES REALM_OBJC_MACH_O_TYPE=staticlib OTHER_LDFLAGS=-ObjC" + + # Build all of the requested frameworks + shift + PLATFORMS="${*:-osx ios watchos tvos catalyst}" + for platform in $PLATFORMS; do + sh build.sh $platform-swift + done + + # Assemble them into xcframeworks + rm -rf build/*.xcframework + find build/DerivedData/Realm/Build/Products -name 'Realm.framework' \ + | grep -v '\-static' \ + | sed 's/.*/-framework &/' \ + | xargs xcodebuild -create-xcframework -output build/Realm.xcframework + find build/DerivedData/Realm/Build/Products -name 'RealmSwift.framework' \ + | sed 's/.*/-framework &/' \ + | xargs xcodebuild -create-xcframework -output build/RealmSwift.xcframework + + # strip-frameworks.sh isn't needed with xcframeworks since we don't + # lipo together device/simulator libs + find build/Realm.xcframework -name 'strip-frameworks.sh' -delete + find build/RealmSwift.xcframework -name 'strip-frameworks.sh' -delete + + # swiftinterface files currently have incorrect name resolution which + # results in the RealmSwift.Realm class name clashing with the Realm + # module name. Work around this by renaming the Realm module to + # RealmObjc. This is safe to do with a pre-built library because the + # module name is unrelated to what symbols are exported by an obj-c + # library, and we're statically linking the obj-c library into the + # swift library so it doesn't need to be loaded at runtime. + cd build + cp -R Realm.xcframework RealmObjc.xcframework + find RealmObjc.xcframework -name 'Realm.framework' \ + -execdir mv {} RealmObjc.framework \; || true 2> /dev/null + find RealmObjc.xcframework -name '*.h' \ + -exec sed -i '' 's/Realm\//RealmObjc\//' {} \; + find RealmObjc.xcframework -name 'module.modulemap' \ + -exec sed -i '' 's/module Realm/module RealmObjc/' {} \; + sed -i '' 's/Realm.framework/RealmObjc.framework/' RealmObjc.xcframework/Info.plist + + find RealmSwift.xcframework -name '*.swiftinterface' \ + -exec sed -i '' 's/import Realm/import RealmObjc/' {} \; \ + -exec sed -i '' 's/Realm.RLM/RealmObjc.RLM/g' {} \; \ + -exec sed -i '' 's/Realm.RealmSwift/RealmObjc.RealmSwift/g' {} \; \ + + # Realm is statically linked into RealmSwift so we no longer actually + # need the obj-c static library, and just need the framework shell. + # Remove everything but placeholder.o so that there's still a library + # to link against that just doesn't define any symbols. + find RealmObjc.xcframework -name 'Realm' | while read file; do + ( + cd $(dirname $file) + if readlink Realm > /dev/null; then + ln -sf Versions/Current/RealmObjc Realm + elif lipo -info Realm | grep -q 'Non-fat'; then + ar -t Realm | grep -v placeholder | tr '\n' '\0' | xargs -0 ar -d Realm >/dev/null 2>&1 + ranlib Realm >/dev/null 2>&1 + else + for arch in $(lipo -info Realm | cut -f3 -d':'); do + lipo Realm -thin $arch -output tmp.a + ar -t tmp.a | grep -v placeholder | tr '\n' '\0' | xargs -0 ar -d tmp.a >/dev/null 2>&1 + ranlib tmp.a >/dev/null 2>&1 + lipo Realm -replace $arch tmp.a -output Realm + rm tmp.a + done + fi + mv Realm RealmObjc + ) + done + + # We built Realm.framework as a static framework so that we could link + # it into RealmSwift.framework and not have to deal with the runtime + # implications of renaming the shared library, but we want the end + # result to be that Realm.xcframework is a dynamic framework. Our build + # system isn't really set up to build both static and dynamic versions + # of it, so instead just turn each of the static libraries in + # Realm.xcframework into a shared library. + cd Realm.xcframework + i=0 + while plist_get Info.plist "AvailableLibraries:$i" > /dev/null; do + arch_dir_name="$(plist_get Info.plist "AvailableLibraries:$i:LibraryIdentifier")" + platform="$(plist_get Info.plist "AvailableLibraries:$i:SupportedPlatform")" + variant="$(plist_get Info.plist "AvailableLibraries:$i:SupportedPlatformVariant" 2> /dev/null || echo 'os')" + deployment_target_name="$platform" + install_name='@rpath/Realm.framework/Realm' + bitcode_flag='-fembed-bitcode' + if [ "$variant" = 'simulator' ]; then + bitcode_flag='' + elif [ "$variant" = 'maccatalyst' ]; then + platform='macos' + fi + case "$platform" in + "macos") sdk='macosx'; install_name='@rpath/Realm.framework/Versions/A/Realm'; bitcode_flag='';; + "ios") sdk="iphone$variant"; deployment_target_name='iphoneos';; + "watchos") sdk="watch$variant";; + "tvos") sdk="appletv$variant";; + esac + if [ "$variant" = 'maccatalyst' ]; then + target='x86_64-apple-ios13.0-macabi' + else + deployment_target=$(grep -i "$deployment_target_name.*_DEPLOYMENT_TARGET" ../../Configuration/Base.xcconfig \ + | sed 's/.*= \(.*\);/\1/') + target="${platform}${deployment_target}" + fi + + architectures="" + j=0 + while plist_get Info.plist "AvailableLibraries:$i:SupportedArchitectures:$j" > /dev/null; do + architectures="${architectures} -arch $(plist_get Info.plist "AvailableLibraries:$i:SupportedArchitectures:$j")" + j=$(($j + 1)) + done + + ( + cd $arch_dir_name/Realm.framework + realm_lib=$(readlink Realm || echo 'Realm') + # feature_token.cpp.o depends on PKey, which isn't actually + # present in the macOS build of the sync library. This normally + # works fine because we never reference any symbols from + # feature_token.cpp.o so it doesn't get pulled in at all, but + # -all_load makes every object file in the input get linked + # into the shared library. + ar -d $realm_lib feature_token.cpp.o 2> /dev/null || true + clang++ -shared $architectures \ + -target ${target} \ + -isysroot $(xcrun --sdk ${sdk} --show-sdk-path) \ + -install_name "$install_name" \ + -compatibility_version 1 -current_version 1 \ + -fapplication-extension \ + $bitcode_flag \ + -Wl,-all_load \ + -Wl,-unexported_symbol,'__Z*' \ + -o realm.dylib \ + Realm -lz + mv realm.dylib $realm_lib + ) + + i=$(($i + 1)) + done + + exit 0 + ;; + + ###################################### + # Analysis + ###################################### + + "analyze-osx") + xc "-scheme Realm -configuration $CONFIGURATION analyze" + exit 0 + ;; + + ###################################### + # Testing + ###################################### + "test") + set +e # Run both sets of tests even if the first fails + failed=0 + sh build.sh test-ios-static || failed=1 + sh build.sh test-ios-dynamic || failed=1 + sh build.sh test-ios-swift || failed=1 + sh build.sh test-ios-devices || failed=1 + sh build.sh test-tvos-devices || failed=1 + sh build.sh test-osx || failed=1 + sh build.sh test-osx-swift || failed=1 + sh build.sh test-catalyst || failed=1 + sh build.sh test-catalyst-swift || failed=1 + exit $failed + ;; + + "test-all") + set +e + failed=0 + sh build.sh test || failed=1 + sh build.sh test-debug || failed=1 + exit $failed + ;; + + "test-ios-static") + test_ios_static "name=iPhone 8" + exit 0 + ;; + + "test-ios-dynamic") + xc "-scheme Realm -configuration $CONFIGURATION -sdk iphonesimulator -destination 'name=iPhone 8' build-for-testing" + xc "-scheme Realm -configuration $CONFIGURATION -sdk iphonesimulator -destination 'name=iPhone 8' test" + exit 0 + ;; + + "test-ios-swift") + xc "-scheme RealmSwift -configuration $CONFIGURATION -sdk iphonesimulator -destination 'name=iPhone 8' build-for-testing" + xc "-scheme RealmSwift -configuration $CONFIGURATION -sdk iphonesimulator -destination 'name=iPhone 8' test" + exit 0 + ;; + + "test-ios-devices") + failed=0 + trap "failed=1" ERR + sh build.sh test-ios-devices-objc + sh build.sh test-ios-devices-swift + exit $failed + ;; + + "test-ios-devices-objc") + test_devices iphoneos "Realm" "$CONFIGURATION" + exit $? + ;; + + "test-ios-devices-swift") + test_devices iphoneos "RealmSwift" "$CONFIGURATION" + exit $? + ;; + + "test-tvos") + destination="Apple TV" + xctest "-scheme Realm -configuration $CONFIGURATION -sdk appletvsimulator -destination 'name=$destination'" + exit $? + ;; + + "test-tvos-swift") + destination="Apple TV" + xctest "-scheme RealmSwift -configuration $CONFIGURATION -sdk appletvsimulator -destination 'name=$destination'" + exit $? + ;; + + "test-tvos-devices") + test_devices appletvos TestHost "$CONFIGURATION" + ;; + + "test-osx") + COVERAGE_PARAMS="" + if [[ "$CONFIGURATION" == "Debug" ]]; then + COVERAGE_PARAMS="GCC_GENERATE_TEST_COVERAGE_FILES=YES GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES" + fi + xctest "-scheme Realm -configuration $CONFIGURATION $COVERAGE_PARAMS" + exit 0 + ;; + + "test-osx-swift") + xctest "-scheme RealmSwift -configuration $CONFIGURATION" + exit 0 + ;; + + "test-osx-object-server") + xctest "-scheme 'Object Server Tests' -configuration $CONFIGURATION -sdk macosx" + exit 0 + ;; + + test-swiftpm-ios) + cd examples/installation + sh build.sh test-ios-swift-spm + exit 0 + ;; + + test-swiftpm*) + SANITIZER=$(echo $COMMAND | cut -d - -f 3) + if [ -n "$SANITIZER" ]; then + SANITIZER="--sanitize $SANITIZER" + export ASAN_OPTIONS='check_initialization_order=true:detect_stack_use_after_return=true' + fi + xcrun swift package resolve + find .build -name views.cpp -delete + xcrun swift test --configuration $(echo $CONFIGURATION | tr "[:upper:]" "[:lower:]") $SANITIZER + exit 0 + ;; + + "test-catalyst") + export REALM_SDKROOT=iphoneos + xc "-scheme Realm -configuration $CONFIGURATION -destination 'platform=macOS,variant=Mac Catalyst' CODE_SIGN_IDENTITY='' build-for-testing" + xc "-scheme Realm -configuration $CONFIGURATION -destination 'platform=macOS,variant=Mac Catalyst' CODE_SIGN_IDENTITY='' test" + exit 0 + ;; + + "test-catalyst-swift") + export REALM_SDKROOT=iphoneos + xc "-scheme RealmSwift -configuration $CONFIGURATION -destination 'platform=macOS,variant=Mac Catalyst' CODE_SIGN_IDENTITY='' build-for-testing" + xc "-scheme RealmSwift -configuration $CONFIGURATION -destination 'platform=macOS,variant=Mac Catalyst' CODE_SIGN_IDENTITY='' test" + exit 0 + ;; + + ###################################### + # Full verification + ###################################### + "verify") + sh build.sh verify-cocoapods + sh build.sh verify-docs + sh build.sh verify-osx + sh build.sh verify-osx-debug + sh build.sh verify-osx-swift + sh build.sh verify-osx-swift-debug + sh build.sh verify-ios-static + sh build.sh verify-ios-static-debug + sh build.sh verify-ios-dynamic + sh build.sh verify-ios-dynamic-debug + sh build.sh verify-ios-swift + sh build.sh verify-ios-swift-debug + sh build.sh verify-ios-device-objc + sh build.sh verify-ios-device-swift + sh build.sh verify-watchos + sh build.sh verify-tvos + sh build.sh verify-tvos-debug + sh build.sh verify-tvos-device + sh build.sh verify-swiftlint + sh build.sh verify-swiftpm + sh build.sh verify-osx-object-server + sh build.sh verify-catalyst + sh build.sh verify-catalyst-swift + ;; + + "verify-cocoapods") + if [[ -d .git ]]; then + # Verify the current branch, unless one was already specified in the sha environment variable. + if [[ -z $sha ]]; then + export sha=$(git rev-parse --abbrev-ref HEAD) + fi + + if [[ $(git log -1 @{push}..) != "" ]] || ! git diff-index --quiet HEAD; then + echo "WARNING: verify-cocoapods will test the latest revision of $sha found on GitHub." + echo " Any unpushed local changes will not be tested." + echo "" + sleep 1 + fi + fi + + sh build.sh verify-cocoapods-ios + sh build.sh verify-cocoapods-ios-dynamic + sh build.sh verify-cocoapods-osx + sh build.sh verify-cocoapods-watchos + + # https://github.com/CocoaPods/CocoaPods/issues/7708 + export EXPANDED_CODE_SIGN_IDENTITY='' + cd examples/installation + sh build.sh test-ios-objc-cocoapods + sh build.sh test-ios-objc-cocoapods-dynamic + sh build.sh test-ios-swift-cocoapods + sh build.sh test-osx-objc-cocoapods + sh build.sh test-osx-swift-cocoapods + sh build.sh test-watchos-objc-cocoapods + sh build.sh test-watchos-swift-cocoapods + ;; + + verify-cocoapods-ios-dynamic) + PLATFORM=$(echo $COMMAND | cut -d - -f 3) + # https://github.com/CocoaPods/CocoaPods/issues/7708 + export EXPANDED_CODE_SIGN_IDENTITY='' + cd examples/installation + sh build.sh test-ios-objc-cocoapods-dynamic + ;; + + verify-cocoapods-*) + PLATFORM=$(echo $COMMAND | cut -d - -f 3) + # https://github.com/CocoaPods/CocoaPods/issues/7708 + export EXPANDED_CODE_SIGN_IDENTITY='' + cd examples/installation + sh build.sh test-$PLATFORM-swift-cocoapods + ;; + + "verify-osx-encryption") + REALM_ENCRYPT_ALL=YES sh build.sh test-osx + exit 0 + ;; + + "verify-osx") + REALM_EXTRA_BUILD_ARGUMENTS="$REALM_EXTRA_BUILD_ARGUMENTS -workspace examples/osx/objc/RealmExamples.xcworkspace" \ + sh build.sh test-osx + sh build.sh examples-osx + + ( + cd examples/osx/objc/build/DerivedData/RealmExamples/Build/Products/$CONFIGURATION + DYLD_FRAMEWORK_PATH=. ./JSONImport >/dev/null + ) + exit 0 + ;; + + "verify-osx-swift") + sh build.sh test-osx-swift + exit 0 + ;; + + "verify-osx-swift-evolution") + export REALM_EXTRA_BUILD_ARGUMENTS="$REALM_EXTRA_BUILD_ARGUMENTS REALM_BUILD_LIBRARY_FOR_DISTRIBUTION=YES" + sh build.sh test-osx-swift + exit 0 + ;; + + "verify-ios-static") + REALM_EXTRA_BUILD_ARGUMENTS="$REALM_EXTRA_BUILD_ARGUMENTS -workspace examples/ios/objc/RealmExamples.xcworkspace" \ + sh build.sh test-ios-static + sh build.sh examples-ios + ;; + + "verify-ios-dynamic") + sh build.sh test-ios-dynamic + ;; + + "verify-ios-swift") + REALM_EXTRA_BUILD_ARGUMENTS="$REALM_EXTRA_BUILD_ARGUMENTS -workspace examples/ios/swift/RealmExamples.xcworkspace" \ + sh build.sh test-ios-swift + sh build.sh examples-ios-swift + ;; + + "verify-ios-swift-evolution") + export REALM_EXTRA_BUILD_ARGUMENTS="$REALM_EXTRA_BUILD_ARGUMENTS REALM_BUILD_LIBRARY_FOR_DISTRIBUTION=YES" + sh build.sh test-ios-swift + exit 0 + ;; + + "verify-ios-device-objc") + sh build.sh test-ios-devices-objc + exit 0 + ;; + + "verify-ios-device-swift") + sh build.sh test-ios-devices-swift + exit 0 + ;; + + "verify-docs") + sh build.sh docs + for lang in swift objc; do + undocumented="docs/${lang}_output/undocumented.json" + if ruby -rjson -e "j = JSON.parse(File.read('docs/${lang}_output/undocumented.json')); exit j['warnings'].length != 0"; then + echo "Undocumented Realm $lang declarations:" + cat "$undocumented" + exit 1 + fi + done + exit 0 + ;; + + "verify-watchos") + sh build.sh watchos-swift + exit 0 + ;; + + "verify-tvos") + REALM_EXTRA_BUILD_ARGUMENTS="$REALM_EXTRA_BUILD_ARGUMENTS -workspace examples/tvos/objc/RealmExamples.xcworkspace" \ + sh build.sh test-tvos + sh build.sh examples-tvos + exit 0 + ;; + + "verify-tvos-swift") + REALM_EXTRA_BUILD_ARGUMENTS="$REALM_EXTRA_BUILD_ARGUMENTS -workspace examples/tvos/swift/RealmExamples.xcworkspace" \ + sh build.sh test-tvos-swift + sh build.sh examples-tvos-swift + exit 0 + ;; + + "verify-tvos-swift-evolution") + export REALM_EXTRA_BUILD_ARGUMENTS="$REALM_EXTRA_BUILD_ARGUMENTS REALM_BUILD_LIBRARY_FOR_DISTRIBUTION=YES" + sh build.sh test-tvos-swift + exit 0 + ;; + + "verify-tvos-device") + sh build.sh test-tvos-devices + exit 0 + ;; + + "verify-swiftlint") + swiftlint lint --strict + exit 0 + ;; + + verify-swiftpm*) + sh build.sh test-$(echo $COMMAND | cut -d - -f 2-) + exit 0 + ;; + + "verify-osx-object-server") + sh build.sh test-osx-object-server + exit 0 + ;; + + "verify-catalyst") + sh build.sh test-catalyst + exit 0 + ;; + + "verify-catalyst-swift") + sh build.sh test-catalyst-swift + exit 0 + ;; + + "verify-xcframework") + sh build.sh xcframework + exit 0 + ;; + + ###################################### + # Docs + ###################################### + "docs") + build_docs objc + build_docs swift + exit 0 + ;; + + ###################################### + # Examples + ###################################### + "examples") + sh build.sh clean + sh build.sh prelaunch-simulator + export REALM_SKIP_PRELAUNCH=1 + sh build.sh examples-ios + sh build.sh examples-ios-swift + sh build.sh examples-osx + sh build.sh examples-tvos + sh build.sh examples-tvos-swift + exit 0 + ;; + + "examples-ios") + workspace="examples/ios/objc/RealmExamples.xcworkspace" + pod install --project-directory="$workspace/.." --no-repo-update + examples="Simple TableView Migration Backlink GroupedTableView RACTableView Encryption Draw" + for example in $examples; do + xc "-workspace $workspace -scheme $example -configuration $CONFIGURATION -sdk iphonesimulator build ARCHS=x86_64 ${CODESIGN_PARAMS}" + done + if [ ! -z "${JENKINS_HOME}" ]; then + xc "-workspace $workspace -scheme Extension -configuration $CONFIGURATION -sdk iphonesimulator build ARCHS=x86_64 ${CODESIGN_PARAMS}" + fi + + exit 0 + ;; + + "examples-ios-swift") + workspace="examples/ios/swift/RealmExamples.xcworkspace" + if [[ ! -d "$workspace" ]]; then + workspace="${workspace/swift/swift-$REALM_XCODE_VERSION}" + fi + + examples="Simple TableView Migration Backlink GroupedTableView Encryption" + for example in $examples; do + xc "-workspace $workspace -scheme $example -configuration $CONFIGURATION -sdk iphonesimulator build ARCHS=x86_64 ${CODESIGN_PARAMS}" + done + + exit 0 + ;; + + "examples-osx") + xc "-workspace examples/osx/objc/RealmExamples.xcworkspace -scheme JSONImport -configuration ${CONFIGURATION} build ${CODESIGN_PARAMS}" + ;; + + "examples-tvos") + workspace="examples/tvos/objc/RealmExamples.xcworkspace" + examples="DownloadCache PreloadedData" + for example in $examples; do + xc "-workspace $workspace -scheme $example -configuration $CONFIGURATION -sdk appletvsimulator build ARCHS=x86_64 ${CODESIGN_PARAMS}" + done + + exit 0 + ;; + + "examples-tvos-swift") + workspace="examples/tvos/swift/RealmExamples.xcworkspace" + if [[ ! -d "$workspace" ]]; then + workspace="${workspace/swift/swift-$REALM_XCODE_VERSION}" + fi + examples="DownloadCache PreloadedData" + for example in $examples; do + xc "-workspace $workspace -scheme $example -configuration $CONFIGURATION -sdk appletvsimulator build ARCHS=x86_64 ${CODESIGN_PARAMS}" + done + + exit 0 + ;; + + ###################################### + # Versioning + ###################################### + "get-version") + echo "$(plist_get 'Realm/Realm-Info.plist' 'CFBundleShortVersionString')" + exit 0 + ;; + + "set-version") + realm_version="$2" + version_files="Realm/Realm-Info.plist" + + if [ -z "$realm_version" ]; then + echo "You must specify a version." + exit 1 + fi + # The bundle version can contain only three groups of digits separated by periods, + # so strip off any -beta.x tag from the end of the version string. + bundle_version=$(echo "$realm_version" | cut -d - -f 1) + for version_file in $version_files; do + PlistBuddy -c "Set :CFBundleVersion $bundle_version" "$version_file" + PlistBuddy -c "Set :CFBundleShortVersionString $realm_version" "$version_file" + done + sed -i '' "s/^VERSION=.*/VERSION=$realm_version/" dependencies.list + sed -i '' "s/^let coreVersionStr =.*/let coreVersionStr = \"$REALM_CORE_VERSION\"/" Package.swift + sed -i '' "s/^let cocoaVersionStr =.*/let cocoaVersionStr = \"$realm_version\"/" Package.swift + sed -i '' "s/x.y.z Release notes (yyyy-MM-dd)/$realm_version Release notes ($(date '+%Y-%m-%d'))/" CHANGELOG.md + + exit 0 + ;; + + ###################################### + # Bitcode Detection + ###################################### + + "binary-has-bitcode") + # Disable pipefail as grep -q will make otool fail due to exiting + # before reading all the output + set +o pipefail + + BINARY="$2" + if otool -l "$BINARY" | grep -q "segname __LLVM"; then + exit 0 + fi + # Work around rdar://21826157 by checking for bitcode in thin binaries + + # Get architectures for binary + archs="$(lipo -info "$BINARY" | rev | cut -d ':' -f1 | rev)" + + archs_array=( $archs ) + if [[ ${#archs_array[@]} -lt 2 ]]; then + echo 'Error: Built library is not a fat binary' + exit 1 # Early exit if not a fat binary + fi + + TEMPDIR=$(mktemp -d $TMPDIR/realm-bitcode-check.XXXX) + + for arch in $archs; do + lipo -thin "$arch" "$BINARY" -output "$TEMPDIR/$arch" + if otool -l "$TEMPDIR/$arch" | grep -q "segname __LLVM"; then + exit 0 + fi + done + echo 'Error: Built library does not contain bitcode' + exit 1 + ;; + + ###################################### + # CocoaPods + ###################################### + "cocoapods-setup") + if [[ "$2" != "swift" ]]; then + if [ ! -d Realm/ObjectStore/src ]; then + cat >&2 < Realm/RLMPlatform.h + cp Realm/*.h include + else + sh build.sh set-swift-version + fi + ;; + + ###################################### + # Continuous Integration + ###################################### + + "ci-pr") + mkdir -p build/reports + export REALM_DISABLE_ANALYTICS=1 + export REALM_DISABLE_UPDATE_CHECKER=1 + # FIXME: Re-enable once CI can properly unlock the keychain + export REALM_DISABLE_METADATA_ENCRYPTION=1 + + # strip off the ios|tvos version specifier, e.g. the last part of: `ios-device-objc-ios8` + if [[ "$target" =~ ^((ios|tvos)-device(-(objc|swift))?)(-(ios|tvos)[[:digit:]]+)?$ ]]; then + export target=${BASH_REMATCH[1]} + fi + + if [ "$target" = "docs" ]; then + sh build.sh set-swift-version + sh build.sh verify-docs + elif [ "$target" = "swiftlint" ]; then + sh build.sh verify-swiftlint + else + export sha=$GITHUB_PR_SOURCE_BRANCH + export CONFIGURATION=$configuration + export REALM_EXTRA_BUILD_ARGUMENTS='GCC_GENERATE_DEBUGGING_SYMBOLS=NO -allowProvisioningUpdates' + if [[ "$target" = *ios* ]] || [[ "$target" = *tvos* ]] || [[ "$target" = *watchos* ]]; then + sh build.sh prelaunch-simulator "$target" + fi + export REALM_SKIP_PRELAUNCH=1 + + if [[ "$target" = *"server"* ]]; then + source $(brew --prefix nvm)/nvm.sh --no-use + export REALM_NODE_PATH="$(nvm which 10)" + fi + + # Reset CoreSimulator.log + mkdir -p ~/Library/Logs/CoreSimulator + echo > ~/Library/Logs/CoreSimulator/CoreSimulator.log + + if [ -d ~/Library/Developer/CoreSimulator/Devices/ ]; then + # Verify that no Realm files still exist + ! find ~/Library/Developer/CoreSimulator/Devices/ -name '*.realm' | grep -q . + fi + + failed=0 + sh build.sh verify-$target 2>&1 | tee build/build.log | xcpretty -r junit -o build/reports/junit.xml || failed=1 + if [ "$failed" = "1" ] && cat build/build.log | grep -E 'DTXProxyChannel|DTXChannel|out of date and needs to be rebuilt|operation never finished bootstrapping'; then + echo "Known Xcode error detected. Running job again." + if cat build/build.log | grep -E 'out of date and needs to be rebuilt'; then + rm -rf build/DerivedData + fi + failed=0 + sh build.sh verify-$target | tee build/build.log | xcpretty -r junit -o build/reports/junit.xml || failed=1 + elif [ "$failed" = "1" ] && tail ~/Library/Logs/CoreSimulator/CoreSimulator.log | grep -E "Operation not supported|Failed to lookup com.apple.coreservices.lsuseractivity.simulatorsupport"; then + echo "Known Xcode error detected. Running job again." + failed=0 + sh build.sh verify-$target | tee build/build.log | xcpretty -r junit -o build/reports/junit.xml || failed=1 + fi + if [ "$failed" = "1" ]; then + echo "\n\n***\nbuild/build.log\n***\n\n" && cat build/build.log || true + echo "\n\n***\nCoreSimulator.log\n***\n\n" && cat ~/Library/Logs/CoreSimulator/CoreSimulator.log + exit 1 + fi + fi + + if [ "$target" = "osx" ] && [ "$configuration" = "Debug" ]; then + gcovr -r . -f ".*Realm.*" -e ".*Tests.*" -e ".*core.*" --xml > build/reports/coverage-report.xml + WS=$(pwd | sed "s/\//\\\\\//g") + sed -i ".bak" "s/\./${WS}/" build/reports/coverage-report.xml + fi + ;; + + ###################################### + # Release packaging + ###################################### + + "package-examples") + ./scripts/package_examples.rb + zip --symlinks -r realm-examples.zip examples -x "examples/installation/*" + ;; + + "package-test-examples-objc") + if ! VERSION=$(echo realm-objc-*.zip | egrep -o '\d*\.\d*\.\d*-[a-z]*(\.\d*)?'); then + VERSION=$(echo realm-objc-*.zip | egrep -o '\d*\.\d*\.\d*') + fi + OBJC="realm-objc-${VERSION}" + unzip ${OBJC}.zip + + cp $0 ${OBJC} + cp -r ${source_root}/scripts ${OBJC} + cd ${OBJC} + sh build.sh examples-ios + sh build.sh examples-tvos + sh build.sh examples-osx + cd .. + rm -rf ${OBJC} + ;; + + "package-test-examples-swift") + if ! VERSION=$(echo realm-swift-*.zip | egrep -o '\d*\.\d*\.\d*-[a-z]*(\.\d*)?'); then + VERSION=$(echo realm-swift-*.zip | egrep -o '\d*\.\d*\.\d*') + fi + SWIFT="realm-swift-${VERSION}" + unzip ${SWIFT}.zip + + cp $0 ${SWIFT} + cp -r ${source_root}/scripts ${SWIFT} + cd ${SWIFT} + sh build.sh examples-ios-swift + sh build.sh examples-tvos-swift + cd .. + rm -rf ${SWIFT} + ;; + + "package-ios-static") + sh build.sh prelaunch-simulator + sh build.sh ios-static + + cd build/ios-static + zip --symlinks -r realm-framework-ios-static.zip Realm.framework + ;; + + "package") + PLATFORM="$2" + REALM_SWIFT_VERSION= + + set_xcode_and_swift_versions + + sh build.sh $PLATFORM-swift + + cd build/$PLATFORM + zip --symlinks -r realm-framework-$PLATFORM-$REALM_XCODE_VERSION.zip swift-$REALM_XCODE_VERSION + ;; + + "package-release") + LANG="$2" + TEMPDIR=$(mktemp -d $TMPDIR/realm-release-package-${LANG}.XXXX) + + VERSION=$(sh build.sh get-version) + + FOLDER=${TEMPDIR}/realm-${LANG}-${VERSION} + + mkdir -p ${FOLDER}/osx ${FOLDER}/ios ${FOLDER}/watchos ${FOLDER}/tvos + + if [[ "${LANG}" == "objc" ]]; then + mkdir -p ${FOLDER}/ios/static + mkdir -p ${FOLDER}/ios/dynamic + mkdir -p ${FOLDER}/Swift + + unzip ${WORKSPACE}/realm-framework-ios-static.zip -d ${FOLDER}/ios/static + for platform in osx ios watchos tvos catalyst; do + unzip ${WORKSPACE}/realm-framework-${platform}-${REALM_XCODE_VERSION}.zip -d ${FOLDER}/${platform} + mv ${FOLDER}/${platform}/swift-*/Realm.framework ${FOLDER}/${platform} + rm -r ${FOLDER}/${platform}/swift-* + done + + mv ${FOLDER}/ios/Realm.framework ${FOLDER}/ios/dynamic + else + for platform in osx ios watchos tvos catalyst; do + find ${WORKSPACE} -name "realm-framework-$platform-*.zip" \ + -maxdepth 1 \ + -exec unzip {} -d ${FOLDER}/${platform} \; + done + fi + + ( + cd ${WORKSPACE} + cp -R plugin ${FOLDER} + cp LICENSE ${FOLDER}/LICENSE.txt + if [[ "${LANG}" == "objc" ]]; then + cp Realm/Swift/RLMSupport.swift ${FOLDER}/Swift/ + fi + ) + + ( + cd ${FOLDER} + unzip ${WORKSPACE}/realm-examples.zip + cd examples + if [[ "${LANG}" == "objc" ]]; then + rm -rf ios/swift-* tvos/swift-* + else + rm -rf ios/objc ios/rubymotion osx tvos/objc + fi + ) + + cat > ${FOLDER}/docs.webloc < + + + + URL + https://realm.io/docs/${LANG}/${VERSION} + + +EOF + + ( + cd ${TEMPDIR} + zip --symlinks -r realm-${LANG}-${VERSION}.zip realm-${LANG}-${VERSION} + mv realm-${LANG}-${VERSION}.zip ${WORKSPACE} + ) + ;; + + "test-package-release") + # Generate a release package locally for testing purposes + # Real releases should always be done via Jenkins + if [ -z "${WORKSPACE}" ]; then + echo 'WORKSPACE must be set to a directory to assemble the release in' + exit 1 + fi + if [ -d "${WORKSPACE}" ]; then + echo 'WORKSPACE directory should not already exist' + exit 1 + fi + + REALM_SOURCE="$(pwd)" + mkdir -p "$WORKSPACE" + WORKSPACE="$(cd "$WORKSPACE" && pwd)" + export WORKSPACE + cd $WORKSPACE + git clone --recursive $REALM_SOURCE realm-cocoa + cd realm-cocoa + + echo 'Packaging iOS' + sh build.sh package-ios-static + cp build/ios-static/realm-framework-ios-static.zip . + sh build.sh package ios + cp build/ios/realm-framework-ios-$REALM_XCODE_VERSION.zip . + + echo 'Packaging macOS' + sh build.sh package osx + cp build/osx/realm-framework-osx-$REALM_XCODE_VERSION.zip . + + echo 'Packaging watchOS' + sh build.sh package watchos + cp build/watchos/realm-framework-watchos-$REALM_XCODE_VERSION.zip . + + echo 'Packaging tvOS' + sh build.sh package tvos + cp build/tvos/realm-framework-tvos-$REALM_XCODE_VERSION.zip . + + echo 'Packaging Catalyst' + sh build.sh package catalyst + cp build/catalyst/realm-framework-catalyst-$REALM_XCODE_VERSION.zip . + + echo 'Packaging examples' + sh build.sh package-examples + + echo 'Building final release packages' + export WORKSPACE="${WORKSPACE}/realm-cocoa" + sh build.sh package-release objc + sh build.sh package-release swift + + echo 'Testing packaged examples' + sh build.sh package-test-examples-objc + sh build.sh package-test-examples-swift + ;; + + "github-release") + if [ -z "${GITHUB_ACCESS_TOKEN}" ]; then + echo 'GITHUB_ACCESS_TOKEN must be set to create GitHub releases' + exit 1 + fi + ./scripts/github_release.rb + ;; + + "add-empty-changelog") + empty_section=$(cat < ([#????](https://github.com/realm/realm-cocoa/issues/????), since v?.?.?) +* None. + + + +### Compatibility +* Realm Studio: 10.0.0 or later. +* APIs are backwards compatible with all previous releases in the 10.x.y series. +* Carthage release for Swift is built with Xcode 12.1. +* CocoaPods: 1.10 or later. + +### Internal +* Upgraded realm-core from ? to ? +* Upgraded realm-sync from ? to ? + +EOS) + changelog=$(cat CHANGELOG.md) + echo "$empty_section" > CHANGELOG.md + echo >> CHANGELOG.md + echo "$changelog" >> CHANGELOG.md + ;; + + *) + echo "Unknown command '$COMMAND'" + usage + exit 1 + ;; +esac diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/Info.plist b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/Info.plist new file mode 100644 index 0000000..0fc7ab3 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/Info.plist @@ -0,0 +1,124 @@ + + + + + AvailableLibraries + + + HeadersPath + Headers + LibraryIdentifier + macos-x86_64 + LibraryPath + librealm-sync.a + SupportedArchitectures + x86_64 + SupportedPlatform + macos + + + HeadersPath + Headers + LibraryIdentifier + ios-armv7_arm64 + LibraryPath + librealm-sync.a + SupportedArchitectures + armv7 +arm64 + SupportedPlatform + ios + + + HeadersPath + Headers + LibraryIdentifier + ios-arm64_i386_x86_64-simulator + LibraryPath + librealm-sync.a + SupportedArchitectures + arm64 +i386 +x86_64 + SupportedPlatform + ios + SupportedPlatformVariant + simulator + + + HeadersPath + Headers + LibraryIdentifier + ios-x86_64-maccatalyst + LibraryPath + librealm-sync.a + SupportedArchitectures + x86_64 + SupportedPlatform + ios + SupportedPlatformVariant + maccatalyst + + + HeadersPath + Headers + LibraryIdentifier + watchos-armv7k_arm64_32 + LibraryPath + librealm-sync.a + SupportedArchitectures + armv7k +arm64_32 + SupportedPlatform + watchos + + + HeadersPath + Headers + LibraryIdentifier + watchos-arm64_i386_x86_64-simulator + LibraryPath + librealm-sync.a + SupportedArchitectures + arm64 +i386 +x86_64 + SupportedPlatform + watchos + SupportedPlatformVariant + simulator + + + HeadersPath + Headers + LibraryIdentifier + tvos-arm64 + LibraryPath + librealm-sync.a + SupportedArchitectures + arm64 + SupportedPlatform + tvos + + + HeadersPath + Headers + LibraryIdentifier + tvos-arm64_x86_64-simulator + LibraryPath + librealm-sync.a + SupportedArchitectures + arm64 +x86_64 + SupportedPlatform + tvos + SupportedPlatformVariant + simulator + + + CFBundlePackageType + XFWK + XCFrameworkFormatVersion + 1.0 + + diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/external/mpark/variant.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/external/mpark/variant.hpp new file mode 100644 index 0000000..2354ca3 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/external/mpark/variant.hpp @@ -0,0 +1,2819 @@ +// MPark.Variant +// +// Copyright Michael Park, 2015-2017 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#ifndef MPARK_VARIANT_HPP +#define MPARK_VARIANT_HPP + +/* + variant synopsis + +namespace std { + + // 20.7.2, class template variant + template + class variant { + public: + + // 20.7.2.1, constructors + constexpr variant() noexcept(see below); + variant(const variant&); + variant(variant&&) noexcept(see below); + + template constexpr variant(T&&) noexcept(see below); + + template + constexpr explicit variant(in_place_type_t, Args&&...); + + template + constexpr explicit variant( + in_place_type_t, initializer_list, Args&&...); + + template + constexpr explicit variant(in_place_index_t, Args&&...); + + template + constexpr explicit variant( + in_place_index_t, initializer_list, Args&&...); + + // 20.7.2.2, destructor + ~variant(); + + // 20.7.2.3, assignment + variant& operator=(const variant&); + variant& operator=(variant&&) noexcept(see below); + + template variant& operator=(T&&) noexcept(see below); + + // 20.7.2.4, modifiers + template + T& emplace(Args&&...); + + template + T& emplace(initializer_list, Args&&...); + + template + variant_alternative& emplace(Args&&...); + + template + variant_alternative& emplace(initializer_list, Args&&...); + + // 20.7.2.5, value status + constexpr bool valueless_by_exception() const noexcept; + constexpr size_t index() const noexcept; + + // 20.7.2.6, swap + void swap(variant&) noexcept(see below); + }; + + // 20.7.3, variant helper classes + template struct variant_size; // undefined + + template + constexpr size_t variant_size_v = variant_size::value; + + template struct variant_size; + template struct variant_size; + template struct variant_size; + + template + struct variant_size>; + + template struct variant_alternative; // undefined + + template + using variant_alternative_t = typename variant_alternative::type; + + template struct variant_alternative; + template struct variant_alternative; + template struct variant_alternative; + + template + struct variant_alternative>; + + constexpr size_t variant_npos = -1; + + // 20.7.4, value access + template + constexpr bool holds_alternative(const variant&) noexcept; + + template + constexpr variant_alternative_t>& + get(variant&); + + template + constexpr variant_alternative_t>&& + get(variant&&); + + template + constexpr variant_alternative_t> const& + get(const variant&); + + template + constexpr variant_alternative_t> const&& + get(const variant&&); + + template + constexpr T& get(variant&); + + template + constexpr T&& get(variant&&); + + template + constexpr const T& get(const variant&); + + template + constexpr const T&& get(const variant&&); + + template + constexpr add_pointer_t>> + get_if(variant*) noexcept; + + template + constexpr add_pointer_t>> + get_if(const variant*) noexcept; + + template + constexpr add_pointer_t + get_if(variant*) noexcept; + + template + constexpr add_pointer_t + get_if(const variant*) noexcept; + + // 20.7.5, relational operators + template + constexpr bool operator==(const variant&, const variant&); + + template + constexpr bool operator!=(const variant&, const variant&); + + template + constexpr bool operator<(const variant&, const variant&); + + template + constexpr bool operator>(const variant&, const variant&); + + template + constexpr bool operator<=(const variant&, const variant&); + + template + constexpr bool operator>=(const variant&, const variant&); + + // 20.7.6, visitation + template + constexpr see below visit(Visitor&&, Variants&&...); + + // 20.7.7, class monostate + struct monostate; + + // 20.7.8, monostate relational operators + constexpr bool operator<(monostate, monostate) noexcept; + constexpr bool operator>(monostate, monostate) noexcept; + constexpr bool operator<=(monostate, monostate) noexcept; + constexpr bool operator>=(monostate, monostate) noexcept; + constexpr bool operator==(monostate, monostate) noexcept; + constexpr bool operator!=(monostate, monostate) noexcept; + + // 20.7.9, specialized algorithms + template + void swap(variant&, variant&) noexcept(see below); + + // 20.7.10, class bad_variant_access + class bad_variant_access; + + // 20.7.11, hash support + template struct hash; + template struct hash>; + template <> struct hash; + +} // namespace std + +*/ + +#include +#include +#include +#include +#include +#include +#include + +// MPark.Variant +// +// Copyright Michael Park, 2015-2017 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#ifndef MPARK_CONFIG_HPP +#define MPARK_CONFIG_HPP + +// MSVC 2015 Update 3. +#if __cplusplus < 201103L && (!defined(_MSC_VER) || _MSC_FULL_VER < 190024210) +#error "MPark.Variant requires C++11 support." +#endif + +#ifndef __has_attribute +#define __has_attribute(x) 0 +#endif + +#ifndef __has_builtin +#define __has_builtin(x) 0 +#endif + +#ifndef __has_include +#define __has_include(x) 0 +#endif + +#ifndef __has_feature +#define __has_feature(x) 0 +#endif + +#if __has_attribute(always_inline) || defined(__GNUC__) +#define MPARK_ALWAYS_INLINE __attribute__((__always_inline__)) inline +#elif defined(_MSC_VER) +#define MPARK_ALWAYS_INLINE __forceinline +#else +#define MPARK_ALWAYS_INLINE inline +#endif + +#if __has_builtin(__builtin_addressof) || \ + (defined(__GNUC__) && __GNUC__ >= 7) || defined(_MSC_VER) +#define MPARK_BUILTIN_ADDRESSOF +#endif + +#if __has_builtin(__builtin_unreachable) || defined(__GNUC__) +#define MPARK_BUILTIN_UNREACHABLE __builtin_unreachable() +#elif defined(_MSC_VER) +#define MPARK_BUILTIN_UNREACHABLE __assume(false) +#else +#define MPARK_BUILTIN_UNREACHABLE +#endif + +#if __has_builtin(__type_pack_element) +#define MPARK_TYPE_PACK_ELEMENT +#endif + +#if defined(__cpp_constexpr) && __cpp_constexpr >= 200704 && \ + !(defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 9) +#define MPARK_CPP11_CONSTEXPR +#endif + +#if defined(__cpp_constexpr) && __cpp_constexpr >= 201304 +#define MPARK_CPP14_CONSTEXPR +#endif + +#if __has_feature(cxx_exceptions) || defined(__cpp_exceptions) || \ + (defined(_MSC_VER) && defined(_CPPUNWIND)) +#define MPARK_EXCEPTIONS +#endif + +#if defined(__cpp_generic_lambdas) || defined(_MSC_VER) +#define MPARK_GENERIC_LAMBDAS +#endif + +#if defined(__cpp_lib_integer_sequence) +#define MPARK_INTEGER_SEQUENCE +#endif + +#if defined(__cpp_return_type_deduction) || defined(_MSC_VER) +#define MPARK_RETURN_TYPE_DEDUCTION +#endif + +#if defined(__cpp_lib_transparent_operators) || defined(_MSC_VER) +#define MPARK_TRANSPARENT_OPERATORS +#endif + +#if defined(__cpp_variable_templates) || defined(_MSC_VER) +#define MPARK_VARIABLE_TEMPLATES +#endif + +#if !defined(__GLIBCXX__) || __has_include() // >= libstdc++-5 +#define MPARK_TRIVIALITY_TYPE_TRAITS +#define MPARK_INCOMPLETE_TYPE_TRAITS +#endif + +#endif // MPARK_CONFIG_HPP + +// MPark.Variant +// +// Copyright Michael Park, 2015-2017 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#ifndef MPARK_IN_PLACE_HPP +#define MPARK_IN_PLACE_HPP + +#include + + +namespace mpark { + + struct in_place_t { explicit in_place_t() = default; }; + + template + struct in_place_index_t { explicit in_place_index_t() = default; }; + + template + struct in_place_type_t { explicit in_place_type_t() = default; }; + +#ifdef MPARK_VARIABLE_TEMPLATES + constexpr in_place_t in_place{}; + + template constexpr in_place_index_t in_place_index{}; + + template constexpr in_place_type_t in_place_type{}; +#endif + +} // namespace mpark + +#endif // MPARK_IN_PLACE_HPP + +// MPark.Variant +// +// Copyright Michael Park, 2015-2017 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#ifndef MPARK_LIB_HPP +#define MPARK_LIB_HPP + +#include +#include +#include +#include + + +#define MPARK_RETURN(...) \ + noexcept(noexcept(__VA_ARGS__)) -> decltype(__VA_ARGS__) { return __VA_ARGS__; } + +namespace mpark { + namespace lib { + template + struct identity { using type = T; }; + + inline namespace cpp14 { + template + struct array { + constexpr const T &operator[](std::size_t index) const { + return data[index]; + } + + T data[N == 0 ? 1 : N]; + }; + + template + using add_pointer_t = typename std::add_pointer::type; + + template + using common_type_t = typename std::common_type::type; + + template + using decay_t = typename std::decay::type; + + template + using enable_if_t = typename std::enable_if::type; + + template + using remove_const_t = typename std::remove_const::type; + + template + using remove_reference_t = typename std::remove_reference::type; + + template + inline constexpr T &&forward(remove_reference_t &t) noexcept { + return static_cast(t); + } + + template + inline constexpr T &&forward(remove_reference_t &&t) noexcept { + static_assert(!std::is_lvalue_reference::value, + "can not forward an rvalue as an lvalue"); + return static_cast(t); + } + + template + inline constexpr remove_reference_t &&move(T &&t) noexcept { + return static_cast &&>(t); + } + +#ifdef MPARK_INTEGER_SEQUENCE + using std::integer_sequence; + using std::index_sequence; + using std::make_index_sequence; + using std::index_sequence_for; +#else + template + struct integer_sequence { + using value_type = T; + static constexpr std::size_t size() noexcept { return sizeof...(Is); } + }; + + template + using index_sequence = integer_sequence; + + template + struct make_index_sequence_concat; + + template + struct make_index_sequence_concat, + index_sequence> + : identity> {}; + + template + struct make_index_sequence_impl; + + template + using make_index_sequence = typename make_index_sequence_impl::type; + + template + struct make_index_sequence_impl + : make_index_sequence_concat, + make_index_sequence> {}; + + template <> + struct make_index_sequence_impl<0> : identity> {}; + + template <> + struct make_index_sequence_impl<1> : identity> {}; + + template + using index_sequence_for = make_index_sequence; +#endif + + // +#ifdef MPARK_TRANSPARENT_OPERATORS + using equal_to = std::equal_to<>; +#else + struct equal_to { + template + inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const + MPARK_RETURN(lib::forward(lhs) == lib::forward(rhs)) + }; +#endif + +#ifdef MPARK_TRANSPARENT_OPERATORS + using not_equal_to = std::not_equal_to<>; +#else + struct not_equal_to { + template + inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const + MPARK_RETURN(lib::forward(lhs) != lib::forward(rhs)) + }; +#endif + +#ifdef MPARK_TRANSPARENT_OPERATORS + using less = std::less<>; +#else + struct less { + template + inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const + MPARK_RETURN(lib::forward(lhs) < lib::forward(rhs)) + }; +#endif + +#ifdef MPARK_TRANSPARENT_OPERATORS + using greater = std::greater<>; +#else + struct greater { + template + inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const + MPARK_RETURN(lib::forward(lhs) > lib::forward(rhs)) + }; +#endif + +#ifdef MPARK_TRANSPARENT_OPERATORS + using less_equal = std::less_equal<>; +#else + struct less_equal { + template + inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const + MPARK_RETURN(lib::forward(lhs) <= lib::forward(rhs)) + }; +#endif + +#ifdef MPARK_TRANSPARENT_OPERATORS + using greater_equal = std::greater_equal<>; +#else + struct greater_equal { + template + inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const + MPARK_RETURN(lib::forward(lhs) >= lib::forward(rhs)) + }; +#endif + } // namespace cpp14 + + inline namespace cpp17 { + + // + template + using bool_constant = std::integral_constant; + + template + struct voider : identity {}; + + template + using void_t = typename voider::type; + + namespace detail { + namespace swappable { + + using std::swap; + + template + struct is_swappable { + private: + template (), + std::declval()))> + inline static std::true_type test(int); + + template + inline static std::false_type test(...); + + public: + static constexpr bool value = decltype(test(0))::value; + }; + + template + struct is_nothrow_swappable { + static constexpr bool value = + noexcept(swap(std::declval(), std::declval())); + }; + + template + struct is_nothrow_swappable : std::false_type {}; + + } // namespace swappable + } // namespace detail + + using detail::swappable::is_swappable; + + template + using is_nothrow_swappable = + detail::swappable::is_nothrow_swappable::value, T>; + + // + namespace detail { + + template + struct is_reference_wrapper : std::false_type {}; + + template + struct is_reference_wrapper> + : std::true_type {}; + + template + struct Invoke; + + template <> + struct Invoke { + template + inline static constexpr auto invoke(R T::*pmf, Arg &&arg, Args &&... args) + MPARK_RETURN((lib::forward(arg).*pmf)(lib::forward(args)...)) + }; + + template <> + struct Invoke { + template + inline static constexpr auto invoke(R T::*pmf, Arg &&arg, Args &&... args) + MPARK_RETURN((lib::forward(arg).get().*pmf)(lib::forward(args)...)) + }; + + template <> + struct Invoke { + template + inline static constexpr auto invoke(R T::*pmf, Arg &&arg, Args &&... args) + MPARK_RETURN(((*lib::forward(arg)).*pmf)(lib::forward(args)...)) + }; + + template <> + struct Invoke { + template + inline static constexpr auto invoke(R T::*pmo, Arg &&arg) + MPARK_RETURN(lib::forward(arg).*pmo) + }; + + template <> + struct Invoke { + template + inline static constexpr auto invoke(R T::*pmo, Arg &&arg) + MPARK_RETURN(lib::forward(arg).get().*pmo) + }; + + template <> + struct Invoke { + template + inline static constexpr auto invoke(R T::*pmo, Arg &&arg) + MPARK_RETURN((*lib::forward(arg)).*pmo) + }; + + template + inline constexpr auto invoke(R T::*f, Arg &&arg, Args &&... args) + MPARK_RETURN( + Invoke::value, + (std::is_base_of>::value + ? 0 + : is_reference_wrapper>::value + ? 1 + : 2)>::invoke(f, + lib::forward(arg), + lib::forward(args)...)) + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4100) +#endif + template + inline constexpr auto invoke(F &&f, Args &&... args) + MPARK_RETURN(lib::forward(f)(lib::forward(args)...)) +#ifdef _MSC_VER +#pragma warning(pop) +#endif + } // namespace detail + + template + inline constexpr auto invoke(F &&f, Args &&... args) + MPARK_RETURN(detail::invoke(lib::forward(f), + lib::forward(args)...)) + + namespace detail { + + template + struct invoke_result {}; + + template + struct invoke_result(), std::declval()...))>, + F, + Args...> + : identity(), std::declval()...))> {}; + + } // namespace detail + + template + using invoke_result = detail::invoke_result; + + template + using invoke_result_t = typename invoke_result::type; + + namespace detail { + + template + struct is_invocable : std::false_type {}; + + template + struct is_invocable>, F, Args...> + : std::true_type {}; + + template + struct is_invocable_r : std::false_type {}; + + template + struct is_invocable_r>, + R, + F, + Args...> + : std::is_convertible, R> {}; + + } // namespace detail + + template + using is_invocable = detail::is_invocable; + + template + using is_invocable_r = detail::is_invocable_r; + + namespace detail { + + template + struct is_nothrow_invocable { + static constexpr bool value = + noexcept(lib::invoke(std::declval(), std::declval()...)); + }; + + template + struct is_nothrow_invocable : std::false_type {}; + + template + struct is_nothrow_invocable_r { + private: + inline static R impl() { + return lib::invoke(std::declval(), std::declval()...); + } + + public: + static constexpr bool value = noexcept(impl()); + }; + + template + struct is_nothrow_invocable_r : std::false_type {}; + + } // namespace detail + + template + using is_nothrow_invocable = detail:: + is_nothrow_invocable::value, F, Args...>; + + template + using is_nothrow_invocable_r = + detail::is_nothrow_invocable_r::value, + R, + F, + Args...>; + + // +#ifdef MPARK_BUILTIN_ADDRESSOF + template + inline constexpr T *addressof(T &arg) noexcept { + return __builtin_addressof(arg); + } +#else + namespace detail { + + namespace has_addressof_impl { + + struct fail; + + template + inline fail operator&(T &&); + + template + inline static constexpr bool impl() { + return (std::is_class::value || std::is_union::value) && + !std::is_same()), fail>::value; + } + + } // namespace has_addressof_impl + + template + using has_addressof = bool_constant()>; + + template + inline constexpr T *addressof(T &arg, std::true_type) noexcept { + return std::addressof(arg); + } + + template + inline constexpr T *addressof(T &arg, std::false_type) noexcept { + return &arg; + } + + } // namespace detail + + template + inline constexpr T *addressof(T &arg) noexcept { + return detail::addressof(arg, detail::has_addressof{}); + } +#endif + + template + inline constexpr T *addressof(const T &&) = delete; + + } // namespace cpp17 + + template + struct remove_all_extents : identity {}; + + template + struct remove_all_extents> : remove_all_extents {}; + + template + using remove_all_extents_t = typename remove_all_extents::type; + + template + using size_constant = std::integral_constant; + + template + struct indexed_type : size_constant { using type = T; }; + + template + using all = std::is_same, + integer_sequence>; + +#ifdef MPARK_TYPE_PACK_ELEMENT + template + using type_pack_element_t = __type_pack_element; +#else + template + struct type_pack_element_impl { + private: + template + struct set; + + template + struct set> : indexed_type... {}; + + template + inline static std::enable_if impl(indexed_type); + + inline static std::enable_if impl(...); + + public: + using type = decltype(impl(set>{})); + }; + + template + using type_pack_element = typename type_pack_element_impl::type; + + template + using type_pack_element_t = typename type_pack_element::type; +#endif + +#ifdef MPARK_TRIVIALITY_TYPE_TRAITS + using std::is_trivially_copy_constructible; + using std::is_trivially_move_constructible; + using std::is_trivially_copy_assignable; + using std::is_trivially_move_assignable; +#else + template + struct is_trivially_copy_constructible + : bool_constant< + std::is_copy_constructible::value && __has_trivial_copy(T)> {}; + + template + struct is_trivially_move_constructible : bool_constant<__is_trivial(T)> {}; + + template + struct is_trivially_copy_assignable + : bool_constant< + std::is_copy_assignable::value && __has_trivial_assign(T)> {}; + + template + struct is_trivially_move_assignable : bool_constant<__is_trivial(T)> {}; +#endif + + template + struct dependent_type : T {}; + + template + struct push_back; + + template + using push_back_t = typename push_back::type; + + template + struct push_back, J> { + using type = index_sequence; + }; + + } // namespace lib +} // namespace mpark + +#undef MPARK_RETURN + +#endif // MPARK_LIB_HPP + + +namespace mpark { + +#ifdef MPARK_RETURN_TYPE_DEDUCTION + +#define AUTO auto +#define AUTO_RETURN(...) { return __VA_ARGS__; } + +#define AUTO_REFREF auto && +#define AUTO_REFREF_RETURN(...) { return __VA_ARGS__; } + +#define DECLTYPE_AUTO decltype(auto) +#define DECLTYPE_AUTO_RETURN(...) { return __VA_ARGS__; } + +#else + +#define AUTO auto +#define AUTO_RETURN(...) \ + -> lib::decay_t { return __VA_ARGS__; } + +#define AUTO_REFREF auto +#define AUTO_REFREF_RETURN(...) \ + -> decltype((__VA_ARGS__)) { \ + static_assert(std::is_reference::value, ""); \ + return __VA_ARGS__; \ + } + +#define DECLTYPE_AUTO auto +#define DECLTYPE_AUTO_RETURN(...) \ + -> decltype(__VA_ARGS__) { return __VA_ARGS__; } + +#endif + + class bad_variant_access : public std::exception { + public: + virtual const char *what() const noexcept override { return "bad_variant_access"; } + }; + + [[noreturn]] inline void throw_bad_variant_access() { +#ifdef MPARK_EXCEPTIONS + throw bad_variant_access{}; +#else + std::terminate(); + MPARK_BUILTIN_UNREACHABLE; +#endif + } + + template + class variant; + + template + struct variant_size; + +#ifdef MPARK_VARIABLE_TEMPLATES + template + constexpr std::size_t variant_size_v = variant_size::value; +#endif + + template + struct variant_size : variant_size {}; + + template + struct variant_size : variant_size {}; + + template + struct variant_size : variant_size {}; + + template + struct variant_size> : lib::size_constant {}; + + template + struct variant_alternative; + + template + using variant_alternative_t = typename variant_alternative::type; + + template + struct variant_alternative + : std::add_const> {}; + + template + struct variant_alternative + : std::add_volatile> {}; + + template + struct variant_alternative + : std::add_cv> {}; + + template + struct variant_alternative> { + static_assert(I < sizeof...(Ts), + "index out of bounds in `std::variant_alternative<>`"); + using type = lib::type_pack_element_t; + }; + + constexpr std::size_t variant_npos = static_cast(-1); + + namespace detail { + + constexpr std::size_t not_found = static_cast(-1); + constexpr std::size_t ambiguous = static_cast(-2); + +#ifdef MPARK_CPP14_CONSTEXPR + template + inline constexpr std::size_t find_index() { + constexpr lib::array matches = { + {std::is_same::value...} + }; + std::size_t result = not_found; + for (std::size_t i = 0; i < sizeof...(Ts); ++i) { + if (matches[i]) { + if (result != not_found) { + return ambiguous; + } + result = i; + } + } + return result; + } +#else + inline constexpr std::size_t find_index_impl(std::size_t result, + std::size_t) { + return result; + } + + template + inline constexpr std::size_t find_index_impl(std::size_t result, + std::size_t idx, + bool b, + Bs... bs) { + return b ? (result != not_found ? ambiguous + : find_index_impl(idx, idx + 1, bs...)) + : find_index_impl(result, idx + 1, bs...); + } + + template + inline constexpr std::size_t find_index() { + return find_index_impl(not_found, 0, std::is_same::value...); + } +#endif + + template + using find_index_sfinae_impl = + lib::enable_if_t>; + + template + using find_index_sfinae = find_index_sfinae_impl()>; + + template + struct find_index_checked_impl : lib::size_constant { + static_assert(I != not_found, "the specified type is not found."); + static_assert(I != ambiguous, "the specified type is ambiguous."); + }; + + template + using find_index_checked = find_index_checked_impl()>; + + struct valueless_t {}; + + enum class Trait { TriviallyAvailable, Available, Unavailable }; + + template class IsTriviallyAvailable, + template class IsAvailable> + inline constexpr Trait trait() { + return IsTriviallyAvailable::value + ? Trait::TriviallyAvailable + : IsAvailable::value ? Trait::Available + : Trait::Unavailable; + } + +#ifdef MPARK_CPP14_CONSTEXPR + template + inline constexpr Trait common_trait(Traits... traits_) { + Trait result = Trait::TriviallyAvailable; + lib::array traits = {{traits_...}}; + for (std::size_t i = 0; i < sizeof...(Traits); ++i) { + Trait t = traits[i]; + if (static_cast(t) > static_cast(result)) { + result = t; + } + } + return result; + } +#else + inline constexpr Trait common_trait_impl(Trait result) { return result; } + + template + inline constexpr Trait common_trait_impl(Trait result, + Trait t, + Traits... ts) { + return static_cast(t) > static_cast(result) + ? common_trait_impl(t, ts...) + : common_trait_impl(result, ts...); + } + + template + inline constexpr Trait common_trait(Traits... ts) { + return common_trait_impl(Trait::TriviallyAvailable, ts...); + } +#endif + + template + struct traits { + static constexpr Trait copy_constructible_trait = + common_trait(trait()...); + + static constexpr Trait move_constructible_trait = + common_trait(trait()...); + + static constexpr Trait copy_assignable_trait = + common_trait(copy_constructible_trait, + trait()...); + + static constexpr Trait move_assignable_trait = + common_trait(move_constructible_trait, + trait()...); + + static constexpr Trait destructible_trait = + common_trait(trait()...); + }; + + namespace access { + + struct recursive_union { +#ifdef MPARK_RETURN_TYPE_DEDUCTION + template + inline static constexpr auto &&get_alt(V &&v, in_place_index_t<0>) { + return lib::forward(v).head_; + } + + template + inline static constexpr auto &&get_alt(V &&v, in_place_index_t) { + return get_alt(lib::forward(v).tail_, in_place_index_t{}); + } +#else + template + struct get_alt_impl { + template + inline constexpr AUTO_REFREF operator()(V &&v) const + AUTO_REFREF_RETURN(get_alt_impl{}(lib::forward(v).tail_)) + }; + + template + struct get_alt_impl<0, Dummy> { + template + inline constexpr AUTO_REFREF operator()(V &&v) const + AUTO_REFREF_RETURN(lib::forward(v).head_) + }; + + template + inline static constexpr AUTO_REFREF get_alt(V &&v, in_place_index_t) + AUTO_REFREF_RETURN(get_alt_impl{}(lib::forward(v))) +#endif + }; + + struct base { + template + inline static constexpr AUTO_REFREF get_alt(V &&v) +#ifdef _MSC_VER + AUTO_REFREF_RETURN(recursive_union::get_alt( + lib::forward(v).data_, in_place_index_t{})) +#else + AUTO_REFREF_RETURN(recursive_union::get_alt( + data(lib::forward(v)), in_place_index_t{})) +#endif + }; + + struct variant { + template + inline static constexpr AUTO_REFREF get_alt(V &&v) + AUTO_REFREF_RETURN(base::get_alt(lib::forward(v).impl_)) + }; + + } // namespace access + + namespace visitation { + +#if defined(MPARK_CPP14_CONSTEXPR) && !defined(_MSC_VER) +#define MPARK_VARIANT_SWITCH_VISIT +#endif + + struct base { + template + using dispatch_result_t = decltype( + lib::invoke(std::declval(), + access::base::get_alt<0>(std::declval())...)); + + template + struct expected { + template + inline static constexpr bool but_got() { + return std::is_same::value; + } + }; + + template + struct visit_return_type_check { + static_assert( + expected::template but_got(), + "`visit` requires the visitor to have a single return type"); + + template + inline static constexpr DECLTYPE_AUTO invoke(Visitor &&visitor, + Alts &&... alts) + DECLTYPE_AUTO_RETURN(lib::invoke(lib::forward(visitor), + lib::forward(alts)...)) + }; + +#ifdef MPARK_VARIANT_SWITCH_VISIT + template + struct dispatcher; + + template + struct dispatcher { + template + MPARK_ALWAYS_INLINE static constexpr R dispatch( + F &&, typename ITs::type &&..., Vs &&...) { + MPARK_BUILTIN_UNREACHABLE; + } + + template + MPARK_ALWAYS_INLINE static constexpr R dispatch_case(F &&, Vs &&...) { + MPARK_BUILTIN_UNREACHABLE; + } + + template + MPARK_ALWAYS_INLINE static constexpr R dispatch_at(std::size_t, + F &&, + Vs &&...) { + MPARK_BUILTIN_UNREACHABLE; + } + }; + + template + struct dispatcher { + template + MPARK_ALWAYS_INLINE static constexpr R dispatch( + F &&f, typename ITs::type &&... visited_vs) { + using Expected = R; + using Actual = decltype(lib::invoke( + lib::forward(f), + access::base::get_alt( + lib::forward(visited_vs))...)); + return visit_return_type_check::invoke( + lib::forward(f), + access::base::get_alt( + lib::forward(visited_vs))...); + } + + template + MPARK_ALWAYS_INLINE static constexpr R dispatch( + F &&f, typename ITs::type &&... visited_vs, V &&v, Vs &&... vs) { +#define MPARK_DISPATCH(I) \ + dispatcher<(I < lib::decay_t::size()), \ + R, \ + ITs..., \ + lib::indexed_type>:: \ + template dispatch<0>(lib::forward(f), \ + lib::forward(visited_vs)..., \ + lib::forward(v), \ + lib::forward(vs)...) + +#define MPARK_DEFAULT(I) \ + dispatcher<(I < lib::decay_t::size()), R, ITs...>::template dispatch( \ + lib::forward(f), \ + lib::forward(visited_vs)..., \ + lib::forward(v), \ + lib::forward(vs)...) + + switch (v.index()) { + case B + 0: return MPARK_DISPATCH(B + 0); + case B + 1: return MPARK_DISPATCH(B + 1); + case B + 2: return MPARK_DISPATCH(B + 2); + case B + 3: return MPARK_DISPATCH(B + 3); + case B + 4: return MPARK_DISPATCH(B + 4); + case B + 5: return MPARK_DISPATCH(B + 5); + case B + 6: return MPARK_DISPATCH(B + 6); + case B + 7: return MPARK_DISPATCH(B + 7); + case B + 8: return MPARK_DISPATCH(B + 8); + case B + 9: return MPARK_DISPATCH(B + 9); + case B + 10: return MPARK_DISPATCH(B + 10); + case B + 11: return MPARK_DISPATCH(B + 11); + case B + 12: return MPARK_DISPATCH(B + 12); + case B + 13: return MPARK_DISPATCH(B + 13); + case B + 14: return MPARK_DISPATCH(B + 14); + case B + 15: return MPARK_DISPATCH(B + 15); + case B + 16: return MPARK_DISPATCH(B + 16); + case B + 17: return MPARK_DISPATCH(B + 17); + case B + 18: return MPARK_DISPATCH(B + 18); + case B + 19: return MPARK_DISPATCH(B + 19); + case B + 20: return MPARK_DISPATCH(B + 20); + case B + 21: return MPARK_DISPATCH(B + 21); + case B + 22: return MPARK_DISPATCH(B + 22); + case B + 23: return MPARK_DISPATCH(B + 23); + case B + 24: return MPARK_DISPATCH(B + 24); + case B + 25: return MPARK_DISPATCH(B + 25); + case B + 26: return MPARK_DISPATCH(B + 26); + case B + 27: return MPARK_DISPATCH(B + 27); + case B + 28: return MPARK_DISPATCH(B + 28); + case B + 29: return MPARK_DISPATCH(B + 29); + case B + 30: return MPARK_DISPATCH(B + 30); + case B + 31: return MPARK_DISPATCH(B + 31); + default: return MPARK_DEFAULT(B + 32); + } + +#undef MPARK_DEFAULT +#undef MPARK_DISPATCH + } + + template + MPARK_ALWAYS_INLINE static constexpr R dispatch_case(F &&f, + Vs &&... vs) { + using Expected = R; + using Actual = decltype( + lib::invoke(lib::forward(f), + access::base::get_alt(lib::forward(vs))...)); + return visit_return_type_check::invoke( + lib::forward(f), + access::base::get_alt(lib::forward(vs))...); + } + + template + MPARK_ALWAYS_INLINE static constexpr R dispatch_at(std::size_t index, + F &&f, + V &&v, + Vs &&... vs) { + static_assert(lib::all<(lib::decay_t::size() == + lib::decay_t::size())...>::value, + "all of the variants must be the same size."); +#define MPARK_DISPATCH_AT(I) \ + dispatcher<(I < lib::decay_t::size()), R>::template dispatch_case( \ + lib::forward(f), lib::forward(v), lib::forward(vs)...) + +#define MPARK_DEFAULT(I) \ + dispatcher<(I < lib::decay_t::size()), R>::template dispatch_at( \ + index, lib::forward(f), lib::forward(v), lib::forward(vs)...) + + switch (index) { + case B + 0: return MPARK_DISPATCH_AT(B + 0); + case B + 1: return MPARK_DISPATCH_AT(B + 1); + case B + 2: return MPARK_DISPATCH_AT(B + 2); + case B + 3: return MPARK_DISPATCH_AT(B + 3); + case B + 4: return MPARK_DISPATCH_AT(B + 4); + case B + 5: return MPARK_DISPATCH_AT(B + 5); + case B + 6: return MPARK_DISPATCH_AT(B + 6); + case B + 7: return MPARK_DISPATCH_AT(B + 7); + case B + 8: return MPARK_DISPATCH_AT(B + 8); + case B + 9: return MPARK_DISPATCH_AT(B + 9); + case B + 10: return MPARK_DISPATCH_AT(B + 10); + case B + 11: return MPARK_DISPATCH_AT(B + 11); + case B + 12: return MPARK_DISPATCH_AT(B + 12); + case B + 13: return MPARK_DISPATCH_AT(B + 13); + case B + 14: return MPARK_DISPATCH_AT(B + 14); + case B + 15: return MPARK_DISPATCH_AT(B + 15); + case B + 16: return MPARK_DISPATCH_AT(B + 16); + case B + 17: return MPARK_DISPATCH_AT(B + 17); + case B + 18: return MPARK_DISPATCH_AT(B + 18); + case B + 19: return MPARK_DISPATCH_AT(B + 19); + case B + 20: return MPARK_DISPATCH_AT(B + 20); + case B + 21: return MPARK_DISPATCH_AT(B + 21); + case B + 22: return MPARK_DISPATCH_AT(B + 22); + case B + 23: return MPARK_DISPATCH_AT(B + 23); + case B + 24: return MPARK_DISPATCH_AT(B + 24); + case B + 25: return MPARK_DISPATCH_AT(B + 25); + case B + 26: return MPARK_DISPATCH_AT(B + 26); + case B + 27: return MPARK_DISPATCH_AT(B + 27); + case B + 28: return MPARK_DISPATCH_AT(B + 28); + case B + 29: return MPARK_DISPATCH_AT(B + 29); + case B + 30: return MPARK_DISPATCH_AT(B + 30); + case B + 31: return MPARK_DISPATCH_AT(B + 31); + default: return MPARK_DEFAULT(B + 32); + } + +#undef MPARK_DEFAULT +#undef MPARK_DISPATCH_AT + } + }; +#else + template + inline static constexpr const T &at(const T &elem) noexcept { + return elem; + } + + template + inline static constexpr const lib::remove_all_extents_t &at( + const lib::array &elems, std::size_t i, Is... is) noexcept { + return at(elems[i], is...); + } + + template + inline static constexpr lib::array, sizeof...(Fs) + 1> + make_farray(F &&f, Fs &&... fs) { + return {{lib::forward(f), lib::forward(fs)...}}; + } + + template + struct make_fmatrix_impl { + + template + inline static constexpr dispatch_result_t dispatch( + F &&f, Vs &&... vs) { + using Expected = dispatch_result_t; + using Actual = decltype(lib::invoke( + lib::forward(f), + access::base::get_alt(lib::forward(vs))...)); + return visit_return_type_check::invoke( + lib::forward(f), + access::base::get_alt(lib::forward(vs))...); + } + +#ifdef MPARK_RETURN_TYPE_DEDUCTION + template + inline static constexpr auto impl(lib::index_sequence) { + return &dispatch; + } + + template + inline static constexpr auto impl(Is, + lib::index_sequence, + Ls... ls) { + return make_farray(impl(lib::push_back_t{}, ls...)...); + } +#else + template + struct impl; + + template + struct impl> { + inline constexpr AUTO operator()() const + AUTO_RETURN(&dispatch) + }; + + template + struct impl, Ls...> { + inline constexpr AUTO operator()() const + AUTO_RETURN( + make_farray(impl, Ls...>{}()...)) + }; +#endif + }; + +#ifdef MPARK_RETURN_TYPE_DEDUCTION + template + inline static constexpr auto make_fmatrix() { + return make_fmatrix_impl::impl( + lib::index_sequence<>{}, + lib::make_index_sequence::size()>{}...); + } +#else + template + inline static constexpr AUTO make_fmatrix() + AUTO_RETURN( + typename make_fmatrix_impl::template impl< + lib::index_sequence<>, + lib::make_index_sequence::size()>...>{}()) +#endif + + template + struct make_fdiagonal_impl { + template + inline static constexpr dispatch_result_t dispatch( + F &&f, Vs &&... vs) { + using Expected = dispatch_result_t; + using Actual = decltype( + lib::invoke(lib::forward(f), + access::base::get_alt(lib::forward(vs))...)); + return visit_return_type_check::invoke( + lib::forward(f), + access::base::get_alt(lib::forward(vs))...); + } + + template + inline static constexpr AUTO impl(lib::index_sequence) + AUTO_RETURN(make_farray(&dispatch...)) + }; + + template + inline static constexpr auto make_fdiagonal() + -> decltype(make_fdiagonal_impl::impl( + lib::make_index_sequence::size()>{})) { + static_assert(lib::all<(lib::decay_t::size() == + lib::decay_t::size())...>::value, + "all of the variants must be the same size."); + return make_fdiagonal_impl::impl( + lib::make_index_sequence::size()>{}); + } +#endif + }; + +#if !defined(MPARK_VARIANT_SWITCH_VISIT) && \ + (!defined(_MSC_VER) || _MSC_VER >= 1910) + template + using fmatrix_t = decltype(base::make_fmatrix()); + + template + struct fmatrix { + static constexpr fmatrix_t value = + base::make_fmatrix(); + }; + + template + constexpr fmatrix_t fmatrix::value; + + template + using fdiagonal_t = decltype(base::make_fdiagonal()); + + template + struct fdiagonal { + static constexpr fdiagonal_t value = + base::make_fdiagonal(); + }; + + template + constexpr fdiagonal_t fdiagonal::value; +#endif + + struct alt { + template + inline static constexpr DECLTYPE_AUTO visit_alt(Visitor &&visitor, + Vs &&... vs) +#ifdef MPARK_VARIANT_SWITCH_VISIT + DECLTYPE_AUTO_RETURN( + base::dispatcher< + true, + base::dispatch_result_t(vs)))...>>:: + template dispatch<0>(lib::forward(visitor), + as_base(lib::forward(vs))...)) +#elif !defined(_MSC_VER) || _MSC_VER >= 1910 + DECLTYPE_AUTO_RETURN(base::at( + fmatrix(vs)))...>::value, + vs.index()...)(lib::forward(visitor), + as_base(lib::forward(vs))...)) +#else + DECLTYPE_AUTO_RETURN(base::at( + base::make_fmatrix(vs)))...>(), + vs.index()...)(lib::forward(visitor), + as_base(lib::forward(vs))...)) +#endif + + template + inline static constexpr DECLTYPE_AUTO visit_alt_at(std::size_t index, + Visitor &&visitor, + Vs &&... vs) +#ifdef MPARK_VARIANT_SWITCH_VISIT + DECLTYPE_AUTO_RETURN( + base::dispatcher< + true, + base::dispatch_result_t(vs)))...>>:: + template dispatch_at<0>(index, + lib::forward(visitor), + as_base(lib::forward(vs))...)) +#elif !defined(_MSC_VER) || _MSC_VER >= 1910 + DECLTYPE_AUTO_RETURN(base::at( + fdiagonal(vs)))...>::value, + index)(lib::forward(visitor), + as_base(lib::forward(vs))...)) +#else + DECLTYPE_AUTO_RETURN(base::at( + base::make_fdiagonal(vs)))...>(), + index)(lib::forward(visitor), + as_base(lib::forward(vs))...)) +#endif + }; + + struct variant { + private: + template + struct visitor { + template + inline static constexpr bool does_not_handle() { + return lib::is_invocable::value; + } + }; + + template + struct visit_exhaustiveness_check { + static_assert(visitor::template does_not_handle(), + "`visit` requires the visitor to be exhaustive."); + + inline static constexpr DECLTYPE_AUTO invoke(Visitor &&visitor, + Values &&... values) + DECLTYPE_AUTO_RETURN(lib::invoke(lib::forward(visitor), + lib::forward(values)...)) + }; + + template + struct value_visitor { + Visitor &&visitor_; + + template + inline constexpr DECLTYPE_AUTO operator()(Alts &&... alts) const + DECLTYPE_AUTO_RETURN( + visit_exhaustiveness_check< + Visitor, + decltype((lib::forward(alts).value))...>:: + invoke(lib::forward(visitor_), + lib::forward(alts).value...)) + }; + + template + inline static constexpr AUTO make_value_visitor(Visitor &&visitor) + AUTO_RETURN(value_visitor{lib::forward(visitor)}) + + public: + template + inline static constexpr DECLTYPE_AUTO visit_alt(Visitor &&visitor, + Vs &&... vs) + DECLTYPE_AUTO_RETURN(alt::visit_alt(lib::forward(visitor), + lib::forward(vs).impl_...)) + + template + inline static constexpr DECLTYPE_AUTO visit_alt_at(std::size_t index, + Visitor &&visitor, + Vs &&... vs) + DECLTYPE_AUTO_RETURN( + alt::visit_alt_at(index, + lib::forward(visitor), + lib::forward(vs).impl_...)) + + template + inline static constexpr DECLTYPE_AUTO visit_value(Visitor &&visitor, + Vs &&... vs) + DECLTYPE_AUTO_RETURN( + visit_alt(make_value_visitor(lib::forward(visitor)), + lib::forward(vs)...)) + + template + inline static constexpr DECLTYPE_AUTO visit_value_at(std::size_t index, + Visitor &&visitor, + Vs &&... vs) + DECLTYPE_AUTO_RETURN( + visit_alt_at(index, + make_value_visitor(lib::forward(visitor)), + lib::forward(vs)...)) + }; + + } // namespace visitation + + template + struct alt { + using value_type = T; + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4244) +#endif + template + inline explicit constexpr alt(in_place_t, Args &&... args) + : value(lib::forward(args)...) {} +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + T value; + }; + + template + union recursive_union; + + template + union recursive_union {}; + +#define MPARK_VARIANT_RECURSIVE_UNION(destructible_trait, destructor) \ + template \ + union recursive_union { \ + public: \ + inline explicit constexpr recursive_union(valueless_t) noexcept \ + : dummy_{} {} \ + \ + template \ + inline explicit constexpr recursive_union(in_place_index_t<0>, \ + Args &&... args) \ + : head_(in_place_t{}, lib::forward(args)...) {} \ + \ + template \ + inline explicit constexpr recursive_union(in_place_index_t, \ + Args &&... args) \ + : tail_(in_place_index_t{}, lib::forward(args)...) {} \ + \ + recursive_union(const recursive_union &) = default; \ + recursive_union(recursive_union &&) = default; \ + \ + destructor \ + \ + recursive_union &operator=(const recursive_union &) = default; \ + recursive_union &operator=(recursive_union &&) = default; \ + \ + private: \ + char dummy_; \ + alt head_; \ + recursive_union tail_; \ + \ + friend struct access::recursive_union; \ + } + + MPARK_VARIANT_RECURSIVE_UNION(Trait::TriviallyAvailable, + ~recursive_union() = default;); + MPARK_VARIANT_RECURSIVE_UNION(Trait::Available, + ~recursive_union() {}); + MPARK_VARIANT_RECURSIVE_UNION(Trait::Unavailable, + ~recursive_union() = delete;); + +#undef MPARK_VARIANT_RECURSIVE_UNION + + using index_t = unsigned int; + + template + class base { + public: + inline explicit constexpr base(valueless_t tag) noexcept + : data_(tag), index_(static_cast(-1)) {} + + template + inline explicit constexpr base(in_place_index_t, Args &&... args) + : data_(in_place_index_t{}, lib::forward(args)...), + index_(I) {} + + inline constexpr bool valueless_by_exception() const noexcept { + return index_ == static_cast(-1); + } + + inline constexpr std::size_t index() const noexcept { + return valueless_by_exception() ? variant_npos : index_; + } + + protected: + using data_t = recursive_union; + + friend inline constexpr base &as_base(base &b) { return b; } + friend inline constexpr const base &as_base(const base &b) { return b; } + friend inline constexpr base &&as_base(base &&b) { return lib::move(b); } + friend inline constexpr const base &&as_base(const base &&b) { return lib::move(b); } + + friend inline constexpr data_t &data(base &b) { return b.data_; } + friend inline constexpr const data_t &data(const base &b) { return b.data_; } + friend inline constexpr data_t &&data(base &&b) { return lib::move(b).data_; } + friend inline constexpr const data_t &&data(const base &&b) { return lib::move(b).data_; } + + inline static constexpr std::size_t size() { return sizeof...(Ts); } + + data_t data_; + index_t index_; + + friend struct access::base; + friend struct visitation::base; + }; + + struct dtor { +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4100) +#endif + template + inline void operator()(Alt &alt) const noexcept { alt.~Alt(); } +#ifdef _MSC_VER +#pragma warning(pop) +#endif + }; + +#if !defined(_MSC_VER) || _MSC_VER >= 1910 +#define MPARK_INHERITING_CTOR(type, base) using base::base; +#else +#define MPARK_INHERITING_CTOR(type, base) \ + template \ + inline explicit constexpr type(Args &&... args) \ + : base(lib::forward(args)...) {} +#endif + + template + class destructor; + +#define MPARK_VARIANT_DESTRUCTOR(destructible_trait, definition, destroy) \ + template \ + class destructor, destructible_trait> \ + : public base { \ + using super = base; \ + \ + public: \ + MPARK_INHERITING_CTOR(destructor, super) \ + using super::operator=; \ + \ + destructor(const destructor &) = default; \ + destructor(destructor &&) = default; \ + definition \ + destructor &operator=(const destructor &) = default; \ + destructor &operator=(destructor &&) = default; \ + \ + protected: \ + destroy \ + } + + MPARK_VARIANT_DESTRUCTOR( + Trait::TriviallyAvailable, + ~destructor() = default;, + inline void destroy() noexcept { + this->index_ = static_cast(-1); + }); + + MPARK_VARIANT_DESTRUCTOR( + Trait::Available, + ~destructor() { destroy(); }, + inline void destroy() noexcept { + if (!this->valueless_by_exception()) { + visitation::alt::visit_alt(dtor{}, *this); + } + this->index_ = static_cast(-1); + }); + + MPARK_VARIANT_DESTRUCTOR( + Trait::Unavailable, + ~destructor() = delete;, + inline void destroy() noexcept = delete;); + +#undef MPARK_VARIANT_DESTRUCTOR + + template + class constructor : public destructor { + using super = destructor; + + public: + MPARK_INHERITING_CTOR(constructor, super) + using super::operator=; + + protected: +#ifndef MPARK_GENERIC_LAMBDAS + struct ctor { + template + inline void operator()(LhsAlt &lhs_alt, RhsAlt &&rhs_alt) const { + constructor::construct_alt(lhs_alt, + lib::forward(rhs_alt).value); + } + }; +#endif + + template + inline static T &construct_alt(alt &a, Args &&... args) { + auto *result = ::new (static_cast(lib::addressof(a))) + alt(in_place_t{}, lib::forward(args)...); + return result->value; + } + + template + inline static void generic_construct(constructor &lhs, Rhs &&rhs) { + lhs.destroy(); + if (!rhs.valueless_by_exception()) { + visitation::alt::visit_alt_at( + rhs.index(), +#ifdef MPARK_GENERIC_LAMBDAS + [](auto &lhs_alt, auto &&rhs_alt) { + constructor::construct_alt( + lhs_alt, lib::forward(rhs_alt).value); + } +#else + ctor{} +#endif + , + lhs, + lib::forward(rhs)); + lhs.index_ = rhs.index_; + } + } + }; + + template + class move_constructor; + +#define MPARK_VARIANT_MOVE_CONSTRUCTOR(move_constructible_trait, definition) \ + template \ + class move_constructor, move_constructible_trait> \ + : public constructor> { \ + using super = constructor>; \ + \ + public: \ + MPARK_INHERITING_CTOR(move_constructor, super) \ + using super::operator=; \ + \ + move_constructor(const move_constructor &) = default; \ + definition \ + ~move_constructor() = default; \ + move_constructor &operator=(const move_constructor &) = default; \ + move_constructor &operator=(move_constructor &&) = default; \ + } + + MPARK_VARIANT_MOVE_CONSTRUCTOR( + Trait::TriviallyAvailable, + move_constructor(move_constructor &&that) = default;); + + MPARK_VARIANT_MOVE_CONSTRUCTOR( + Trait::Available, + move_constructor(move_constructor &&that) noexcept( + lib::all::value...>::value) + : move_constructor(valueless_t{}) { + this->generic_construct(*this, lib::move(that)); + }); + + MPARK_VARIANT_MOVE_CONSTRUCTOR( + Trait::Unavailable, + move_constructor(move_constructor &&) = delete;); + +#undef MPARK_VARIANT_MOVE_CONSTRUCTOR + + template + class copy_constructor; + +#define MPARK_VARIANT_COPY_CONSTRUCTOR(copy_constructible_trait, definition) \ + template \ + class copy_constructor, copy_constructible_trait> \ + : public move_constructor> { \ + using super = move_constructor>; \ + \ + public: \ + MPARK_INHERITING_CTOR(copy_constructor, super) \ + using super::operator=; \ + \ + definition \ + copy_constructor(copy_constructor &&) = default; \ + ~copy_constructor() = default; \ + copy_constructor &operator=(const copy_constructor &) = default; \ + copy_constructor &operator=(copy_constructor &&) = default; \ + } + + MPARK_VARIANT_COPY_CONSTRUCTOR( + Trait::TriviallyAvailable, + copy_constructor(const copy_constructor &that) = default;); + + MPARK_VARIANT_COPY_CONSTRUCTOR( + Trait::Available, + copy_constructor(const copy_constructor &that) + : copy_constructor(valueless_t{}) { + this->generic_construct(*this, that); + }); + + MPARK_VARIANT_COPY_CONSTRUCTOR( + Trait::Unavailable, + copy_constructor(const copy_constructor &) = delete;); + +#undef MPARK_VARIANT_COPY_CONSTRUCTOR + + template + class assignment : public copy_constructor { + using super = copy_constructor; + + public: + MPARK_INHERITING_CTOR(assignment, super) + using super::operator=; + + template + inline /* auto & */ auto emplace(Args &&... args) + -> decltype(this->construct_alt(access::base::get_alt(*this), + lib::forward(args)...)) { + this->destroy(); + auto &result = this->construct_alt(access::base::get_alt(*this), + lib::forward(args)...); + this->index_ = I; + return result; + } + + protected: +#ifndef MPARK_GENERIC_LAMBDAS + template + struct assigner { + template + inline void operator()(ThisAlt &this_alt, ThatAlt &&that_alt) const { + self->assign_alt(this_alt, lib::forward(that_alt).value); + } + assignment *self; + }; +#endif + + template + inline void assign_alt(alt &a, Arg &&arg) { + if (this->index() == I) { +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4244) +#endif + a.value = lib::forward(arg); +#ifdef _MSC_VER +#pragma warning(pop) +#endif + } else { + struct { + void operator()(std::true_type) const { + this_->emplace(lib::forward(arg_)); + } + void operator()(std::false_type) const { + this_->emplace(T(lib::forward(arg_))); + } + assignment *this_; + Arg &&arg_; + } impl{this, lib::forward(arg)}; + impl(lib::bool_constant< + std::is_nothrow_constructible::value || + !std::is_nothrow_move_constructible::value>{}); + } + } + + template + inline void generic_assign(That &&that) { + if (this->valueless_by_exception() && that.valueless_by_exception()) { + // do nothing. + } else if (that.valueless_by_exception()) { + this->destroy(); + } else { + visitation::alt::visit_alt_at( + that.index(), +#ifdef MPARK_GENERIC_LAMBDAS + [this](auto &this_alt, auto &&that_alt) { + this->assign_alt( + this_alt, lib::forward(that_alt).value); + } +#else + assigner{this} +#endif + , + *this, + lib::forward(that)); + } + } + }; + + template + class move_assignment; + +#define MPARK_VARIANT_MOVE_ASSIGNMENT(move_assignable_trait, definition) \ + template \ + class move_assignment, move_assignable_trait> \ + : public assignment> { \ + using super = assignment>; \ + \ + public: \ + MPARK_INHERITING_CTOR(move_assignment, super) \ + using super::operator=; \ + \ + move_assignment(const move_assignment &) = default; \ + move_assignment(move_assignment &&) = default; \ + ~move_assignment() = default; \ + move_assignment &operator=(const move_assignment &) = default; \ + definition \ + } + + MPARK_VARIANT_MOVE_ASSIGNMENT( + Trait::TriviallyAvailable, + move_assignment &operator=(move_assignment &&that) = default;); + + MPARK_VARIANT_MOVE_ASSIGNMENT( + Trait::Available, + move_assignment & + operator=(move_assignment &&that) noexcept( + lib::all<(std::is_nothrow_move_constructible::value && + std::is_nothrow_move_assignable::value)...>::value) { + this->generic_assign(lib::move(that)); + return *this; + }); + + MPARK_VARIANT_MOVE_ASSIGNMENT( + Trait::Unavailable, + move_assignment &operator=(move_assignment &&) = delete;); + +#undef MPARK_VARIANT_MOVE_ASSIGNMENT + + template + class copy_assignment; + +#define MPARK_VARIANT_COPY_ASSIGNMENT(copy_assignable_trait, definition) \ + template \ + class copy_assignment, copy_assignable_trait> \ + : public move_assignment> { \ + using super = move_assignment>; \ + \ + public: \ + MPARK_INHERITING_CTOR(copy_assignment, super) \ + using super::operator=; \ + \ + copy_assignment(const copy_assignment &) = default; \ + copy_assignment(copy_assignment &&) = default; \ + ~copy_assignment() = default; \ + definition \ + copy_assignment &operator=(copy_assignment &&) = default; \ + } + + MPARK_VARIANT_COPY_ASSIGNMENT( + Trait::TriviallyAvailable, + copy_assignment &operator=(const copy_assignment &that) = default;); + + MPARK_VARIANT_COPY_ASSIGNMENT( + Trait::Available, + copy_assignment &operator=(const copy_assignment &that) { + this->generic_assign(that); + return *this; + }); + + MPARK_VARIANT_COPY_ASSIGNMENT( + Trait::Unavailable, + copy_assignment &operator=(const copy_assignment &) = delete;); + +#undef MPARK_VARIANT_COPY_ASSIGNMENT + + template + class impl : public copy_assignment> { + using super = copy_assignment>; + + public: + MPARK_INHERITING_CTOR(impl, super) + using super::operator=; + + impl(const impl&) = default; + impl(impl&&) = default; + ~impl() = default; + impl &operator=(const impl &) = default; + impl &operator=(impl &&) = default; + + template + inline void assign(Arg &&arg) { + this->assign_alt(access::base::get_alt(*this), + lib::forward(arg)); + } + + inline void swap(impl &that) { + if (this->valueless_by_exception() && that.valueless_by_exception()) { + // do nothing. + } else if (this->index() == that.index()) { + visitation::alt::visit_alt_at(this->index(), +#ifdef MPARK_GENERIC_LAMBDAS + [](auto &this_alt, auto &that_alt) { + using std::swap; + swap(this_alt.value, + that_alt.value); + } +#else + swapper{} +#endif + , + *this, + that); + } else { + impl *lhs = this; + impl *rhs = lib::addressof(that); + if (lhs->move_nothrow() && !rhs->move_nothrow()) { + std::swap(lhs, rhs); + } + impl tmp(lib::move(*rhs)); +#ifdef MPARK_EXCEPTIONS + // EXTENSION: When the move construction of `lhs` into `rhs` throws + // and `tmp` is nothrow move constructible then we move `tmp` back + // into `rhs` and provide the strong exception safety guarantee. + try { + this->generic_construct(*rhs, lib::move(*lhs)); + } catch (...) { + if (tmp.move_nothrow()) { + this->generic_construct(*rhs, lib::move(tmp)); + } + throw; + } +#else + this->generic_construct(*rhs, lib::move(*lhs)); +#endif + this->generic_construct(*lhs, lib::move(tmp)); + } + } + + private: +#ifndef MPARK_GENERIC_LAMBDAS + struct swapper { + template + inline void operator()(ThisAlt &this_alt, ThatAlt &that_alt) const { + using std::swap; + swap(this_alt.value, that_alt.value); + } + }; +#endif + + inline constexpr bool move_nothrow() const { + return this->valueless_by_exception() || + lib::array{ + {std::is_nothrow_move_constructible::value...} + }[this->index()]; + } + }; + +#undef MPARK_INHERITING_CTOR + + template + struct overload_leaf { + using F = lib::size_constant (*)(T); + operator F() const { return nullptr; } + }; + + template + struct overload_impl { + private: + template + struct impl; + + template + struct impl> : overload_leaf... {}; + + public: + using type = impl>; + }; + + template + using overload = typename overload_impl::type; + + template + using best_match = lib::invoke_result_t, T &&>; + + template + struct is_in_place_index : std::false_type {}; + + template + struct is_in_place_index> : std::true_type {}; + + template + struct is_in_place_type : std::false_type {}; + + template + struct is_in_place_type> : std::true_type {}; + + } // detail + + template + class variant { + static_assert(0 < sizeof...(Ts), + "variant must consist of at least one alternative."); + + static_assert(lib::all::value...>::value, + "variant can not have an array type as an alternative."); + + static_assert(lib::all::value...>::value, + "variant can not have a reference type as an alternative."); + + static_assert(lib::all::value...>::value, + "variant can not have a void type as an alternative."); + + public: + template < + typename Front = lib::type_pack_element_t<0, Ts...>, + lib::enable_if_t::value, int> = 0> + inline constexpr variant() noexcept( + std::is_nothrow_default_constructible::value) + : impl_(in_place_index_t<0>{}) {} + + variant(const variant &) = default; + variant(variant &&) = default; + + template < + typename Arg, + typename Decayed = lib::decay_t, + lib::enable_if_t::value, int> = 0, + lib::enable_if_t::value, int> = 0, + lib::enable_if_t::value, int> = 0, + std::size_t I = detail::best_match::value, + typename T = lib::type_pack_element_t, + lib::enable_if_t::value, int> = 0> + inline constexpr variant(Arg &&arg) noexcept( + std::is_nothrow_constructible::value) + : impl_(in_place_index_t{}, lib::forward(arg)) {} + + template < + std::size_t I, + typename... Args, + typename T = lib::type_pack_element_t, + lib::enable_if_t::value, int> = 0> + inline explicit constexpr variant( + in_place_index_t, + Args &&... args) noexcept(std::is_nothrow_constructible::value) + : impl_(in_place_index_t{}, lib::forward(args)...) {} + + template < + std::size_t I, + typename Up, + typename... Args, + typename T = lib::type_pack_element_t, + lib::enable_if_t &, + Args...>::value, + int> = 0> + inline explicit constexpr variant( + in_place_index_t, + std::initializer_list il, + Args &&... args) noexcept(std:: + is_nothrow_constructible< + T, + std::initializer_list &, + Args...>::value) + : impl_(in_place_index_t{}, il, lib::forward(args)...) {} + + template < + typename T, + typename... Args, + std::size_t I = detail::find_index_sfinae::value, + lib::enable_if_t::value, int> = 0> + inline explicit constexpr variant( + in_place_type_t, + Args &&... args) noexcept(std::is_nothrow_constructible::value) + : impl_(in_place_index_t{}, lib::forward(args)...) {} + + template < + typename T, + typename Up, + typename... Args, + std::size_t I = detail::find_index_sfinae::value, + lib::enable_if_t &, + Args...>::value, + int> = 0> + inline explicit constexpr variant( + in_place_type_t, + std::initializer_list il, + Args &&... args) noexcept(std:: + is_nothrow_constructible< + T, + std::initializer_list &, + Args...>::value) + : impl_(in_place_index_t{}, il, lib::forward(args)...) {} + + ~variant() = default; + + variant &operator=(const variant &) = default; + variant &operator=(variant &&) = default; + + template , variant>::value, + int> = 0, + std::size_t I = detail::best_match::value, + typename T = lib::type_pack_element_t, + lib::enable_if_t<(std::is_assignable::value && + std::is_constructible::value), + int> = 0> + inline variant &operator=(Arg &&arg) noexcept( + (std::is_nothrow_assignable::value && + std::is_nothrow_constructible::value)) { + impl_.template assign(lib::forward(arg)); + return *this; + } + + template < + std::size_t I, + typename... Args, + typename T = lib::type_pack_element_t, + lib::enable_if_t::value, int> = 0> + inline T &emplace(Args &&... args) { + return impl_.template emplace(lib::forward(args)...); + } + + template < + std::size_t I, + typename Up, + typename... Args, + typename T = lib::type_pack_element_t, + lib::enable_if_t &, + Args...>::value, + int> = 0> + inline T &emplace(std::initializer_list il, Args &&... args) { + return impl_.template emplace(il, lib::forward(args)...); + } + + template < + typename T, + typename... Args, + std::size_t I = detail::find_index_sfinae::value, + lib::enable_if_t::value, int> = 0> + inline T &emplace(Args &&... args) { + return impl_.template emplace(lib::forward(args)...); + } + + template < + typename T, + typename Up, + typename... Args, + std::size_t I = detail::find_index_sfinae::value, + lib::enable_if_t &, + Args...>::value, + int> = 0> + inline T &emplace(std::initializer_list il, Args &&... args) { + return impl_.template emplace(il, lib::forward(args)...); + } + + inline constexpr bool valueless_by_exception() const noexcept { + return impl_.valueless_by_exception(); + } + + inline constexpr std::size_t index() const noexcept { + return impl_.index(); + } + + template , + Dummy>::value && + lib::dependent_type, + Dummy>::value)...>::value, + int> = 0> + inline void swap(variant &that) noexcept( + lib::all<(std::is_nothrow_move_constructible::value && + lib::is_nothrow_swappable::value)...>::value) { + impl_.swap(that.impl_); + } + + private: + detail::impl impl_; + + friend struct detail::access::variant; + friend struct detail::visitation::variant; + }; + + template + inline constexpr bool holds_alternative(const variant &v) noexcept { + return v.index() == I; + } + + template + inline constexpr bool holds_alternative(const variant &v) noexcept { + return holds_alternative::value>(v); + } + + namespace detail { + template + struct generic_get_impl { + constexpr generic_get_impl(int) noexcept {} + + constexpr AUTO_REFREF operator()(V &&v) const + AUTO_REFREF_RETURN( + access::variant::get_alt(lib::forward(v)).value) + }; + + template + inline constexpr AUTO_REFREF generic_get(V &&v) + AUTO_REFREF_RETURN(generic_get_impl( + holds_alternative(v) ? 0 : (throw_bad_variant_access(), 0))( + lib::forward(v))) + } // namespace detail + + template + inline constexpr variant_alternative_t> &get( + variant &v) { + return detail::generic_get(v); + } + + template + inline constexpr variant_alternative_t> &&get( + variant &&v) { + return detail::generic_get(lib::move(v)); + } + + template + inline constexpr const variant_alternative_t> &get( + const variant &v) { + return detail::generic_get(v); + } + + template + inline constexpr const variant_alternative_t> &&get( + const variant &&v) { + return detail::generic_get(lib::move(v)); + } + + template + inline constexpr T &get(variant &v) { + return get::value>(v); + } + + template + inline constexpr T &&get(variant &&v) { + return get::value>(lib::move(v)); + } + + template + inline constexpr const T &get(const variant &v) { + return get::value>(v); + } + + template + inline constexpr const T &&get(const variant &&v) { + return get::value>(lib::move(v)); + } + + namespace detail { + + template + inline constexpr /* auto * */ AUTO generic_get_if(V *v) noexcept + AUTO_RETURN(v && holds_alternative(*v) + ? lib::addressof(access::variant::get_alt(*v).value) + : nullptr) + + } // namespace detail + + template + inline constexpr lib::add_pointer_t>> + get_if(variant *v) noexcept { + return detail::generic_get_if(v); + } + + template + inline constexpr lib::add_pointer_t< + const variant_alternative_t>> + get_if(const variant *v) noexcept { + return detail::generic_get_if(v); + } + + template + inline constexpr lib::add_pointer_t + get_if(variant *v) noexcept { + return get_if::value>(v); + } + + template + inline constexpr lib::add_pointer_t + get_if(const variant *v) noexcept { + return get_if::value>(v); + } + + namespace detail { + template + struct convert_to_bool { + template + inline constexpr bool operator()(Lhs &&lhs, Rhs &&rhs) const { + static_assert(std::is_convertible, + bool>::value, + "relational operators must return a type" + " implicitly convertible to bool"); + return lib::invoke( + RelOp{}, lib::forward(lhs), lib::forward(rhs)); + } + }; + } // namespace detail + + template + inline constexpr bool operator==(const variant &lhs, + const variant &rhs) { + using detail::visitation::variant; + using equal_to = detail::convert_to_bool; +#ifdef MPARK_CPP14_CONSTEXPR + if (lhs.index() != rhs.index()) return false; + if (lhs.valueless_by_exception()) return true; + return variant::visit_value_at(lhs.index(), equal_to{}, lhs, rhs); +#else + return lhs.index() == rhs.index() && + (lhs.valueless_by_exception() || + variant::visit_value_at(lhs.index(), equal_to{}, lhs, rhs)); +#endif + } + + template + inline constexpr bool operator!=(const variant &lhs, + const variant &rhs) { + using detail::visitation::variant; + using not_equal_to = detail::convert_to_bool; +#ifdef MPARK_CPP14_CONSTEXPR + if (lhs.index() != rhs.index()) return true; + if (lhs.valueless_by_exception()) return false; + return variant::visit_value_at(lhs.index(), not_equal_to{}, lhs, rhs); +#else + return lhs.index() != rhs.index() || + (!lhs.valueless_by_exception() && + variant::visit_value_at(lhs.index(), not_equal_to{}, lhs, rhs)); +#endif + } + + template + inline constexpr bool operator<(const variant &lhs, + const variant &rhs) { + using detail::visitation::variant; + using less = detail::convert_to_bool; +#ifdef MPARK_CPP14_CONSTEXPR + if (rhs.valueless_by_exception()) return false; + if (lhs.valueless_by_exception()) return true; + if (lhs.index() < rhs.index()) return true; + if (lhs.index() > rhs.index()) return false; + return variant::visit_value_at(lhs.index(), less{}, lhs, rhs); +#else + return !rhs.valueless_by_exception() && + (lhs.valueless_by_exception() || lhs.index() < rhs.index() || + (lhs.index() == rhs.index() && + variant::visit_value_at(lhs.index(), less{}, lhs, rhs))); +#endif + } + + template + inline constexpr bool operator>(const variant &lhs, + const variant &rhs) { + using detail::visitation::variant; + using greater = detail::convert_to_bool; +#ifdef MPARK_CPP14_CONSTEXPR + if (lhs.valueless_by_exception()) return false; + if (rhs.valueless_by_exception()) return true; + if (lhs.index() > rhs.index()) return true; + if (lhs.index() < rhs.index()) return false; + return variant::visit_value_at(lhs.index(), greater{}, lhs, rhs); +#else + return !lhs.valueless_by_exception() && + (rhs.valueless_by_exception() || lhs.index() > rhs.index() || + (lhs.index() == rhs.index() && + variant::visit_value_at(lhs.index(), greater{}, lhs, rhs))); +#endif + } + + template + inline constexpr bool operator<=(const variant &lhs, + const variant &rhs) { + using detail::visitation::variant; + using less_equal = detail::convert_to_bool; +#ifdef MPARK_CPP14_CONSTEXPR + if (lhs.valueless_by_exception()) return true; + if (rhs.valueless_by_exception()) return false; + if (lhs.index() < rhs.index()) return true; + if (lhs.index() > rhs.index()) return false; + return variant::visit_value_at(lhs.index(), less_equal{}, lhs, rhs); +#else + return lhs.valueless_by_exception() || + (!rhs.valueless_by_exception() && + (lhs.index() < rhs.index() || + (lhs.index() == rhs.index() && + variant::visit_value_at(lhs.index(), less_equal{}, lhs, rhs)))); +#endif + } + + template + inline constexpr bool operator>=(const variant &lhs, + const variant &rhs) { + using detail::visitation::variant; + using greater_equal = detail::convert_to_bool; +#ifdef MPARK_CPP14_CONSTEXPR + if (rhs.valueless_by_exception()) return true; + if (lhs.valueless_by_exception()) return false; + if (lhs.index() > rhs.index()) return true; + if (lhs.index() < rhs.index()) return false; + return variant::visit_value_at(lhs.index(), greater_equal{}, lhs, rhs); +#else + return rhs.valueless_by_exception() || + (!lhs.valueless_by_exception() && + (lhs.index() > rhs.index() || + (lhs.index() == rhs.index() && + variant::visit_value_at( + lhs.index(), greater_equal{}, lhs, rhs)))); +#endif + } + + struct monostate {}; + + inline constexpr bool operator<(monostate, monostate) noexcept { + return false; + } + + inline constexpr bool operator>(monostate, monostate) noexcept { + return false; + } + + inline constexpr bool operator<=(monostate, monostate) noexcept { + return true; + } + + inline constexpr bool operator>=(monostate, monostate) noexcept { + return true; + } + + inline constexpr bool operator==(monostate, monostate) noexcept { + return true; + } + + inline constexpr bool operator!=(monostate, monostate) noexcept { + return false; + } + +#ifdef MPARK_CPP14_CONSTEXPR + namespace detail { + + inline constexpr bool all(std::initializer_list bs) { + for (bool b : bs) { + if (!b) { + return false; + } + } + return true; + } + + } // namespace detail + + template + inline constexpr decltype(auto) visit(Visitor &&visitor, Vs &&... vs) { + return (detail::all({!vs.valueless_by_exception()...}) + ? (void)0 + : throw_bad_variant_access()), + detail::visitation::variant::visit_value( + lib::forward(visitor), lib::forward(vs)...); + } +#else + namespace detail { + + template + inline constexpr bool all_impl(const lib::array &bs, + std::size_t idx) { + return idx >= N || (bs[idx] && all_impl(bs, idx + 1)); + } + + template + inline constexpr bool all(const lib::array &bs) { + return all_impl(bs, 0); + } + + } // namespace detail + + template + inline constexpr DECLTYPE_AUTO visit(Visitor &&visitor, Vs &&... vs) + DECLTYPE_AUTO_RETURN( + (detail::all( + lib::array{{!vs.valueless_by_exception()...}}) + ? (void)0 + : throw_bad_variant_access()), + detail::visitation::variant::visit_value(lib::forward(visitor), + lib::forward(vs)...)) +#endif + + template + inline auto swap(variant &lhs, + variant &rhs) noexcept(noexcept(lhs.swap(rhs))) + -> decltype(lhs.swap(rhs)) { + lhs.swap(rhs); + } + + namespace detail { + + template + using enabled_type = T; + + namespace hash { + + template + constexpr bool meets_requirements() noexcept { + return std::is_copy_constructible::value && + std::is_move_constructible::value && + lib::is_invocable_r::value; + } + + template + constexpr bool is_enabled() noexcept { + using H = std::hash; + return meets_requirements() && + std::is_default_constructible::value && + std::is_copy_assignable::value && + std::is_move_assignable::value; + } + + } // namespace hash + + } // namespace detail + +#undef AUTO +#undef AUTO_RETURN + +#undef AUTO_REFREF +#undef AUTO_REFREF_RETURN + +#undef DECLTYPE_AUTO +#undef DECLTYPE_AUTO_RETURN + +} // namespace mpark + +namespace std { + + template + struct hash, + mpark::lib::enable_if_t>()...>::value>>> { + using argument_type = mpark::variant; + using result_type = std::size_t; + + inline result_type operator()(const argument_type &v) const { + using mpark::detail::visitation::variant; + std::size_t result = + v.valueless_by_exception() + ? 299792458 // Random value chosen by the universe upon creation + : variant::visit_alt( +#ifdef MPARK_GENERIC_LAMBDAS + [](const auto &alt) { + using alt_type = mpark::lib::decay_t; + using value_type = mpark::lib::remove_const_t< + typename alt_type::value_type>; + return hash{}(alt.value); + } +#else + hasher{} +#endif + , + v); + return hash_combine(result, hash{}(v.index())); + } + + private: +#ifndef MPARK_GENERIC_LAMBDAS + struct hasher { + template + inline std::size_t operator()(const Alt &alt) const { + using alt_type = mpark::lib::decay_t; + using value_type = + mpark::lib::remove_const_t; + return hash{}(alt.value); + } + }; +#endif + + static std::size_t hash_combine(std::size_t lhs, std::size_t rhs) { + return lhs ^= rhs + 0x9e3779b9 + (lhs << 6) + (lhs >> 2); + } + }; + + template <> + struct hash { + using argument_type = mpark::monostate; + using result_type = std::size_t; + + inline result_type operator()(const argument_type &) const noexcept { + return 66740831; // return a fundamentally attractive random value. + } + }; + +} // namespace std + +#endif // MPARK_VARIANT_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm.hpp new file mode 100644 index 0000000..5e52173 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm.hpp @@ -0,0 +1,30 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_HPP +#define REALM_HPP + +#include +#include +#include +#include +#include +#include +#include + +#endif // REALM_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/.gitkeep b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/alloc.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/alloc.hpp new file mode 100644 index 0000000..d015148 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/alloc.hpp @@ -0,0 +1,586 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_ALLOC_HPP +#define REALM_ALLOC_HPP + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +// Temporary workaround for +// https://developercommunity.visualstudio.com/content/problem/994075/64-bit-atomic-load-ices-cl-1924-with-o2-ob1.html +#if defined REALM_ARCHITECTURE_X86_32 && defined REALM_WINDOWS +#define REALM_WORKAROUND_MSVC_BUG REALM_NOINLINE +#else +#define REALM_WORKAROUND_MSVC_BUG +#endif + +namespace realm { + +class Allocator; + +using ref_type = size_t; + +int_fast64_t from_ref(ref_type) noexcept; +ref_type to_ref(int_fast64_t) noexcept; +int64_t to_int64(size_t value) noexcept; + +class MemRef { +public: + MemRef() noexcept; + ~MemRef() noexcept; + + MemRef(char* addr, ref_type ref, Allocator& alloc) noexcept; + MemRef(ref_type ref, Allocator& alloc) noexcept; + + char* get_addr() const; + ref_type get_ref() const; + void set_ref(ref_type ref); + void set_addr(char* addr); + +private: + char* m_addr; + ref_type m_ref; +#if REALM_ENABLE_MEMDEBUG + // Allocator that created m_ref. Used to verify that the ref is valid whenever you call + // get_ref()/get_addr and that it e.g. has not been free'ed + const Allocator* m_alloc = nullptr; +#endif +}; + + +/// The common interface for Realm allocators. +/// +/// A Realm allocator must associate a 'ref' to each allocated +/// object and be able to efficiently map any 'ref' to the +/// corresponding memory address. The 'ref' is an integer and it must +/// always be divisible by 8. Also, a value of zero is used to +/// indicate a null-reference, and must therefore never be returned by +/// Allocator::alloc(). +/// +/// The purpose of the 'refs' is to decouple the memory reference from +/// the actual address and thereby allowing objects to be relocated in +/// memory without having to modify stored references. +/// +/// \sa SlabAlloc +class Allocator { +public: + /// The specified size must be divisible by 8, and must not be + /// zero. + /// + /// \throw std::bad_alloc If insufficient memory was available. + MemRef alloc(size_t size); + + /// Calls do_realloc(). + /// + /// Note: The underscore has been added because the name `realloc` + /// would conflict with a macro on the Windows platform. + MemRef realloc_(ref_type, const char* addr, size_t old_size, size_t new_size); + + /// Calls do_free(). + /// + /// Note: The underscore has been added because the name `free + /// would conflict with a macro on the Windows platform. + void free_(ref_type, const char* addr) noexcept; + + /// Shorthand for free_(mem.get_ref(), mem.get_addr()). + void free_(MemRef mem) noexcept; + + /// Calls do_translate(). + char* translate(ref_type ref) const noexcept; + + /// Returns true if, and only if the object at the specified 'ref' + /// is in the immutable part of the memory managed by this + /// allocator. The method by which some objects become part of the + /// immuatble part is entirely up to the class that implements + /// this interface. + bool is_read_only(ref_type) const noexcept; + + void set_read_only(bool ro) + { + m_is_read_only = ro; + } + /// Returns a simple allocator that can be used with free-standing + /// Realm objects (such as a free-standing table). A + /// free-standing object is one that is not part of a Group, and + /// therefore, is not part of an actual database. + static Allocator& get_default() noexcept; + + virtual ~Allocator() noexcept; + + // Disable copying. Copying an allocator can produce double frees. + Allocator(const Allocator&) = delete; + Allocator& operator=(const Allocator&) = delete; + + virtual void verify() const = 0; + +#ifdef REALM_DEBUG + /// Terminate the program precisely when the specified 'ref' is + /// freed (or reallocated). You can use this to detect whether the + /// ref is freed (or reallocated), and even to get a stacktrace at + /// the point where it happens. Call watch(0) to stop watching + /// that ref. + void watch(ref_type ref) + { + m_debug_watch = ref; + } +#endif + + struct MappedFile; + +protected: + constexpr static int section_shift = 26; + + std::atomic m_baseline; // Separation line between immutable and mutable refs. + + ref_type m_debug_watch = 0; + + // The following logically belongs in the slab allocator, but is placed + // here to optimize a critical path: + + // The ref translation splits the full ref-space (both below and above baseline) + // into equal chunks. + struct RefTranslation { + char* mapping_addr = nullptr; + std::atomic lowest_possible_xover_offset = 0; + + // member 'xover_mapping_addr' is used for memory synchronization of the fields + // 'xover_mapping_base' and 'xover_encrypted_mapping'. It also imposes an ordering + // on 'lowest_possible_xover_offset' such that once a non-null value of 'xover_mapping_addr' + // has been acquired, 'lowest_possible_xover_offset' will never change. + std::atomic xover_mapping_addr = nullptr; + size_t xover_mapping_base = 0; +#if REALM_ENABLE_ENCRYPTION + util::EncryptedFileMapping* encrypted_mapping = nullptr; + util::EncryptedFileMapping* xover_encrypted_mapping = nullptr; +#endif + explicit RefTranslation(char* addr) + : mapping_addr(addr) + { + } + RefTranslation() = default; + RefTranslation& operator=(const RefTranslation& from) + { + if (&from != this) { + mapping_addr = from.mapping_addr; +#if REALM_ENABLE_ENCRYPTION + encrypted_mapping = from.encrypted_mapping; +#endif + const auto local_xover_mapping_addr = from.xover_mapping_addr.load(std::memory_order_acquire); + + // This must be loaded after xover_mapping_addr to ensure it isn't stale. + lowest_possible_xover_offset.store(from.lowest_possible_xover_offset, std::memory_order_relaxed); + + if (local_xover_mapping_addr) { + xover_mapping_base = from.xover_mapping_base; +#if REALM_ENABLE_ENCRYPTION + xover_encrypted_mapping = from.xover_encrypted_mapping; +#endif + xover_mapping_addr.store(local_xover_mapping_addr, std::memory_order_release); + } + } + return *this; + } + }; + // This pointer may be changed concurrently with access, so make sure it is + // atomic! + std::atomic m_ref_translation_ptr; + + /// The specified size must be divisible by 8, and must not be + /// zero. + /// + /// \throw std::bad_alloc If insufficient memory was available. + virtual MemRef do_alloc(const size_t size) = 0; + + /// The specified size must be divisible by 8, and must not be + /// zero. + /// + /// The default version of this function simply allocates a new + /// chunk of memory, copies over the old contents, and then frees + /// the old chunk. + /// + /// \throw std::bad_alloc If insufficient memory was available. + virtual MemRef do_realloc(ref_type, char* addr, size_t old_size, size_t new_size) = 0; + + /// Release the specified chunk of memory. + virtual void do_free(ref_type, char* addr) = 0; + + /// Map the specified \a ref to the corresponding memory + /// address. Note that if is_read_only(ref) returns true, then the + /// referenced object is to be considered immutable, and it is + /// then entirely the responsibility of the caller that the memory + /// is not modified by way of the returned memory pointer. + virtual char* do_translate(ref_type ref) const noexcept = 0; + char* translate_critical(RefTranslation*, ref_type ref) const noexcept; + char* translate_less_critical(RefTranslation*, ref_type ref) const noexcept; + virtual void get_or_add_xover_mapping(RefTranslation&, size_t, size_t, size_t) = 0; + Allocator() noexcept; + size_t get_section_index(size_t pos) const noexcept; + inline size_t get_section_base(size_t index) const noexcept; + + + // The following counters are used to ensure accessor refresh, + // and allows us to report many errors related to attempts to + // access data which is no longer current. + // + // * storage_versioning: monotonically increasing counter + // bumped whenever the underlying storage layout is changed, + // or if the owning accessor have been detached. + // * content_versioning: monotonically increasing counter + // bumped whenever the data is changed. Used to detect + // if queries are stale. + // * instance_versioning: monotonically increasing counter + // used to detect if the allocator (and owning structure, e.g. Table) + // is recycled. Mismatch on this counter will cause accesors + // lower in the hierarchy to throw if access is attempted. + std::atomic m_content_versioning_counter; + + std::atomic m_storage_versioning_counter; + + std::atomic m_instance_versioning_counter; + + inline uint_fast64_t get_storage_version(uint64_t instance_version) + { + if (instance_version != m_instance_versioning_counter) { + throw LogicError(LogicError::detached_accessor); + } + return m_storage_versioning_counter.load(std::memory_order_acquire); + } + + inline uint_fast64_t get_storage_version() + { + return m_storage_versioning_counter.load(std::memory_order_acquire); + } + + inline void bump_storage_version() noexcept + { + m_storage_versioning_counter.fetch_add(1, std::memory_order_acq_rel); + } + + REALM_WORKAROUND_MSVC_BUG inline uint_fast64_t get_content_version() noexcept + { + return m_content_versioning_counter.load(std::memory_order_acquire); + } + + inline uint_fast64_t bump_content_version() noexcept + { + return m_content_versioning_counter.fetch_add(1, std::memory_order_acq_rel) + 1; + } + + REALM_WORKAROUND_MSVC_BUG inline uint_fast64_t get_instance_version() noexcept + { + return m_instance_versioning_counter.load(std::memory_order_relaxed); + } + + inline void bump_instance_version() noexcept + { + m_instance_versioning_counter.fetch_add(1, std::memory_order_relaxed); + } + +private: + bool m_is_read_only = false; // prevent any alloc or free operations + + friend class Table; + friend class ClusterTree; + friend class Group; + friend class WrappedAllocator; + friend class ConstObj; + friend class Obj; + friend class ConstLstBase; +}; + + +class WrappedAllocator : public Allocator { +public: + WrappedAllocator(Allocator& underlying_allocator) + : m_alloc(&underlying_allocator) + { + m_baseline.store(m_alloc->m_baseline, std::memory_order_relaxed); + m_debug_watch = 0; + m_ref_translation_ptr.store(m_alloc->m_ref_translation_ptr); + } + + ~WrappedAllocator() + { + } + + void switch_underlying_allocator(Allocator& underlying_allocator) + { + m_alloc = &underlying_allocator; + m_baseline.store(m_alloc->m_baseline, std::memory_order_relaxed); + m_debug_watch = 0; + m_ref_translation_ptr.store(m_alloc->m_ref_translation_ptr); + } + + void update_from_underlying_allocator(bool writable) + { + switch_underlying_allocator(*m_alloc); + set_read_only(!writable); + } + +protected: + void get_or_add_xover_mapping(RefTranslation& txl, size_t index, size_t offset, size_t size) override + { + m_alloc->get_or_add_xover_mapping(txl, index, offset, size); + } + +private: + Allocator* m_alloc; + MemRef do_alloc(const size_t size) override + { + auto result = m_alloc->do_alloc(size); + bump_storage_version(); + m_baseline.store(m_alloc->m_baseline, std::memory_order_relaxed); + m_ref_translation_ptr.store(m_alloc->m_ref_translation_ptr); + return result; + } + virtual MemRef do_realloc(ref_type ref, char* addr, size_t old_size, size_t new_size) override + { + auto result = m_alloc->do_realloc(ref, addr, old_size, new_size); + bump_storage_version(); + m_baseline.store(m_alloc->m_baseline, std::memory_order_relaxed); + m_ref_translation_ptr.store(m_alloc->m_ref_translation_ptr); + return result; + } + + virtual void do_free(ref_type ref, char* addr) noexcept override + { + return m_alloc->do_free(ref, addr); + } + + virtual char* do_translate(ref_type ref) const noexcept override + { + return m_alloc->translate(ref); + } + + virtual void verify() const override + { + m_alloc->verify(); + } +}; + + +// Implementation: + +inline int_fast64_t from_ref(ref_type v) noexcept +{ + // Check that v is divisible by 8 (64-bit aligned). + REALM_ASSERT_DEBUG(v % 8 == 0); + + static_assert(std::is_same::value, + "If ref_type changes, from_ref and to_ref should probably be updated"); + + // Make sure that we preserve the bit pattern of the ref_type (without sign extension). + return int_fast64_t(uint_fast64_t(v)); +} + +inline ref_type to_ref(int_fast64_t v) noexcept +{ + // Check that v is divisible by 8 (64-bit aligned). + REALM_ASSERT_DEBUG(v % 8 == 0); + + // C++11 standard, paragraph 4.7.2 [conv.integral]: + // If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source + // integer (modulo 2n where n is the number of bits used to represent the unsigned type). [ Note: In a two's + // complement representation, this conversion is conceptual and there is no change in the bit pattern (if there is + // no truncation). - end note ] + static_assert(std::is_unsigned::value, + "If ref_type changes, from_ref and to_ref should probably be updated"); + return ref_type(v); +} + +inline int64_t to_int64(size_t value) noexcept +{ + // FIXME: Enable once we get clang warning flags correct + // REALM_ASSERT_DEBUG(value <= std::numeric_limits::max()); + return static_cast(value); +} + + +inline MemRef::MemRef() noexcept + : m_addr(nullptr) + , m_ref(0) +{ +} + +inline MemRef::~MemRef() noexcept +{ +} + +inline MemRef::MemRef(char* addr, ref_type ref, Allocator& alloc) noexcept + : m_addr(addr) + , m_ref(ref) +{ + static_cast(alloc); +#if REALM_ENABLE_MEMDEBUG + m_alloc = &alloc; +#endif +} + +inline MemRef::MemRef(ref_type ref, Allocator& alloc) noexcept + : m_addr(alloc.translate(ref)) + , m_ref(ref) +{ + static_cast(alloc); +#if REALM_ENABLE_MEMDEBUG + m_alloc = &alloc; +#endif +} + +inline char* MemRef::get_addr() const +{ +#if REALM_ENABLE_MEMDEBUG + // Asserts if the ref has been freed + m_alloc->translate(m_ref); +#endif + return m_addr; +} + +inline ref_type MemRef::get_ref() const +{ +#if REALM_ENABLE_MEMDEBUG + // Asserts if the ref has been freed + m_alloc->translate(m_ref); +#endif + return m_ref; +} + +inline void MemRef::set_ref(ref_type ref) +{ +#if REALM_ENABLE_MEMDEBUG + // Asserts if the ref has been freed + m_alloc->translate(ref); +#endif + m_ref = ref; +} + +inline void MemRef::set_addr(char* addr) +{ + m_addr = addr; +} + +inline MemRef Allocator::alloc(size_t size) +{ + if (m_is_read_only) + throw realm::LogicError(realm::LogicError::wrong_transact_state); + return do_alloc(size); +} + +inline MemRef Allocator::realloc_(ref_type ref, const char* addr, size_t old_size, size_t new_size) +{ +#ifdef REALM_DEBUG + if (ref == m_debug_watch) + REALM_TERMINATE("Allocator watch: Ref was reallocated"); +#endif + if (m_is_read_only) + throw realm::LogicError(realm::LogicError::wrong_transact_state); + return do_realloc(ref, const_cast(addr), old_size, new_size); +} + +inline void Allocator::free_(ref_type ref, const char* addr) noexcept +{ +#ifdef REALM_DEBUG + if (ref == m_debug_watch) + REALM_TERMINATE("Allocator watch: Ref was freed"); +#endif + REALM_ASSERT(!m_is_read_only); + + return do_free(ref, const_cast(addr)); +} + +inline void Allocator::free_(MemRef mem) noexcept +{ + free_(mem.get_ref(), mem.get_addr()); +} + +inline size_t Allocator::get_section_base(size_t index) const noexcept +{ + return index << section_shift; // 64MB chunks +} + +inline size_t Allocator::get_section_index(size_t pos) const noexcept +{ + return pos >> section_shift; // 64Mb chunks +} + +inline bool Allocator::is_read_only(ref_type ref) const noexcept +{ + REALM_ASSERT_DEBUG(ref != 0); + // REALM_ASSERT_DEBUG(m_baseline != 0); // Attached SlabAlloc + return ref < m_baseline.load(std::memory_order_relaxed); +} + +inline Allocator::Allocator() noexcept +{ + m_content_versioning_counter = 0; + m_storage_versioning_counter = 0; + m_instance_versioning_counter = 0; + m_ref_translation_ptr = nullptr; +} + +inline Allocator::~Allocator() noexcept +{ +} + +// performance critical part of the translation process. Less critical code is in translate_less_critical. +inline char* Allocator::translate_critical(RefTranslation* ref_translation_ptr, ref_type ref) const noexcept +{ + size_t idx = get_section_index(ref); + RefTranslation& txl = ref_translation_ptr[idx]; + size_t offset = ref - get_section_base(idx); + size_t lowest_possible_xover_offset = txl.lowest_possible_xover_offset.load(std::memory_order_relaxed); + if (REALM_LIKELY(offset < lowest_possible_xover_offset)) { + // the lowest possible xover offset may grow concurrently, but that will not affect this code path + char* addr = txl.mapping_addr + offset; +#if REALM_ENABLE_ENCRYPTION + realm::util::encryption_read_barrier(addr, NodeHeader::header_size, txl.encrypted_mapping, + NodeHeader::get_byte_size_from_header); +#endif + return addr; + } + else { + // the lowest possible xover offset may grow concurrently, but that will be handled inside the call + return translate_less_critical(ref_translation_ptr, ref); + } +} + +inline char* Allocator::translate(ref_type ref) const noexcept +{ + auto ref_translation_ptr = m_ref_translation_ptr.load(std::memory_order_acquire); + if (REALM_LIKELY(ref_translation_ptr)) { + return translate_critical(ref_translation_ptr, ref); + } + else { + return do_translate(ref); + } +} + + +} // namespace realm + +#endif // REALM_ALLOC_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/alloc_slab.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/alloc_slab.hpp new file mode 100644 index 0000000..1d2f7e6 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/alloc_slab.hpp @@ -0,0 +1,796 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_ALLOC_SLAB_HPP +#define REALM_ALLOC_SLAB_HPP + +#include // unint8_t etc +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace realm { + +// Pre-declarations +class Group; +class GroupWriter; + +namespace util { +struct SharedFileInfo; +} + +/// Thrown by Group and DB constructors if the specified file +/// (or memory buffer) does not appear to contain a valid Realm +/// database. +struct InvalidDatabase; + + +/// The allocator that is used to manage the memory of a Realm +/// group, i.e., a Realm database. +/// +/// Optionally, it can be attached to an pre-existing database (file +/// or memory buffer) which then becomes an immuatble part of the +/// managed memory. +/// +/// To attach a slab allocator to a pre-existing database, call +/// attach_file() or attach_buffer(). To create a new database +/// in-memory, call attach_empty(). +/// +/// For efficiency, this allocator manages its mutable memory as a set +/// of slabs. +class SlabAlloc : public Allocator { +public: + ~SlabAlloc() noexcept override; + SlabAlloc(); + + // Disable copying. Copying an allocator can produce double frees. + SlabAlloc(const SlabAlloc&) = delete; + SlabAlloc& operator=(const SlabAlloc&) = delete; + + /// \struct Config + /// \brief Storage for combining setup flags for initialization to + /// the SlabAlloc. + /// + /// \var Config::is_shared + /// Must be true if, and only if we are called on behalf of DB. + /// + /// \var Config::read_only + /// Open the file in read-only mode. This implies \a Config::no_create. + /// + /// \var Config::no_create + /// Fail if the file does not already exist. + /// + /// \var Config::skip_validate + /// Skip validation of file header. In a + /// set of overlapping DBs, only the first one (the one + /// that creates/initlializes the coordination file) may validate + /// the header, otherwise it will result in a race condition. + /// + /// \var Config::encryption_key + /// 32-byte key to use to encrypt and decrypt the backing storage, + /// or nullptr to disable encryption. + /// + /// \var Config::session_initiator + /// If set, the caller is the session initiator and + /// guarantees exclusive access to the file. If attaching in + /// read/write mode, the file is modified: files on streaming form + /// is changed to non-streaming form, and if needed the file size + /// is adjusted to match mmap boundaries. + /// Must be set to false if is_shared is false. + /// + /// \var Config::clear_file + /// Always initialize the file as if it was a newly + /// created file and ignore any pre-existing contents. Requires that + /// Config::session_initiator be true as well. + struct Config { + bool is_shared = false; + bool read_only = false; + bool no_create = false; + bool skip_validate = false; + bool session_initiator = false; + bool clear_file = false; + bool disable_sync = false; + const char* encryption_key = nullptr; + }; + + struct Retry { + }; + + /// \brief Attach this allocator to the specified file. + /// + /// It is an error if this function is called at a time where the specified + /// Realm file (file system inode) is modified asynchronously. + /// + /// In non-shared mode (when this function is called on behalf of a + /// free-standing Group instance), it is the responsibility of the + /// application to ensure that the Realm file is not modified concurrently + /// from any other thread or process. + /// + /// In shared mode (when this function is called on behalf of a DB + /// instance), the caller (DB::do_open()) must take steps to ensure + /// cross-process mutual exclusion. + /// + /// Except for \a file_path, the parameters are passed in through a + /// configuration object. + /// + /// \return The `ref` of the root node, or zero if there is none. + /// + /// Please note that attach_file can fail to attach to a file due to a + /// collision with a writer extending the file. This can only happen if the + /// caller is *not* the session initiator. When this happens, attach_file() + /// throws SlabAlloc::Retry, and the caller must retry the call. The caller + /// should check if it has become the session initiator before retrying. + /// This can happen if the conflicting thread (or process) terminates or + /// crashes before the next retry. + /// + /// \throw util::File::AccessError + /// \throw SlabAlloc::Retry + ref_type attach_file(const std::string& file_path, Config& cfg); + + /// Get the attached file. Only valid when called on an allocator with + /// an attached file. + util::File& get_file(); + + /// Attach this allocator to the specified memory buffer. + /// + /// It is an error to call this function on an attached + /// allocator. Doing so will result in undefined behavor. + /// + /// \return The `ref` of the root node, or zero if there is none. + /// + /// \sa own_buffer() + /// + /// \throw InvalidDatabase + ref_type attach_buffer(const char* data, size_t size); + + /// Reads file format from file header. Must be called from within a write + /// transaction. + int get_committed_file_format_version() const noexcept; + + bool is_file_on_streaming_form() const + { + const Header& header = *reinterpret_cast(m_data); + return is_file_on_streaming_form(header); + } + + /// Attach this allocator to an empty buffer. + /// + /// It is an error to call this function on an attached + /// allocator. Doing so will result in undefined behavor. + void attach_empty(); + + /// Detach from a previously attached file or buffer. + /// + /// This function does not reset free space tracking. To + /// completely reset the allocator, you must also call + /// reset_free_space_tracking(). + /// + /// This function has no effect if the allocator is already in the + /// detached state (idempotency). + void detach() noexcept; + + class DetachGuard; + + /// If a memory buffer has been attached using attach_buffer(), + /// mark it as owned by this slab allocator. Behaviour is + /// undefined if this function is called on a detached allocator, + /// one that is not attached using attach_buffer(), or one for + /// which this function has already been called during the latest + /// attachment. + void own_buffer() noexcept; + + /// Returns true if, and only if this allocator is currently + /// in the attached state. + bool is_attached() const noexcept; + + /// Returns true if, and only if this allocator is currently in + /// the attached state and attachment was not established using + /// attach_empty(). + bool nonempty_attachment() const noexcept; + + /// Reserve disk space now to avoid allocation errors at a later + /// point in time, and to minimize on-disk fragmentation. In some + /// cases, less fragmentation translates into improved + /// performance. On flash or SSD-drives this is likely a waste. + /// + /// Note: File::prealloc() may misbehave under race conditions (see + /// documentation of File::prealloc()). For that reason, to avoid race + /// conditions, when this allocator is used in a transactional mode, this + /// function may be called only when the caller has exclusive write + /// access. In non-transactional mode it is the responsibility of the user + /// to ensure non-concurrent file mutation. + /// + /// This function will call File::sync(). + /// + /// It is an error to call this function on an allocator that is not + /// attached to a file. Doing so will result in undefined behavior. + void resize_file(size_t new_file_size); + +#ifdef REALM_DEBUG + /// Deprecated method, only called from a unit test + /// + /// WARNING: This method is NOT thread safe on multiple platforms; see + /// File::prealloc(). + /// + /// Reserve disk space now to avoid allocation errors at a later point in + /// time, and to minimize on-disk fragmentation. In some cases, less + /// fragmentation translates into improved performance. On SSD-drives + /// preallocation is likely a waste. + /// + /// When supported by the system, a call to this function will make the + /// database file at least as big as the specified size, and cause space on + /// the target device to be allocated (note that on many systems on-disk + /// allocation is done lazily by default). If the file is already bigger + /// than the specified size, the size will be unchanged, and on-disk + /// allocation will occur only for the initial section that corresponds to + /// the specified size. + /// + /// This function will call File::sync() if it changes the size of the file. + /// + /// It is an error to call this function on an allocator that is not + /// attached to a file. Doing so will result in undefined behavior. + void reserve_disk_space(size_t size_in_bytes); +#endif + + /// Get the size of the attached database file or buffer in number + /// of bytes. This size is not affected by new allocations. After + /// attachment, it can only be modified by a call to update_reader_view(). + /// + /// It is an error to call this function on a detached allocator, + /// or one that was attached using attach_empty(). Doing so will + /// result in undefined behavior. + size_t get_baseline() const noexcept; + + /// Get the total amount of managed memory. This is the baseline plus the + /// sum of the sizes of the allocated slabs. It includes any free space. + /// + /// It is an error to call this function on a detached + /// allocator. Doing so will result in undefined behavior. + size_t get_total_size() const noexcept; + + /// Mark all mutable memory (ref-space outside the attached file) as free + /// space. + void reset_free_space_tracking(); + + /// Update the readers view of the file: + /// + /// Remap the attached file such that a prefix of the specified + /// size becomes available in memory. If sucessfull, + /// get_baseline() will return the specified new file size. + /// + /// It is an error to call this function on a detached allocator, + /// or one that was not attached using attach_file(). Doing so + /// will result in undefined behavior. + /// + /// The file_size argument must be aligned to a *section* boundary: + /// The database file is logically split into sections, each section + /// guaranteed to be mapped as a contiguous address range. The allocation + /// of memory in the file must ensure that no allocation crosses the + /// boundary between two sections. + /// + /// Updates the memory mappings to reflect a new size for the file. + /// Stale mappings are retained so that they remain valid for other threads, + /// which haven't yet seen the file size change. The stale mappings are + /// associated with a version count if one is provided. + /// They are later purged by calls to purge_old_mappings(). + /// The version parameter is subtly different from the mapping_version obtained + /// by get_mapping_version() below. The mapping version changes whenever a + /// ref->ptr translation changes, and is used by Group to enforce re-translation. + void update_reader_view(size_t file_size); + void purge_old_mappings(uint64_t oldest_live_version, uint64_t youngest_live_version); + void init_mapping_management(uint64_t currently_live_version); + + /// Get an ID for the current mapping version. This ID changes whenever any part + /// of an existing mapping is changed. Such a change requires all refs to be + /// retranslated to new pointers. The allocator tries to avoid this, and we + /// believe it will only ever occur on Windows based platforms. + uint64_t get_mapping_version() + { + return m_mapping_version; + } + + /// Returns true initially, and after a call to reset_free_space_tracking() + /// up until the point of the first call to SlabAlloc::alloc(). Note that a + /// call to SlabAlloc::alloc() corresponds to a mutation event. + bool is_free_space_clean() const noexcept; + + /// Returns the amount of memory requested by calls to SlabAlloc::alloc(). + size_t get_commit_size() const + { + return m_commit_size; + } + + /// Returns the total amount of memory currently allocated in slab area + size_t get_allocated_size() const noexcept; + + /// Returns total amount of slab for all slab allocators + static size_t get_total_slab_size() noexcept; + + /// Hooks used to keep the encryption layer informed of the start and stop + /// of transactions. + void note_reader_start(const void* reader_id); + void note_reader_end(const void* reader_id) noexcept; + + void verify() const override; +#ifdef REALM_DEBUG + void enable_debug(bool enable) + { + m_debug_out = enable; + } + bool is_all_free() const; + void print() const; +#endif + +protected: + MemRef do_alloc(const size_t size) override; + MemRef do_realloc(ref_type, char*, size_t old_size, size_t new_size) override; + // FIXME: It would be very nice if we could detect an invalid free operation in debug mode + void do_free(ref_type, char*) override; + char* do_translate(ref_type) const noexcept override; + + /// Returns the first section boundary *above* the given position. + size_t get_upper_section_boundary(size_t start_pos) const noexcept; + + /// Returns the section boundary at or above the given size + size_t align_size_to_section_boundary(size_t size) const noexcept; + + /// Returns the first section boundary *at or below* the given position. + size_t get_lower_section_boundary(size_t start_pos) const noexcept; + + /// Returns true if the given position is at a section boundary + bool matches_section_boundary(size_t pos) const noexcept; + + /// Actually compute the starting offset of a section. Only used to initialize + /// a table of predefined results, which are then used by get_section_base(). + size_t compute_section_base(size_t index) const noexcept; + + /// Find a possible allocation of 'request_size' that will fit into a section + /// which is inside the range from 'start_pos' to 'start_pos'+'free_chunk_size' + /// If found return the position, if not return 0. + size_t find_section_in_range(size_t start_pos, size_t free_chunk_size, size_t request_size) const noexcept; + +private: + enum AttachMode { + attach_None, // Nothing is attached + attach_OwnedBuffer, // We own the buffer (m_data = nullptr for empty buffer) + attach_UsersBuffer, // We do not own the buffer + attach_SharedFile, // On behalf of DB + attach_UnsharedFile // Not on behalf of DB + }; + + // A slab is a dynamically allocated contiguous chunk of memory used to + // extend the amount of space available for database node + // storage. Inter-node references are represented as file offsets + // (a.k.a. "refs"), and each slab creates an apparently seamless extension + // of this file offset addressable space. Slabs are stored as rows in the + // Slabs table in order of ascending file offsets. + struct Slab { + ref_type ref_end; + char* addr; + size_t size; + + Slab(ref_type r, size_t s); + ~Slab(); + + Slab(const Slab&) = delete; + Slab(Slab&& other) noexcept + : ref_end(other.ref_end) + , size(other.size) + { + addr = other.addr; + other.addr = nullptr; + other.size = 0; + } + }; + + // free blocks that are in the slab area are managed using the following structures: + // - FreeBlock: Placed at the start of any free space. Holds the 'ref' corresponding to + // the start of the space, and prev/next links used to place it in a size-specific + // freelist. + // - BetweenBlocks: Structure sitting between any two free OR allocated spaces. + // describes the size of the space before and after. + // Each slab (area obtained from the underlying system) has a terminating BetweenBlocks + // at the beginning and at the end of the Slab. + struct FreeBlock { + ref_type ref; // ref for this entry. Saves a reverse translate / representing links as refs + FreeBlock* prev; // circular doubly linked list + FreeBlock* next; + void clear_links() + { + prev = next = nullptr; + } + void unlink(); + }; + struct BetweenBlocks { // stores sizes and used/free status of blocks before and after. + int32_t block_before_size; // negated if block is in use, + int32_t block_after_size; // positive if block is free - and zero at end + }; + + Config m_cfg; + using FreeListMap = std::map; // log(N) addressing for larger blocks + FreeListMap m_block_map; + + // abstract notion of a freelist - used to hide whether a freelist + // is residing in the small blocks or the large blocks structures. + struct FreeList { + int size = 0; // size of every element in the list, 0 if not found + FreeListMap::iterator it; + bool found_something() + { + return size != 0; + } + bool found_exact(int sz) + { + return size == sz; + } + }; + + // simple helper functions for accessing/navigating blocks and betweenblocks (TM) + BetweenBlocks* bb_before(FreeBlock* entry) const + { + return reinterpret_cast(entry) - 1; + } + BetweenBlocks* bb_after(FreeBlock* entry) const + { + auto bb = bb_before(entry); + size_t sz = bb->block_after_size; + char* addr = reinterpret_cast(entry) + sz; + return reinterpret_cast(addr); + } + FreeBlock* block_before(BetweenBlocks* bb) const + { + size_t sz = bb->block_before_size; + if (sz <= 0) + return nullptr; // only blocks that are not in use + char* addr = reinterpret_cast(bb) - sz; + return reinterpret_cast(addr); + } + FreeBlock* block_after(BetweenBlocks* bb) const + { + if (bb->block_after_size <= 0) + return nullptr; + return reinterpret_cast(bb + 1); + } + int size_from_block(FreeBlock* entry) const + { + return bb_before(entry)->block_after_size; + } + void mark_allocated(FreeBlock* entry); + // mark the entry freed in bordering BetweenBlocks. Also validate size. + void mark_freed(FreeBlock* entry, int size); + + // hook for the memory verifier in Group. + template + void for_all_free_entries(Func f) const; + + // Main entry points for alloc/free: + FreeBlock* allocate_block(int size); + void free_block(ref_type ref, FreeBlock* addr); + + // Searching/manipulating freelists + FreeList find(int size); + FreeList find_larger(FreeList hint, int size); + FreeBlock* pop_freelist_entry(FreeList list); + void push_freelist_entry(FreeBlock* entry); + void remove_freelist_entry(FreeBlock* element); + void rebuild_freelists_from_slab(); + void clear_freelists(); + + // grow the slab area. + // returns a free block large enough to handle the request. + FreeBlock* grow_slab(int size); + // create a single free chunk with "BetweenBlocks" at both ends and a + // single free chunk between them. This free chunk will be of size: + // slab_size - 2 * sizeof(BetweenBlocks) + FreeBlock* slab_to_entry(const Slab& slab, ref_type ref_start); + + // breaking/merging of blocks + FreeBlock* get_prev_block_if_mergeable(FreeBlock* block); + FreeBlock* get_next_block_if_mergeable(FreeBlock* block); + // break 'block' to give it 'new_size'. Return remaining block. + // If the block is too small to split, return nullptr. + FreeBlock* break_block(FreeBlock* block, int new_size); + FreeBlock* merge_blocks(FreeBlock* first, FreeBlock* second); + + // Values of each used bit in m_flags + enum { + flags_SelectBit = 1, + }; + + // 24 bytes + struct Header { + uint64_t m_top_ref[2]; // 2 * 8 bytes + // Info-block 8-bytes + uint8_t m_mnemonic[4]; // "T-DB" + uint8_t m_file_format[2]; // See `library_file_format` + uint8_t m_reserved; + // bit 0 of m_flags is used to select between the two top refs. + uint8_t m_flags; + }; + + // 16 bytes + struct StreamingFooter { + uint64_t m_top_ref; + uint64_t m_magic_cookie; + }; + + // Description of to-be-deleted memory mapping + struct OldMapping { + OldMapping(uint64_t version, util::File::Map&& map) noexcept + : replaced_at_version(version) + , mapping(std::move(map)) + { + } + OldMapping(OldMapping&& other) noexcept + : replaced_at_version(other.replaced_at_version) + , mapping() + { + mapping = std::move(other.mapping); + } + void operator=(OldMapping&& other) noexcept + { + replaced_at_version = other.replaced_at_version; + mapping = std::move(other.mapping); + } + uint64_t replaced_at_version; + util::File::Map mapping; + }; + struct OldRefTranslation { + OldRefTranslation(uint64_t v, RefTranslation* m) noexcept + { + replaced_at_version = v; + translations = m; + } + uint64_t replaced_at_version; + RefTranslation* translations; + }; + static_assert(sizeof(Header) == 24, "Bad header size"); + static_assert(sizeof(StreamingFooter) == 16, "Bad footer size"); + + static const Header empty_file_header; + static void init_streaming_header(Header*, int file_format_version); + + static const uint_fast64_t footer_magic_cookie = 0x3034125237E526C8ULL; + + util::RaceDetector changes; + + // mappings used by newest transactions - additional mappings may be open + // and in use by older transactions. These translations are in m_old_mappings. + struct MapEntry { + util::File::Map primary_mapping; + size_t lowest_possible_xover_offset = 0; + util::File::Map xover_mapping; + }; + std::vector m_mappings; + size_t m_translation_table_size = 0; + uint64_t m_mapping_version = 1; + uint64_t m_youngest_live_version = 1; + std::mutex m_mapping_mutex; + util::File m_file; + util::SharedFileInfo* m_realm_file_info = nullptr; + // vectors where old mappings, are held from deletion to ensure translations are + // kept open and ref->ptr translations work for other threads.. + std::vector m_old_mappings; + std::vector m_old_translations; + // Rebuild the ref translations in a thread-safe manner. Save the old one along with it's + // versioning information for later deletion - 'requires_new_fast_mapping' must be + // true if there are changes to entries among the existing translations. Must be called + // with m_mapping_mutex locked. + void rebuild_translations(bool requires_new_fast_mapping, size_t old_num_sections); + // Add a translation covering a new section in the slab area. The translation is always + // added at the end. + void extend_fast_mapping_with_slab(char* address); + void get_or_add_xover_mapping(RefTranslation& txl, size_t index, size_t offset, size_t size) override; + + const char* m_data = nullptr; + size_t m_initial_section_size = 0; + int m_section_shifts = 0; + AttachMode m_attach_mode = attach_None; + enum FeeeSpaceState { + free_space_Clean, + free_space_Dirty, + free_space_Invalid, + }; + constexpr static int minimal_alloc = 128 * 1024; + constexpr static int maximal_alloc = 1 << section_shift; + + /// When set to free_space_Invalid, the free lists are no longer + /// up-to-date. This happens if do_free() or + /// reset_free_space_tracking() fails, presumably due to + /// std::bad_alloc being thrown during updating of the free space + /// list. In this this case, alloc(), realloc_(), and + /// get_free_read_only() must throw. This member is deliberately + /// placed here (after m_attach_mode) in the hope that it leads to + /// less padding between members due to alignment requirements. + FeeeSpaceState m_free_space_state = free_space_Clean; + + typedef std::vector Slabs; + using Chunks = std::map; + Slabs m_slabs; + Chunks m_free_read_only; + size_t m_commit_size = 0; + + bool m_debug_out = false; + + /// Throws if free-lists are no longer valid. + size_t consolidate_free_read_only(); + /// Throws if free-lists are no longer valid. + const Chunks& get_free_read_only() const; + + /// Throws InvalidDatabase if the file is not a Realm file, if the file is + /// corrupted, or if the specified encryption key is incorrect. This + /// function will not detect all forms of corruption, though. + /// Returns the top_ref for the latest commit. + ref_type validate_header(const char* data, size_t len, const std::string& path); + ref_type validate_header(const Header* header, const StreamingFooter* footer, size_t size, + const std::string& path); + void throw_header_exception(std::string msg, const Header& header, const std::string& path); + + static bool is_file_on_streaming_form(const Header& header); + /// Read the top_ref from the given buffer and set m_file_on_streaming_form + /// if the buffer contains a file in streaming form + static ref_type get_top_ref(const char* data, size_t len); + + // Gets the path of the attached file, or other relevant debugging info. + std::string get_file_path_for_assertions() const; + + static bool ref_less_than_slab_ref_end(ref_type, const Slab&) noexcept; + + friend class Group; + friend class DB; + friend class GroupWriter; +}; + + +class SlabAlloc::DetachGuard { +public: + DetachGuard(SlabAlloc& alloc) noexcept + : m_alloc(&alloc) + { + } + ~DetachGuard() noexcept; + SlabAlloc* release() noexcept; + +private: + SlabAlloc* m_alloc; +}; + + +// Implementation: + +struct InvalidDatabase : util::File::AccessError { + InvalidDatabase(const std::string& msg, const std::string& path) + : util::File::AccessError(msg, path) + { + } +}; + +inline void SlabAlloc::own_buffer() noexcept +{ + REALM_ASSERT_3(m_attach_mode, ==, attach_UsersBuffer); + REALM_ASSERT(m_data); + m_attach_mode = attach_OwnedBuffer; +} + +inline bool SlabAlloc::is_attached() const noexcept +{ + return m_attach_mode != attach_None; +} + +inline bool SlabAlloc::nonempty_attachment() const noexcept +{ + return is_attached() && m_data; +} + +inline size_t SlabAlloc::get_baseline() const noexcept +{ + REALM_ASSERT_DEBUG(is_attached()); + return m_baseline.load(std::memory_order_relaxed); +} + +inline bool SlabAlloc::is_free_space_clean() const noexcept +{ + return m_free_space_state == free_space_Clean; +} + +inline SlabAlloc::DetachGuard::~DetachGuard() noexcept +{ + if (m_alloc) + m_alloc->detach(); +} + +inline SlabAlloc* SlabAlloc::DetachGuard::release() noexcept +{ + SlabAlloc* alloc = m_alloc; + m_alloc = nullptr; + return alloc; +} + +inline bool SlabAlloc::ref_less_than_slab_ref_end(ref_type ref, const Slab& slab) noexcept +{ + return ref < slab.ref_end; +} + +inline size_t SlabAlloc::get_upper_section_boundary(size_t start_pos) const noexcept +{ + return get_section_base(1 + get_section_index(start_pos)); +} + +inline size_t SlabAlloc::align_size_to_section_boundary(size_t size) const noexcept +{ + if (matches_section_boundary(size)) + return size; + else + return get_upper_section_boundary(size); +} + +inline size_t SlabAlloc::get_lower_section_boundary(size_t start_pos) const noexcept +{ + return get_section_base(get_section_index(start_pos)); +} + +inline bool SlabAlloc::matches_section_boundary(size_t pos) const noexcept +{ + auto boundary = get_lower_section_boundary(pos); + return pos == boundary; +} + +template +void SlabAlloc::for_all_free_entries(Func f) const +{ + ref_type ref = align_size_to_section_boundary(m_baseline.load(std::memory_order_relaxed)); + for (const auto& e : m_slabs) { + BetweenBlocks* bb = reinterpret_cast(e.addr); + REALM_ASSERT(bb->block_before_size == 0); + while (1) { + int size = bb->block_after_size; + f(ref, sizeof(BetweenBlocks)); + ref += sizeof(BetweenBlocks); + if (size == 0) { + break; + } + if (size > 0) { // freeblock. + f(ref, size); + bb = reinterpret_cast(reinterpret_cast(bb) + sizeof(BetweenBlocks) + size); + ref += size; + } + else { + bb = reinterpret_cast(reinterpret_cast(bb) + sizeof(BetweenBlocks) - size); + ref -= size; + } + } + // any gaps in ref-space is reported as a free block to the validator: + auto next_ref = align_size_to_section_boundary(ref); + if (next_ref > ref) { + f(ref, next_ref - ref); + ref = next_ref; + } + } +} + +} // namespace realm + +#endif // REALM_ALLOC_SLAB_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array.hpp new file mode 100644 index 0000000..cd65ea0 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array.hpp @@ -0,0 +1,2383 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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. + * + **************************************************************************/ + +/* +Searching: The main finding function is: + template + void find(int64_t value, size_t start, size_t end, size_t baseindex, QueryState *state, Callback callback) const + + cond: One of Equal, NotEqual, Greater, etc. classes + Action: One of act_ReturnFirst, act_FindAll, act_Max, act_CallbackIdx, etc, constants + Callback: Optional function to call for each search result. Will be called if action == act_CallbackIdx + + find() will call find_action_pattern() or find_action() that again calls match() for each search result which + optionally calls callback(): + + find() -> find_action() -------> bool match() -> bool callback() + | ^ + +-> find_action_pattern()----+ + + If callback() returns false, find() will exit, otherwise it will keep searching remaining items in array. +*/ + +#ifndef REALM_ARRAY_HPP +#define REALM_ARRAY_HPP + +#include + +#include +#include // size_t +#include +#include +#include +#include + +#include // unint8_t etc + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + MMX: mmintrin.h + SSE: xmmintrin.h + SSE2: emmintrin.h + SSE3: pmmintrin.h + SSSE3: tmmintrin.h + SSE4A: ammintrin.h + SSE4.1: smmintrin.h + SSE4.2: nmmintrin.h +*/ +#ifdef REALM_COMPILER_SSE +#include // SSE2 +#include // SSE42 +#endif + +namespace realm { + +template +inline T no0(T v) +{ + return v == 0 ? 1 : v; +} + +// Pre-definitions +struct ObjKey; +class Array; +class GroupWriter; +namespace _impl { +class ArrayWriterBase; +} + +template +class BPlusTree; + +using KeyColumn = BPlusTree; + + +struct MemStats { + size_t allocated = 0; + size_t used = 0; + size_t array_count = 0; +}; + +#ifdef REALM_DEBUG +template +std::basic_ostream& operator<<(std::basic_ostream& out, MemStats stats); +#endif + + +// Stores a value obtained from Array::get(). It is a ref if the least +// significant bit is clear, otherwise it is a tagged integer. A tagged interger +// is obtained from a logical integer value by left shifting by one bit position +// (multiplying by two), and then setting the least significant bit to +// one. Clearly, this means that the maximum value that can be stored as a +// tagged integer is 2**63 - 1. +class RefOrTagged { +public: + bool is_ref() const noexcept; + bool is_tagged() const noexcept; + ref_type get_as_ref() const noexcept; + uint_fast64_t get_as_int() const noexcept; + + static RefOrTagged make_ref(ref_type) noexcept; + static RefOrTagged make_tagged(uint_fast64_t) noexcept; + +private: + int_fast64_t m_value; + RefOrTagged(int_fast64_t) noexcept; + friend class Array; +}; + + +struct TreeInsertBase { + size_t m_split_offset; + size_t m_split_size; +}; + +class Array : public Node, public ArrayParent { +public: + // void state_init(int action, QueryState *state); + // bool match(int action, size_t index, int64_t value, QueryState *state); + + /// Create an array accessor in the unattached state. + explicit Array(Allocator& allocator) noexcept + : Node(allocator) + { + } + + ~Array() noexcept override {} + + /// Create a new integer array of the specified type and size, and filled + /// with the specified value, and attach this accessor to it. This does not + /// modify the parent reference information of this accessor. + /// + /// Note that the caller assumes ownership of the allocated underlying + /// node. It is not owned by the accessor. + void create(Type, bool context_flag = false, size_t size = 0, int_fast64_t value = 0); + + /// Reinitialize this array accessor to point to the specified new + /// underlying memory. This does not modify the parent reference information + /// of this accessor. + void init_from_ref(ref_type ref) noexcept + { + REALM_ASSERT_DEBUG(ref); + char* header = m_alloc.translate(ref); + init_from_mem(MemRef(header, ref, m_alloc)); + } + + /// Same as init_from_ref(ref_type) but avoid the mapping of 'ref' to memory + /// pointer. + void init_from_mem(MemRef) noexcept; + + /// Same as `init_from_ref(get_ref_from_parent())`. + void init_from_parent() noexcept + { + ref_type ref = get_ref_from_parent(); + init_from_ref(ref); + } + + /// Called in the context of Group::commit() to ensure that attached + /// accessors stay valid across a commit. Please note that this works only + /// for non-transactional commits. Accessors obtained during a transaction + /// are always detached when the transaction ends. + /// + /// Returns true if, and only if the array has changed. If the array has not + /// changed, then its children are guaranteed to also not have changed. + bool update_from_parent(size_t old_baseline) noexcept; + + /// Change the type of an already attached array node. + /// + /// The effect of calling this function on an unattached accessor is + /// undefined. + void set_type(Type); + + /// Construct a complete copy of this array (including its subarrays) using + /// the specified target allocator and return just the reference to the + /// underlying memory. + MemRef clone_deep(Allocator& target_alloc) const; + + /// Construct an empty integer array of the specified type, and return just + /// the reference to the underlying memory. + static MemRef create_empty_array(Type, bool context_flag, Allocator&); + + /// Construct an integer array of the specified type and size, and return + /// just the reference to the underlying memory. All elements will be + /// initialized to the specified value. + static MemRef create_array(Type, bool context_flag, size_t size, int_fast64_t value, Allocator&); + + Type get_type() const noexcept; + + /// The meaning of 'width' depends on the context in which this + /// array is used. + size_t get_width() const noexcept + { + REALM_ASSERT_3(m_width, ==, get_width_from_header(get_header())); + return m_width; + } + + static void add_to_column(IntegerColumn* column, int64_t value); + static void add_to_column(KeyColumn* column, int64_t value); + + void insert(size_t ndx, int_fast64_t value); + void add(int_fast64_t value); + + // Used from ArrayBlob + size_t blob_size() const noexcept; + ref_type blob_replace(size_t begin, size_t end, const char* data, size_t data_size, bool add_zero_term); + + /// This function is guaranteed to not throw if the current width is + /// sufficient for the specified value (e.g. if you have called + /// ensure_minimum_width(value)) and get_alloc().is_read_only(get_ref()) + /// returns false (noexcept:array-set). Note that for a value of zero, the + /// first criterion is trivially satisfied. + void set(size_t ndx, int64_t value); + + void set_as_ref(size_t ndx, ref_type ref); + + template + void set(size_t ndx, int64_t value); + + int64_t get(size_t ndx) const noexcept; + + template + int64_t get(size_t ndx) const noexcept; + + void get_chunk(size_t ndx, int64_t res[8]) const noexcept; + + template + void get_chunk(size_t ndx, int64_t res[8]) const noexcept; + + ref_type get_as_ref(size_t ndx) const noexcept; + + RefOrTagged get_as_ref_or_tagged(size_t ndx) const noexcept; + void set(size_t ndx, RefOrTagged); + void add(RefOrTagged); + void ensure_minimum_width(RefOrTagged); + + int64_t front() const noexcept; + int64_t back() const noexcept; + + void alloc(size_t init_size, size_t new_width) + { + REALM_ASSERT_3(m_width, ==, get_width_from_header(get_header())); + REALM_ASSERT_3(m_size, ==, get_size_from_header(get_header())); + Node::alloc(init_size, new_width); + update_width_cache_from_header(); + } + + /// Remove the element at the specified index, and move elements at higher + /// indexes to the next lower index. + /// + /// This function does **not** destroy removed subarrays. That is, if the + /// erased element is a 'ref' pointing to a subarray, then that subarray + /// will not be destroyed automatically. + /// + /// This function guarantees that no exceptions will be thrown if + /// get_alloc().is_read_only(get_ref()) would return false before the + /// call. This is automatically guaranteed if the array is used in a + /// non-transactional context, or if the array has already been successfully + /// modified within the current write transaction. + void erase(size_t ndx); + + /// Same as erase(size_t), but remove all elements in the specified + /// range. + /// + /// Please note that this function does **not** destroy removed subarrays. + /// + /// This function guarantees that no exceptions will be thrown if + /// get_alloc().is_read_only(get_ref()) would return false before the call. + void erase(size_t begin, size_t end); + + /// Reduce the size of this array to the specified number of elements. It is + /// an error to specify a size that is greater than the current size of this + /// array. The effect of doing so is undefined. This is just a shorthand for + /// calling the ranged erase() function with appropriate arguments. + /// + /// Please note that this function does **not** destroy removed + /// subarrays. See clear_and_destroy_children() for an alternative. + /// + /// This function guarantees that no exceptions will be thrown if + /// get_alloc().is_read_only(get_ref()) would return false before the call. + void truncate(size_t new_size); + + /// Reduce the size of this array to the specified number of elements. It is + /// an error to specify a size that is greater than the current size of this + /// array. The effect of doing so is undefined. Subarrays will be destroyed + /// recursively, as if by a call to `destroy_deep(subarray_ref, alloc)`. + /// + /// This function is guaranteed not to throw if + /// get_alloc().is_read_only(get_ref()) returns false. + void truncate_and_destroy_children(size_t new_size); + + /// Remove every element from this array. This is just a shorthand for + /// calling truncate(0). + /// + /// Please note that this function does **not** destroy removed + /// subarrays. See clear_and_destroy_children() for an alternative. + /// + /// This function guarantees that no exceptions will be thrown if + /// get_alloc().is_read_only(get_ref()) would return false before the call. + void clear(); + + /// Remove every element in this array. Subarrays will be destroyed + /// recursively, as if by a call to `destroy_deep(subarray_ref, + /// alloc)`. This is just a shorthand for calling + /// truncate_and_destroy_children(0). + /// + /// This function guarantees that no exceptions will be thrown if + /// get_alloc().is_read_only(get_ref()) would return false before the call. + void clear_and_destroy_children(); + + /// If neccessary, expand the representation so that it can store the + /// specified value. + void ensure_minimum_width(int_fast64_t value); + + /// This one may change the represenation of the array, so be carefull if + /// you call it after ensure_minimum_width(). + void set_all_to_zero(); + + /// Add \a diff to the element at the specified index. + void adjust(size_t ndx, int_fast64_t diff); + + /// Add \a diff to all the elements in the specified index range. + void adjust(size_t begin, size_t end, int_fast64_t diff); + + //@{ + /// This is similar in spirit to std::move() from ``. + /// \a dest_begin must not be in the range [`begin`,`end`) + /// + /// This function is guaranteed to not throw if + /// `get_alloc().is_read_only(get_ref())` returns false. + void move(size_t begin, size_t end, size_t dest_begin); + //@} + + // Move elements from ndx and above to another array + void move(Array& dst, size_t ndx); + + //@{ + /// Find the lower/upper bound of the specified value in a sequence of + /// integers which must already be sorted ascendingly. + /// + /// For an integer value '`v`', lower_bound_int(v) returns the index '`l`' + /// of the first element such that `get(l) ≥ v`, and upper_bound_int(v) + /// returns the index '`u`' of the first element such that `get(u) > + /// v`. In both cases, if no such element is found, the returned value is + /// the number of elements in the array. + /// + /// 3 3 3 4 4 4 5 6 7 9 9 9 + /// ^ ^ ^ ^ ^ + /// | | | | | + /// | | | | -- Lower and upper bound of 15 + /// | | | | + /// | | | -- Lower and upper bound of 8 + /// | | | + /// | | -- Upper bound of 4 + /// | | + /// | -- Lower bound of 4 + /// | + /// -- Lower and upper bound of 1 + /// + /// These functions are similar to std::lower_bound() and + /// std::upper_bound(). + /// + /// We currently use binary search. See for example + /// http://www.tbray.org/ongoing/When/200x/2003/03/22/Binary. + /// + /// FIXME: It may be worth considering if overall efficiency can be improved + /// by doing a linear search for short sequences. + size_t lower_bound_int(int64_t value) const noexcept; + size_t upper_bound_int(int64_t value) const noexcept; + //@} + + int64_t get_sum(size_t start = 0, size_t end = size_t(-1)) const + { + return sum(start, end); + } + + /// This information is guaranteed to be cached in the array accessor. + bool is_inner_bptree_node() const noexcept; + + /// Returns true if type is either type_HasRefs or type_InnerColumnNode. + /// + /// This information is guaranteed to be cached in the array accessor. + bool has_refs() const noexcept; + void set_has_refs(bool) noexcept; + + /// This information is guaranteed to be cached in the array accessor. + /// + /// Columns and indexes can use the context bit to differentiate leaf types. + bool get_context_flag() const noexcept; + void set_context_flag(bool) noexcept; + + /// Recursively destroy children (as if calling + /// clear_and_destroy_children()), then put this accessor into the detached + /// state (as if calling detach()), then free the allocated memory. If this + /// accessor is already in the detached state, this function has no effect + /// (idempotency). + void destroy_deep() noexcept; + + /// Shorthand for `destroy_deep(MemRef(ref, alloc), alloc)`. + static void destroy_deep(ref_type ref, Allocator& alloc) noexcept; + + /// Destroy the specified array node and all of its children, recursively. + /// + /// This is done by freeing the specified array node after calling + /// destroy_deep() for every contained 'ref' element. + static void destroy_deep(MemRef, Allocator&) noexcept; + + // Clone deep + static MemRef clone(MemRef, Allocator& from_alloc, Allocator& target_alloc); + + // Serialization + + /// Returns the ref (position in the target stream) of the written copy of + /// this array, or the ref of the original array if \a only_if_modified is + /// true, and this array is unmodified (Alloc::is_read_only()). + /// + /// The number of bytes that will be written by a non-recursive invocation + /// of this function is exactly the number returned by get_byte_size(). + /// + /// \param out The destination stream (writer). + /// + /// \param deep If true, recursively write out subarrays, but still subject + /// to \a only_if_modified. + /// + /// \param only_if_modified Set to `false` to always write, or to `true` to + /// only write the array if it has been modified. + ref_type write(_impl::ArrayWriterBase& out, bool deep, bool only_if_modified) const; + + /// Same as non-static write() with `deep` set to true. This is for the + /// cases where you do not already have an array accessor available. + static ref_type write(ref_type, Allocator&, _impl::ArrayWriterBase&, bool only_if_modified); + + // Main finding function - used for find_first, find_all, sum, max, min, etc. + bool find(int cond, Action action, int64_t value, size_t start, size_t end, size_t baseindex, + QueryState* state, bool nullable_array = false, bool find_null = false) const; + + // Templated find function to avoid conversion to and from integer represenation of condition + template + bool find(Action action, int64_t value, size_t start, size_t end, size_t baseindex, QueryState* state, + bool nullable_array = false, bool find_null = false) const + { + if (action == act_ReturnFirst) { + REALM_TEMPEX3(return find, cond, act_ReturnFirst, m_width, + (value, start, end, baseindex, state, CallbackDummy(), nullable_array, find_null)) + } + else if (action == act_Sum) { + REALM_TEMPEX3(return find, cond, act_Sum, m_width, + (value, start, end, baseindex, state, CallbackDummy(), nullable_array, find_null)) + } + else if (action == act_Min) { + REALM_TEMPEX3(return find, cond, act_Min, m_width, + (value, start, end, baseindex, state, CallbackDummy(), nullable_array, find_null)) + } + else if (action == act_Max) { + REALM_TEMPEX3(return find, cond, act_Max, m_width, + (value, start, end, baseindex, state, CallbackDummy(), nullable_array, find_null)) + } + else if (action == act_Count) { + REALM_TEMPEX3(return find, cond, act_Count, m_width, + (value, start, end, baseindex, state, CallbackDummy(), nullable_array, find_null)) + } + else if (action == act_FindAll) { + REALM_TEMPEX3(return find, cond, act_FindAll, m_width, + (value, start, end, baseindex, state, CallbackDummy(), nullable_array, find_null)) + } + else if (action == act_CallbackIdx) { + REALM_TEMPEX3(return find, cond, act_CallbackIdx, m_width, + (value, start, end, baseindex, state, CallbackDummy(), nullable_array, find_null)) + } + REALM_ASSERT_DEBUG(false); + return false; + } + + + /* + bool find(int cond, Action action, null, size_t start, size_t end, size_t baseindex, + QueryState* state) const; + */ + + template + bool find(int64_t value, size_t start, size_t end, size_t baseindex, QueryState* state, + Callback callback, bool nullable_array = false, bool find_null = false) const; + + // This is the one installed into the m_vtable->finder slots. + template + bool find(int64_t value, size_t start, size_t end, size_t baseindex, QueryState* state) const; + + template + bool find(int64_t value, size_t start, size_t end, size_t baseindex, QueryState* state, + Callback callback, bool nullable_array = false, bool find_null = false) const; + + /* + template + bool find(null, size_t start, size_t end, size_t baseindex, + QueryState* state, Callback callback) const; + */ + + // Optimized implementation for release mode + template + bool find_optimized(int64_t value, size_t start, size_t end, size_t baseindex, QueryState* state, + Callback callback, bool nullable_array = false, bool find_null = false) const; + + // Called for each search result + template + bool find_action(size_t index, util::Optional value, QueryState* state, + Callback callback) const; + + template + bool find_action_pattern(size_t index, uint64_t pattern, QueryState* state, Callback callback) const; + + // Wrappers for backwards compatibility and for simple use without + // setting up state initialization etc + template + size_t find_first(int64_t value, size_t start = 0, size_t end = size_t(-1)) const; + + void find_all(IntegerColumn* result, int64_t value, size_t col_offset = 0, size_t begin = 0, + size_t end = size_t(-1)) const; + + size_t find_first(int64_t value, size_t begin = 0, size_t end = size_t(-1)) const; + + // Non-SSE find for the four functions Equal/NotEqual/Less/Greater + template + bool compare(int64_t value, size_t start, size_t end, size_t baseindex, QueryState* state, + Callback callback) const; + + // Non-SSE find for Equal/NotEqual + template + inline bool compare_equality(int64_t value, size_t start, size_t end, size_t baseindex, + QueryState* state, Callback callback) const; + + // Non-SSE find for Less/Greater + template + bool compare_relation(int64_t value, size_t start, size_t end, size_t baseindex, QueryState* state, + Callback callback) const; + + template + bool compare_leafs_4(const Array* foreign, size_t start, size_t end, size_t baseindex, QueryState* state, + Callback callback) const; + + template + bool compare_leafs(const Array* foreign, size_t start, size_t end, size_t baseindex, QueryState* state, + Callback callback) const; + + template + bool compare_leafs(const Array* foreign, size_t start, size_t end, size_t baseindex, QueryState* state, + Callback callback) const; + + template + bool compare_leafs(const Array* foreign, size_t start, size_t end, size_t baseindex, QueryState* state, + Callback callback) const; + +// SSE find for the four functions Equal/NotEqual/Less/Greater +#ifdef REALM_COMPILER_SSE + template + bool find_sse(int64_t value, __m128i* data, size_t items, QueryState* state, size_t baseindex, + Callback callback) const; + + template + REALM_FORCEINLINE bool find_sse_intern(__m128i* action_data, __m128i* data, size_t items, + QueryState* state, size_t baseindex, Callback callback) const; + +#endif + + template + inline bool test_zero(uint64_t value) const; // Tests value for 0-elements + + template + size_t find_zero(uint64_t v) const; // Finds position of 0/non-zero element + + template + uint64_t cascade(uint64_t a) const; // Sets lowermost bits of zero or non-zero elements + + template + int64_t + find_gtlt_magic(int64_t v) const; // Compute magic constant needed for searching for value 'v' using bit hacks + + template + inline int64_t lower_bits() const; // Return chunk with lower bit set in each element + + size_t first_set_bit(unsigned int v) const; + size_t first_set_bit64(int64_t v) const; + + template + int64_t get_universal(const char* const data, const size_t ndx) const; + + // Find value greater/less in 64-bit chunk - only works for positive values + template + bool find_gtlt_fast(uint64_t chunk, uint64_t magic, QueryState* state, size_t baseindex, + Callback callback) const; + + // Find value greater/less in 64-bit chunk - no constraints + template + bool find_gtlt(int64_t v, uint64_t chunk, QueryState* state, size_t baseindex, Callback callback) const; + + /// Get the specified element without the cost of constructing an + /// array instance. If an array instance is already available, or + /// you need to get multiple values, then this method will be + /// slower. + static int_fast64_t get(const char* header, size_t ndx) noexcept; + + /// Like get(const char*, size_t) but gets two consecutive + /// elements. + static std::pair get_two(const char* header, size_t ndx) noexcept; + + static void get_three(const char* data, size_t ndx, ref_type& v0, ref_type& v1, ref_type& v2) noexcept; + + static RefOrTagged get_as_ref_or_tagged(const char* header, size_t ndx) noexcept + { + return get(header, ndx); + } + + /// Get the number of bytes currently in use by this array. This + /// includes the array header, but it does not include allocated + /// bytes corresponding to excess capacity. The result is + /// guaranteed to be a multiple of 8 (i.e., 64-bit aligned). + /// + /// This number is exactly the number of bytes that will be + /// written by a non-recursive invocation of write(). + size_t get_byte_size() const noexcept; + + /// Get the maximum number of bytes that can be written by a + /// non-recursive invocation of write() on an array with the + /// specified number of elements, that is, the maximum value that + /// can be returned by get_byte_size(). + static size_t get_max_byte_size(size_t num_elems) noexcept; + + /// FIXME: Belongs in IntegerArray + static size_t calc_aligned_byte_size(size_t size, int width); + + class MemUsageHandler { + public: + virtual void handle(ref_type ref, size_t allocated, size_t used) = 0; + }; + + void report_memory_usage(MemUsageHandler&) const; + + void stats(MemStats& stats_dest) const noexcept; + + void verify() const; + + Array& operator=(const Array&) = delete; // not allowed + Array(const Array&) = delete; // not allowed +protected: + typedef bool (*CallbackDummy)(int64_t); + +protected: + // This returns the minimum value ("lower bound") of the representable values + // for the given bit width. Valid widths are 0, 1, 2, 4, 8, 16, 32, and 64. + static int_fast64_t lbound_for_width(size_t width) noexcept; + + // This returns the maximum value ("inclusive upper bound") of the representable values + // for the given bit width. Valid widths are 0, 1, 2, 4, 8, 16, 32, and 64. + static int_fast64_t ubound_for_width(size_t width) noexcept; + +private: + void update_width_cache_from_header() noexcept; + + void do_ensure_minimum_width(int_fast64_t); + + int64_t sum(size_t start, size_t end) const; + size_t count(int64_t value) const noexcept; + + bool maximum(int64_t& result, size_t start = 0, size_t end = size_t(-1), size_t* return_ndx = nullptr) const; + + bool minimum(int64_t& result, size_t start = 0, size_t end = size_t(-1), size_t* return_ndx = nullptr) const; + + template + int64_t sum(size_t start, size_t end) const; + + template + bool minmax(int64_t& result, size_t start, size_t end, size_t* return_ndx) const; + +protected: + /// It is an error to specify a non-zero value unless the width + /// type is wtype_Bits. It is also an error to specify a non-zero + /// size if the width type is wtype_Ignore. + static MemRef create(Type, bool context_flag, WidthType, size_t size, int_fast64_t value, Allocator&); + + // Overriding method in ArrayParent + void update_child_ref(size_t, ref_type) override; + + // Overriding method in ArrayParent + ref_type get_child_ref(size_t) const noexcept override; + + void destroy_children(size_t offset = 0) noexcept; + +protected: + // Getters and Setters for adaptive-packed arrays + typedef int64_t (Array::*Getter)(size_t) const; // Note: getters must not throw + typedef void (Array::*Setter)(size_t, int64_t); + typedef bool (Array::*Finder)(int64_t, size_t, size_t, size_t, QueryState*) const; + typedef void (Array::*ChunkGetter)(size_t, int64_t res[8]) const; // Note: getters must not throw + + struct VTable { + Getter getter; + ChunkGetter chunk_getter; + Setter setter; + Finder finder[cond_VTABLE_FINDER_COUNT]; // one for each active function pointer + }; + template + struct VTableForWidth; + +protected: + /// Takes a 64-bit value and returns the minimum number of bits needed + /// to fit the value. For alignment this is rounded up to nearest + /// log2. Posssible results {0, 1, 2, 4, 8, 16, 32, 64} + static size_t bit_width(int64_t value); + + void report_memory_usage_2(MemUsageHandler&) const; + +private: + Getter m_getter = nullptr; // cached to avoid indirection + const VTable* m_vtable = nullptr; + +protected: + uint_least8_t m_width = 0; // Size of an element (meaning depend on type of array). + int64_t m_lbound; // min number that can be stored with current m_width + int64_t m_ubound; // max number that can be stored with current m_width + + bool m_is_inner_bptree_node; // This array is an inner node of B+-tree. + bool m_has_refs; // Elements whose first bit is zero are refs to subarrays. + bool m_context_flag; // Meaning depends on context. + +private: + ref_type do_write_shallow(_impl::ArrayWriterBase&) const; + ref_type do_write_deep(_impl::ArrayWriterBase&, bool only_if_modified) const; + + friend class Allocator; + friend class SlabAlloc; + friend class GroupWriter; +}; + +class ClusterKeyArray : public ArrayUnsigned { +public: + using ArrayUnsigned::ArrayUnsigned; + + uint64_t get(size_t ndx) const + { + return (m_data != nullptr) ? ArrayUnsigned::get(ndx) : uint64_t(ndx); + } +}; + +// Implementation: +template <> +class QueryState : public QueryStateBase { +public: + int64_t m_state = 0; + + template + bool uses_val() + { + if (action == act_Max || action == act_Min || action == act_Sum) + return true; + else + return false; + } + + QueryState(Action action, size_t limit = -1) + : QueryState(action, int64_t(0), limit) + { + } + + QueryState(Action action, KeyColumn* akku, size_t limit = -1) + : QueryState(action, reinterpret_cast(akku), limit) + { + } + QueryState(Action action, IntegerColumn* akku, size_t limit = -1) + : QueryState(action, reinterpret_cast(akku), limit) + { + } + + template + inline bool match(size_t index, uint64_t indexpattern, int64_t value) + { + if (pattern) { + if (action == act_Count) { + // If we are close to 'limit' argument in query, we cannot count-up a complete chunk. Count up single + // elements instead + if (m_match_count + 64 >= m_limit) + return false; + + m_state += fast_popcount64(indexpattern); + m_match_count = size_t(m_state); + return true; + } + // Other aggregates cannot (yet) use bit pattern for anything. Make Array-finder call with pattern = false + // instead + return false; + } + + ++m_match_count; + + if (action == act_Max) { + if (value > m_state) { + m_state = value; + m_minmax_index = m_key_values ? m_key_values->get(index) + m_key_offset : index; + } + } + else if (action == act_Min) { + if (value < m_state) { + m_state = value; + m_minmax_index = m_key_values ? m_key_values->get(index) + m_key_offset : index; + } + } + else if (action == act_Sum) + m_state += value; + else if (action == act_Count) { + m_state++; + m_match_count = size_t(m_state); + } + else if (action == act_FindAll) { + if (m_key_values) { + int64_t key_value = m_key_values->get(index) + m_key_offset; + Array::add_to_column(reinterpret_cast(m_state), key_value); + } + else { + Array::add_to_column(reinterpret_cast(m_state), index); + } + } + else if (action == act_ReturnFirst) { + m_state = index; + return false; + } + else { + REALM_ASSERT_DEBUG(false); + } + return (m_limit > m_match_count); + } + + template + inline bool match(size_t index, uint64_t indexpattern, util::Optional value) + { + // FIXME: This is a temporary hack for nullable integers. + if (value) { + return match(index, indexpattern, *value); + } + + // If value is null, the only sensible actions are count, find_all, and return first. + // Max, min, and sum should all have no effect. + if (action == act_Count) { + m_state++; + m_match_count = size_t(m_state); + } + else if (action == act_FindAll) { + if (m_key_values) { + int64_t key_value = m_key_values->get(index) + m_key_offset; + Array::add_to_column(reinterpret_cast(m_state), key_value); + } + else { + Array::add_to_column(reinterpret_cast(m_state), index); + } + } + else if (action == act_ReturnFirst) { + m_match_count++; + m_state = index; + return false; + } + return m_limit > m_match_count; + } + +private: + QueryState(Action action, int64_t akku, size_t limit) + : QueryStateBase(limit) + { + if (action == act_Max) + m_state = std::numeric_limits::min(); + else if (action == act_Min) + m_state = std::numeric_limits::max(); + else if (action == act_ReturnFirst) + m_state = not_found; + else if (action == act_Sum) + m_state = 0; + else if (action == act_Count) + m_state = 0; + else if (action == act_FindAll) + m_state = akku; + else if (action == act_CallbackIdx) { + } + else { + REALM_ASSERT_DEBUG(false); + } + } +}; + +inline bool RefOrTagged::is_ref() const noexcept +{ + return (m_value & 1) == 0; +} + +inline bool RefOrTagged::is_tagged() const noexcept +{ + return !is_ref(); +} + +inline ref_type RefOrTagged::get_as_ref() const noexcept +{ + // to_ref() is defined in + return to_ref(m_value); +} + +inline uint_fast64_t RefOrTagged::get_as_int() const noexcept +{ + // The bitwise AND is there in case uint_fast64_t is wider than 64 bits. + return (uint_fast64_t(m_value) & 0xFFFFFFFFFFFFFFFFULL) >> 1; +} + +inline RefOrTagged RefOrTagged::make_ref(ref_type ref) noexcept +{ + // from_ref() is defined in + int_fast64_t value = from_ref(ref); + return RefOrTagged(value); +} + +inline RefOrTagged RefOrTagged::make_tagged(uint_fast64_t i) noexcept +{ + REALM_ASSERT(i < (1ULL << 63)); + return RefOrTagged((i << 1) | 1); +} + +inline RefOrTagged::RefOrTagged(int_fast64_t value) noexcept + : m_value(value) +{ +} + +inline void Array::create(Type type, bool context_flag, size_t length, int_fast64_t value) +{ + MemRef mem = create_array(type, context_flag, length, value, m_alloc); // Throws + init_from_mem(mem); +} + + +inline Array::Type Array::get_type() const noexcept +{ + if (m_is_inner_bptree_node) { + REALM_ASSERT_DEBUG(m_has_refs); + return type_InnerBptreeNode; + } + if (m_has_refs) + return type_HasRefs; + return type_Normal; +} + + +inline void Array::get_chunk(size_t ndx, int64_t res[8]) const noexcept +{ + REALM_ASSERT_DEBUG(ndx < m_size); + (this->*(m_vtable->chunk_getter))(ndx, res); +} + + +inline int64_t Array::get(size_t ndx) const noexcept +{ + REALM_ASSERT_DEBUG(is_attached()); + REALM_ASSERT_DEBUG(ndx < m_size); + return (this->*m_getter)(ndx); + + // Two ideas that are not efficient but may be worth looking into again: + /* + // Assume correct width is found early in REALM_TEMPEX, which is the case for B tree offsets that + // are probably either 2^16 long. Turns out to be 25% faster if found immediately, but 50-300% slower + // if found later + REALM_TEMPEX(return get, (ndx)); + */ + /* + // Slightly slower in both of the if-cases. Also needs an matchcount m_size check too, to avoid + // reading beyond array. + if (m_width >= 8 && m_size > ndx + 7) + return get<64>(ndx >> m_shift) & m_widthmask; + else + return (this->*(m_vtable->getter))(ndx); + */ +} + +inline int64_t Array::front() const noexcept +{ + return get(0); +} + +inline int64_t Array::back() const noexcept +{ + return get(m_size - 1); +} + +inline ref_type Array::get_as_ref(size_t ndx) const noexcept +{ + REALM_ASSERT_DEBUG(is_attached()); + REALM_ASSERT_DEBUG(m_has_refs); + int64_t v = get(ndx); + return to_ref(v); +} + +inline RefOrTagged Array::get_as_ref_or_tagged(size_t ndx) const noexcept +{ + REALM_ASSERT(has_refs()); + return RefOrTagged(get(ndx)); +} + +inline void Array::set(size_t ndx, RefOrTagged ref_or_tagged) +{ + REALM_ASSERT(has_refs()); + set(ndx, ref_or_tagged.m_value); // Throws +} + +inline void Array::add(RefOrTagged ref_or_tagged) +{ + REALM_ASSERT(has_refs()); + add(ref_or_tagged.m_value); // Throws +} + +inline void Array::ensure_minimum_width(RefOrTagged ref_or_tagged) +{ + REALM_ASSERT(has_refs()); + ensure_minimum_width(ref_or_tagged.m_value); // Throws +} + +inline bool Array::is_inner_bptree_node() const noexcept +{ + return m_is_inner_bptree_node; +} + +inline bool Array::has_refs() const noexcept +{ + return m_has_refs; +} + +inline void Array::set_has_refs(bool value) noexcept +{ + if (m_has_refs != value) { + REALM_ASSERT(!is_read_only()); + m_has_refs = value; + set_hasrefs_in_header(value, get_header()); + } +} + +inline bool Array::get_context_flag() const noexcept +{ + return m_context_flag; +} + +inline void Array::set_context_flag(bool value) noexcept +{ + if (m_context_flag != value) { + copy_on_write(); + m_context_flag = value; + set_context_flag_in_header(value, get_header()); + } +} + +inline void Array::destroy_deep() noexcept +{ + if (!is_attached()) + return; + + if (m_has_refs) + destroy_children(); + + char* header = get_header_from_data(m_data); + m_alloc.free_(m_ref, header); + m_data = nullptr; +} + +inline ref_type Array::write(_impl::ArrayWriterBase& out, bool deep, bool only_if_modified) const +{ + REALM_ASSERT(is_attached()); + + if (only_if_modified && m_alloc.is_read_only(m_ref)) + return m_ref; + + if (!deep || !m_has_refs) + return do_write_shallow(out); // Throws + + return do_write_deep(out, only_if_modified); // Throws +} + +inline ref_type Array::write(ref_type ref, Allocator& alloc, _impl::ArrayWriterBase& out, bool only_if_modified) +{ + if (only_if_modified && alloc.is_read_only(ref)) + return ref; + + Array array(alloc); + array.init_from_ref(ref); + + if (!array.m_has_refs) + return array.do_write_shallow(out); // Throws + + return array.do_write_deep(out, only_if_modified); // Throws +} + +inline void Array::add(int_fast64_t value) +{ + insert(m_size, value); +} + +inline void Array::erase(size_t ndx) +{ + // This can throw, but only if array is currently in read-only + // memory. + move(ndx + 1, size(), ndx); + + // Update size (also in header) + --m_size; + set_header_size(m_size); +} + + +inline void Array::erase(size_t begin, size_t end) +{ + if (begin != end) { + // This can throw, but only if array is currently in read-only memory. + move(end, size(), begin); // Throws + + // Update size (also in header) + m_size -= end - begin; + set_header_size(m_size); + } +} + +inline void Array::clear() +{ + truncate(0); // Throws +} + +inline void Array::clear_and_destroy_children() +{ + truncate_and_destroy_children(0); +} + +inline void Array::destroy_deep(ref_type ref, Allocator& alloc) noexcept +{ + destroy_deep(MemRef(ref, alloc), alloc); +} + +inline void Array::destroy_deep(MemRef mem, Allocator& alloc) noexcept +{ + if (!get_hasrefs_from_header(mem.get_addr())) { + alloc.free_(mem); + return; + } + Array array(alloc); + array.init_from_mem(mem); + array.destroy_deep(); +} + + +inline void Array::adjust(size_t ndx, int_fast64_t diff) +{ + REALM_ASSERT_3(ndx, <=, m_size); + if (diff != 0) { + // FIXME: Should be optimized + int_fast64_t v = get(ndx); + set(ndx, int64_t(v + diff)); // Throws + } +} + +inline void Array::adjust(size_t begin, size_t end, int_fast64_t diff) +{ + if (diff != 0) { + // FIXME: Should be optimized + for (size_t i = begin; i != end; ++i) + adjust(i, diff); // Throws + } +} + + +//------------------------------------------------- + + +inline size_t Array::get_byte_size() const noexcept +{ + const char* header = get_header_from_data(m_data); + WidthType wtype = Node::get_wtype_from_header(header); + size_t num_bytes = NodeHeader::calc_byte_size(wtype, m_size, m_width); + + REALM_ASSERT_7(m_alloc.is_read_only(m_ref), ==, true, ||, num_bytes, <=, get_capacity_from_header(header)); + + return num_bytes; +} + + +//------------------------------------------------- + +inline MemRef Array::clone_deep(Allocator& target_alloc) const +{ + char* header = get_header_from_data(m_data); + return clone(MemRef(header, m_ref, m_alloc), m_alloc, target_alloc); // Throws +} + +inline MemRef Array::create_empty_array(Type type, bool context_flag, Allocator& alloc) +{ + size_t size = 0; + int_fast64_t value = 0; + return create_array(type, context_flag, size, value, alloc); // Throws +} + +inline MemRef Array::create_array(Type type, bool context_flag, size_t size, int_fast64_t value, Allocator& alloc) +{ + return create(type, context_flag, wtype_Bits, size, value, alloc); // Throws +} + +inline size_t Array::get_max_byte_size(size_t num_elems) noexcept +{ + int max_bytes_per_elem = 8; + return header_size + num_elems * max_bytes_per_elem; +} + + +inline void Array::update_child_ref(size_t child_ndx, ref_type new_ref) +{ + set(child_ndx, new_ref); +} + +inline ref_type Array::get_child_ref(size_t child_ndx) const noexcept +{ + return get_as_ref(child_ndx); +} + +inline void Array::ensure_minimum_width(int_fast64_t value) +{ + if (value >= m_lbound && value <= m_ubound) + return; + do_ensure_minimum_width(value); +} + + +//************************************************************************************* +// Finding code * +//************************************************************************************* + +template +int64_t Array::get(size_t ndx) const noexcept +{ + return get_universal(m_data, ndx); +} + +template +int64_t Array::get_universal(const char* data, size_t ndx) const +{ + if (w == 0) { + return 0; + } + else if (w == 1) { + size_t offset = ndx >> 3; + return (data[offset] >> (ndx & 7)) & 0x01; + } + else if (w == 2) { + size_t offset = ndx >> 2; + return (data[offset] >> ((ndx & 3) << 1)) & 0x03; + } + else if (w == 4) { + size_t offset = ndx >> 1; + return (data[offset] >> ((ndx & 1) << 2)) & 0x0F; + } + else if (w == 8) { + return *reinterpret_cast(data + ndx); + } + else if (w == 16) { + size_t offset = ndx * 2; + return *reinterpret_cast(data + offset); + } + else if (w == 32) { + size_t offset = ndx * 4; + return *reinterpret_cast(data + offset); + } + else if (w == 64) { + size_t offset = ndx * 8; + return *reinterpret_cast(data + offset); + } + else { + REALM_ASSERT_DEBUG(false); + return int64_t(-1); + } +} + +/* +find() (calls find_optimized()) will call match() for each search result. + +If pattern == true: + 'indexpattern' contains a 64-bit chunk of elements, each of 'width' bits in size where each element indicates a + match if its lower bit is set, otherwise it indicates a non-match. 'index' tells the database row index of the + first element. You must return true if you chose to 'consume' the chunk or false if not. If not, then Array-finder + will afterwards call match() successive times with pattern == false. + +If pattern == false: + 'index' tells the row index of a single match and 'value' tells its value. Return false to make Array-finder break + its search or return true to let it continue until 'end' or 'limit'. + +Array-finder decides itself if - and when - it wants to pass you an indexpattern. It depends on array bit width, match +frequency, and whether the arithemetic and computations for the given search criteria makes it feasible to construct +such a pattern. +*/ + +// These wrapper functions only exist to enable a possibility to make the compiler see that 'value' and/or 'index' are +// unused, such that caller's computation of these values will not be made. Only works if find_action() and +// find_action_pattern() rewritten as macros. Note: This problem has been fixed in next upcoming array.hpp version +template +bool Array::find_action(size_t index, util::Optional value, QueryState* state, + Callback callback) const +{ + if (action == act_CallbackIdx) + return callback(index); + else + return state->match(index, 0, value); +} +template +bool Array::find_action_pattern(size_t index, uint64_t pattern, QueryState* state, Callback callback) const +{ + static_cast(callback); + if (action == act_CallbackIdx) { + // Possible future optimization: call callback(index) like in above find_action(), in a loop for each bit set + // in 'pattern' + return false; + } + return state->match(index, pattern, 0); +} + + +template +uint64_t Array::cascade(uint64_t a) const +{ + // Takes a chunk of values as argument and sets the least significant bit for each + // element which is zero or non-zero, depending on the template parameter. + // Example for zero=true: + // width == 4 and a = 0x5fd07a107610f610 + // will return: 0x0001000100010001 + + // static values needed for fast population count + const uint64_t m1 = 0x5555555555555555ULL; + + if (width == 1) { + return zero ? ~a : a; + } + else if (width == 2) { + // Masks to avoid spillover between segments in cascades + const uint64_t c1 = ~0ULL / 0x3 * 0x1; + + a |= (a >> 1) & c1; // cascade ones in non-zeroed segments + a &= m1; // isolate single bit in each segment + if (zero) + a ^= m1; // reverse isolated bits if checking for zeroed segments + + return a; + } + else if (width == 4) { + const uint64_t m = ~0ULL / 0xF * 0x1; + + // Masks to avoid spillover between segments in cascades + const uint64_t c1 = ~0ULL / 0xF * 0x7; + const uint64_t c2 = ~0ULL / 0xF * 0x3; + + a |= (a >> 1) & c1; // cascade ones in non-zeroed segments + a |= (a >> 2) & c2; + a &= m; // isolate single bit in each segment + if (zero) + a ^= m; // reverse isolated bits if checking for zeroed segments + + return a; + } + else if (width == 8) { + const uint64_t m = ~0ULL / 0xFF * 0x1; + + // Masks to avoid spillover between segments in cascades + const uint64_t c1 = ~0ULL / 0xFF * 0x7F; + const uint64_t c2 = ~0ULL / 0xFF * 0x3F; + const uint64_t c3 = ~0ULL / 0xFF * 0x0F; + + a |= (a >> 1) & c1; // cascade ones in non-zeroed segments + a |= (a >> 2) & c2; + a |= (a >> 4) & c3; + a &= m; // isolate single bit in each segment + if (zero) + a ^= m; // reverse isolated bits if checking for zeroed segments + + return a; + } + else if (width == 16) { + const uint64_t m = ~0ULL / 0xFFFF * 0x1; + + // Masks to avoid spillover between segments in cascades + const uint64_t c1 = ~0ULL / 0xFFFF * 0x7FFF; + const uint64_t c2 = ~0ULL / 0xFFFF * 0x3FFF; + const uint64_t c3 = ~0ULL / 0xFFFF * 0x0FFF; + const uint64_t c4 = ~0ULL / 0xFFFF * 0x00FF; + + a |= (a >> 1) & c1; // cascade ones in non-zeroed segments + a |= (a >> 2) & c2; + a |= (a >> 4) & c3; + a |= (a >> 8) & c4; + a &= m; // isolate single bit in each segment + if (zero) + a ^= m; // reverse isolated bits if checking for zeroed segments + + return a; + } + + else if (width == 32) { + const uint64_t m = ~0ULL / 0xFFFFFFFF * 0x1; + + // Masks to avoid spillover between segments in cascades + const uint64_t c1 = ~0ULL / 0xFFFFFFFF * 0x7FFFFFFF; + const uint64_t c2 = ~0ULL / 0xFFFFFFFF * 0x3FFFFFFF; + const uint64_t c3 = ~0ULL / 0xFFFFFFFF * 0x0FFFFFFF; + const uint64_t c4 = ~0ULL / 0xFFFFFFFF * 0x00FFFFFF; + const uint64_t c5 = ~0ULL / 0xFFFFFFFF * 0x0000FFFF; + + a |= (a >> 1) & c1; // cascade ones in non-zeroed segments + a |= (a >> 2) & c2; + a |= (a >> 4) & c3; + a |= (a >> 8) & c4; + a |= (a >> 16) & c5; + a &= m; // isolate single bit in each segment + if (zero) + a ^= m; // reverse isolated bits if checking for zeroed segments + + return a; + } + else if (width == 64) { + return (a == 0) == zero; + } + else { + REALM_ASSERT_DEBUG(false); + return uint64_t(-1); + } +} + +// This is the main finding function for Array. Other finding functions are just wrappers around this one. +// Search for 'value' using condition cond (Equal, NotEqual, Less, etc) and call find_action() or +// find_action_pattern() for each match. Break and return if find_action() returns false or 'end' is reached. + +// If nullable_array is set, then find_optimized() will treat the array is being nullable, i.e. it will skip the +// first entry and compare correctly against null, etc. +// +// If find_null is set, it means that we search for a null. In that case, `value` is ignored. If find_null is set, +// then nullable_array must be set too. +template +bool Array::find_optimized(int64_t value, size_t start, size_t end, size_t baseindex, QueryState* state, + Callback callback, bool nullable_array, bool find_null) const +{ + REALM_ASSERT(!(find_null && !nullable_array)); + REALM_ASSERT_DEBUG(start <= m_size && (end <= m_size || end == size_t(-1)) && start <= end); + + size_t start2 = start; + cond c; + + if (end == npos) + end = nullable_array ? size() - 1 : size(); + + if (nullable_array) { + if (std::is_same::value) { + // In case of Equal it is safe to use the optimized logic. We just have to fetch the null value + // if this is what we are looking for. And we have to adjust the indexes to compensate for the + // null value at position 0. + if (find_null) { + value = get(0); + } + else { + // If the value to search for is equal to the null value, the value cannot be in the array + if (value == get(0)) { + return true; + } + } + start2++; + end++; + baseindex--; + } + else { + // We were called by find() of a nullable array. So skip first entry, take nulls in count, etc, etc. + // Fixme: + // Huge speed optimizations are possible here! This is a very simple generic method. + auto null_value = get(0); + for (; start2 < end; start2++) { + int64_t v = get(start2 + 1); + bool value_is_null = (v == null_value); + if (c(v, value, value_is_null, find_null)) { + util::Optional v2(value_is_null ? util::none : util::make_optional(v)); + if (!find_action(start2 + baseindex, v2, state, callback)) + return false; // tell caller to stop aggregating/search + } + } + return true; // tell caller to continue aggregating/search (on next array leafs) + } + } + + + // Test first few items with no initial time overhead + if (start2 > 0) { + if (m_size > start2 && c(get(start2), value) && start2 < end) { + if (!find_action(start2 + baseindex, get(start2), state, callback)) + return false; + } + + ++start2; + + if (m_size > start2 && c(get(start2), value) && start2 < end) { + if (!find_action(start2 + baseindex, get(start2), state, callback)) + return false; + } + + ++start2; + + if (m_size > start2 && c(get(start2), value) && start2 < end) { + if (!find_action(start2 + baseindex, get(start2), state, callback)) + return false; + } + + ++start2; + + if (m_size > start2 && c(get(start2), value) && start2 < end) { + if (!find_action(start2 + baseindex, get(start2), state, callback)) + return false; + } + + ++start2; + } + + if (!(m_size > start2 && start2 < end)) + return true; + + if (end == size_t(-1)) + end = m_size; + + // Return immediately if no items in array can match (such as if cond == Greater && value == 100 && + // m_ubound == 15) + if (!c.can_match(value, m_lbound, m_ubound)) + return true; + + // optimization if all items are guaranteed to match (such as cond == NotEqual && value == 100 && m_ubound == 15) + if (c.will_match(value, m_lbound, m_ubound)) { + size_t end2; + + if (action == act_CallbackIdx) + end2 = end; + else { + REALM_ASSERT_DEBUG(state->m_match_count < state->m_limit); + size_t process = state->m_limit - state->m_match_count; + end2 = end - start2 > process ? start2 + process : end; + } + if (action == act_Sum || action == act_Max || action == act_Min) { + int64_t res; + size_t res_ndx = 0; + if (action == act_Sum) + res = Array::sum(start2, end2); + if (action == act_Max) + Array::maximum(res, start2, end2, &res_ndx); + if (action == act_Min) + Array::minimum(res, start2, end2, &res_ndx); + + find_action(res_ndx + baseindex, res, state, callback); + // find_action will increment match count by 1, so we need to `-1` from the number of elements that + // we performed the fast Array methods on. + state->m_match_count += end2 - start2 - 1; + } + else if (action == act_Count) { + state->m_state += end2 - start2; + } + else { + for (; start2 < end2; start2++) + if (!find_action(start2 + baseindex, get(start2), state, callback)) + return false; + } + return true; + } + + // finder cannot handle this bitwidth + REALM_ASSERT_3(m_width, !=, 0); + +#if defined(REALM_COMPILER_SSE) + // Only use SSE if payload is at least one SSE chunk (128 bits) in size. Also note taht SSE doesn't support + // Less-than comparison for 64-bit values. + if ((!(std::is_same::value && m_width == 64)) && end - start2 >= sizeof(__m128i) && m_width >= 8 && + (sseavx<42>() || (sseavx<30>() && std::is_same::value && m_width < 64))) { + + // find_sse() must start2 at 16-byte boundary, so search area before that using compare_equality() + __m128i* const a = reinterpret_cast<__m128i*>(round_up(m_data + start2 * bitwidth / 8, sizeof(__m128i))); + __m128i* const b = reinterpret_cast<__m128i*>(round_down(m_data + end * bitwidth / 8, sizeof(__m128i))); + + if (!compare( + value, start2, (reinterpret_cast(a) - m_data) * 8 / no0(bitwidth), baseindex, state, callback)) + return false; + + // Search aligned area with SSE + if (b > a) { + if (sseavx<42>()) { + if (!find_sse( + value, a, b - a, state, + baseindex + ((reinterpret_cast(a) - m_data) * 8 / no0(bitwidth)), callback)) + return false; + } + else if (sseavx<30>()) { + + if (!find_sse( + value, a, b - a, state, + baseindex + ((reinterpret_cast(a) - m_data) * 8 / no0(bitwidth)), callback)) + return false; + } + } + + // Search remainder with compare_equality() + if (!compare( + value, (reinterpret_cast(b) - m_data) * 8 / no0(bitwidth), end, baseindex, state, callback)) + return false; + + return true; + } + else { + return compare(value, start2, end, baseindex, state, callback); + } +#else + return compare(value, start2, end, baseindex, state, callback); +#endif +} + +template +inline int64_t Array::lower_bits() const +{ + if (width == 1) + return 0xFFFFFFFFFFFFFFFFULL; + else if (width == 2) + return 0x5555555555555555ULL; + else if (width == 4) + return 0x1111111111111111ULL; + else if (width == 8) + return 0x0101010101010101ULL; + else if (width == 16) + return 0x0001000100010001ULL; + else if (width == 32) + return 0x0000000100000001ULL; + else if (width == 64) + return 0x0000000000000001ULL; + else { + REALM_ASSERT_DEBUG(false); + return int64_t(-1); + } +} + +// Tests if any chunk in 'value' is 0 +template +inline bool Array::test_zero(uint64_t value) const +{ + uint64_t hasZeroByte; + uint64_t lower = lower_bits(); + uint64_t upper = lower_bits() * 1ULL << (width == 0 ? 0 : (width - 1ULL)); + hasZeroByte = (value - lower) & ~value & upper; + return hasZeroByte != 0; +} + +// Finds first zero (if eq == true) or non-zero (if eq == false) element in v and returns its position. +// IMPORTANT: This function assumes that at least 1 item matches (test this with test_zero() or other means first)! +template +size_t Array::find_zero(uint64_t v) const +{ + size_t start = 0; + uint64_t hasZeroByte; + // Warning free way of computing (1ULL << width) - 1 + uint64_t mask = (width == 64 ? ~0ULL : ((1ULL << (width == 64 ? 0 : width)) - 1ULL)); + + if (eq == (((v >> (width * start)) & mask) == 0)) { + return 0; + } + + // Bisection optimization, speeds up small bitwidths with high match frequency. More partions than 2 do NOT pay + // off because the work done by test_zero() is wasted for the cases where the value exists in first half, but + // useful if it exists in last half. Sweet spot turns out to be the widths and partitions below. + if (width <= 8) { + hasZeroByte = test_zero(v | 0xffffffff00000000ULL); + if (eq ? !hasZeroByte : (v & 0x00000000ffffffffULL) == 0) { + // 00?? -> increasing + start += 64 / no0(width) / 2; + if (width <= 4) { + hasZeroByte = test_zero(v | 0xffff000000000000ULL); + if (eq ? !hasZeroByte : (v & 0x0000ffffffffffffULL) == 0) { + // 000? + start += 64 / no0(width) / 4; + } + } + } + else { + if (width <= 4) { + // ??00 + hasZeroByte = test_zero(v | 0xffffffffffff0000ULL); + if (eq ? !hasZeroByte : (v & 0x000000000000ffffULL) == 0) { + // 0?00 + start += 64 / no0(width) / 4; + } + } + } + } + + while (eq == (((v >> (width * start)) & mask) != 0)) { + // You must only call find_zero() if you are sure that at least 1 item matches + REALM_ASSERT_3(start, <=, 8 * sizeof(v)); + start++; + } + + return start; +} + +// Generate a magic constant used for later bithacks +template +int64_t Array::find_gtlt_magic(int64_t v) const +{ + uint64_t mask1 = + (width == 64 + ? ~0ULL + : ((1ULL << (width == 64 ? 0 : width)) - 1ULL)); // Warning free way of computing (1ULL << width) - 1 + uint64_t mask2 = mask1 >> 1; + uint64_t magic = gt ? (~0ULL / no0(mask1) * (mask2 - v)) : (~0ULL / no0(mask1) * v); + return magic; +} + +template +bool Array::find_gtlt_fast(uint64_t chunk, uint64_t magic, QueryState* state, size_t baseindex, + Callback callback) const +{ + // Tests if a a chunk of values contains values that are greater (if gt == true) or less (if gt == false) than v. + // Fast, but limited to work when all values in the chunk are positive. + + uint64_t mask1 = + (width == 64 + ? ~0ULL + : ((1ULL << (width == 64 ? 0 : width)) - 1ULL)); // Warning free way of computing (1ULL << width) - 1 + uint64_t mask2 = mask1 >> 1; + uint64_t m = gt ? (((chunk + magic) | chunk) & ~0ULL / no0(mask1) * (mask2 + 1)) + : ((chunk - magic) & ~chunk & ~0ULL / no0(mask1) * (mask2 + 1)); + size_t p = 0; + while (m) { + if (find_action_pattern(baseindex, m >> (no0(width) - 1), state, callback)) + break; // consumed, so do not call find_action() + + size_t t = first_set_bit64(m) / no0(width); + p += t; + if (!find_action(p + baseindex, (chunk >> (p * width)) & mask1, state, callback)) + return false; + + if ((t + 1) * width == 64) + m = 0; + else + m >>= (t + 1) * width; + p++; + } + + return true; +} + +// clang-format off +template +bool Array::find_gtlt(int64_t v, uint64_t chunk, QueryState* state, size_t baseindex, Callback callback) const +{ + // Find items in 'chunk' that are greater (if gt == true) or smaller (if gt == false) than 'v'. Fixme, __forceinline can make it crash in vS2010 - find out why + if (width == 1) { + for (size_t t = 0; t < 64; t++) { + if (gt ? static_cast(chunk & 0x1) > v : static_cast(chunk & 0x1) < v) {if (!find_action( t + baseindex, static_cast(chunk & 0x1), state, callback)) return false;} + chunk >>= 1; + } + } + else if (width == 2) { + // Alot (50% +) faster than loop/compiler-unrolled loop + if (gt ? static_cast(chunk & 0x3) > v : static_cast(chunk & 0x3) < v) {if (!find_action( 0 + baseindex, static_cast(chunk & 0x3), state, callback)) return false;} + chunk >>= 2; + if (gt ? static_cast(chunk & 0x3) > v : static_cast(chunk & 0x3) < v) {if (!find_action( 1 + baseindex, static_cast(chunk & 0x3), state, callback)) return false;} + chunk >>= 2; + if (gt ? static_cast(chunk & 0x3) > v : static_cast(chunk & 0x3) < v) {if (!find_action( 2 + baseindex, static_cast(chunk & 0x3), state, callback)) return false;} + chunk >>= 2; + if (gt ? static_cast(chunk & 0x3) > v : static_cast(chunk & 0x3) < v) {if (!find_action( 3 + baseindex, static_cast(chunk & 0x3), state, callback)) return false;} + chunk >>= 2; + if (gt ? static_cast(chunk & 0x3) > v : static_cast(chunk & 0x3) < v) {if (!find_action( 4 + baseindex, static_cast(chunk & 0x3), state, callback)) return false;} + chunk >>= 2; + if (gt ? static_cast(chunk & 0x3) > v : static_cast(chunk & 0x3) < v) {if (!find_action( 5 + baseindex, static_cast(chunk & 0x3), state, callback)) return false;} + chunk >>= 2; + if (gt ? static_cast(chunk & 0x3) > v : static_cast(chunk & 0x3) < v) {if (!find_action( 6 + baseindex, static_cast(chunk & 0x3), state, callback)) return false;} + chunk >>= 2; + if (gt ? static_cast(chunk & 0x3) > v : static_cast(chunk & 0x3) < v) {if (!find_action( 7 + baseindex, static_cast(chunk & 0x3), state, callback)) return false;} + chunk >>= 2; + + if (gt ? static_cast(chunk & 0x3) > v : static_cast(chunk & 0x3) < v) {if (!find_action( 8 + baseindex, static_cast(chunk & 0x3), state, callback)) return false;} + chunk >>= 2; + if (gt ? static_cast(chunk & 0x3) > v : static_cast(chunk & 0x3) < v) {if (!find_action( 9 + baseindex, static_cast(chunk & 0x3), state, callback)) return false;} + chunk >>= 2; + if (gt ? static_cast(chunk & 0x3) > v : static_cast(chunk & 0x3) < v) {if (!find_action( 10 + baseindex, static_cast(chunk & 0x3), state, callback)) return false;} + chunk >>= 2; + if (gt ? static_cast(chunk & 0x3) > v : static_cast(chunk & 0x3) < v) {if (!find_action( 11 + baseindex, static_cast(chunk & 0x3), state, callback)) return false;} + chunk >>= 2; + if (gt ? static_cast(chunk & 0x3) > v : static_cast(chunk & 0x3) < v) {if (!find_action( 12 + baseindex, static_cast(chunk & 0x3), state, callback)) return false;} + chunk >>= 2; + if (gt ? static_cast(chunk & 0x3) > v : static_cast(chunk & 0x3) < v) {if (!find_action( 13 + baseindex, static_cast(chunk & 0x3), state, callback)) return false;} + chunk >>= 2; + if (gt ? static_cast(chunk & 0x3) > v : static_cast(chunk & 0x3) < v) {if (!find_action( 14 + baseindex, static_cast(chunk & 0x3), state, callback)) return false;} + chunk >>= 2; + if (gt ? static_cast(chunk & 0x3) > v : static_cast(chunk & 0x3) < v) {if (!find_action( 15 + baseindex, static_cast(chunk & 0x3), state, callback)) return false;} + chunk >>= 2; + + if (gt ? static_cast(chunk & 0x3) > v : static_cast(chunk & 0x3) < v) {if (!find_action( 16 + baseindex, static_cast(chunk & 0x3), state, callback)) return false;} + chunk >>= 2; + if (gt ? static_cast(chunk & 0x3) > v : static_cast(chunk & 0x3) < v) {if (!find_action( 17 + baseindex, static_cast(chunk & 0x3), state, callback)) return false;} + chunk >>= 2; + if (gt ? static_cast(chunk & 0x3) > v : static_cast(chunk & 0x3) < v) {if (!find_action( 18 + baseindex, static_cast(chunk & 0x3), state, callback)) return false;} + chunk >>= 2; + if (gt ? static_cast(chunk & 0x3) > v : static_cast(chunk & 0x3) < v) {if (!find_action( 19 + baseindex, static_cast(chunk & 0x3), state, callback)) return false;} + chunk >>= 2; + if (gt ? static_cast(chunk & 0x3) > v : static_cast(chunk & 0x3) < v) {if (!find_action( 20 + baseindex, static_cast(chunk & 0x3), state, callback)) return false;} + chunk >>= 2; + if (gt ? static_cast(chunk & 0x3) > v : static_cast(chunk & 0x3) < v) {if (!find_action( 21 + baseindex, static_cast(chunk & 0x3), state, callback)) return false;} + chunk >>= 2; + if (gt ? static_cast(chunk & 0x3) > v : static_cast(chunk & 0x3) < v) {if (!find_action( 22 + baseindex, static_cast(chunk & 0x3), state, callback)) return false;} + chunk >>= 2; + if (gt ? static_cast(chunk & 0x3) > v : static_cast(chunk & 0x3) < v) {if (!find_action( 23 + baseindex, static_cast(chunk & 0x3), state, callback)) return false;} + chunk >>= 2; + + if (gt ? static_cast(chunk & 0x3) > v : static_cast(chunk & 0x3) < v) {if (!find_action( 24 + baseindex, static_cast(chunk & 0x3), state, callback)) return false;} + chunk >>= 2; + if (gt ? static_cast(chunk & 0x3) > v : static_cast(chunk & 0x3) < v) {if (!find_action( 25 + baseindex, static_cast(chunk & 0x3), state, callback)) return false;} + chunk >>= 2; + if (gt ? static_cast(chunk & 0x3) > v : static_cast(chunk & 0x3) < v) {if (!find_action( 26 + baseindex, static_cast(chunk & 0x3), state, callback)) return false;} + chunk >>= 2; + if (gt ? static_cast(chunk & 0x3) > v : static_cast(chunk & 0x3) < v) {if (!find_action( 27 + baseindex, static_cast(chunk & 0x3), state, callback)) return false;} + chunk >>= 2; + if (gt ? static_cast(chunk & 0x3) > v : static_cast(chunk & 0x3) < v) {if (!find_action( 28 + baseindex, static_cast(chunk & 0x3), state, callback)) return false;} + chunk >>= 2; + if (gt ? static_cast(chunk & 0x3) > v : static_cast(chunk & 0x3) < v) {if (!find_action( 29 + baseindex, static_cast(chunk & 0x3), state, callback)) return false;} + chunk >>= 2; + if (gt ? static_cast(chunk & 0x3) > v : static_cast(chunk & 0x3) < v) {if (!find_action( 30 + baseindex, static_cast(chunk & 0x3), state, callback)) return false;} + chunk >>= 2; + if (gt ? static_cast(chunk & 0x3) > v : static_cast(chunk & 0x3) < v) {if (!find_action( 31 + baseindex, static_cast(chunk & 0x3), state, callback)) return false;} + chunk >>= 2; + } + else if (width == 4) { + if (gt ? static_cast(chunk & 0xf) > v : static_cast(chunk & 0xf) < v) {if (!find_action( 0 + baseindex, static_cast(chunk & 0xf), state, callback)) return false;} + chunk >>= 4; + if (gt ? static_cast(chunk & 0xf) > v : static_cast(chunk & 0xf) < v) {if (!find_action( 1 + baseindex, static_cast(chunk & 0xf), state, callback)) return false;} + chunk >>= 4; + if (gt ? static_cast(chunk & 0xf) > v : static_cast(chunk & 0xf) < v) {if (!find_action( 2 + baseindex, static_cast(chunk & 0xf), state, callback)) return false;} + chunk >>= 4; + if (gt ? static_cast(chunk & 0xf) > v : static_cast(chunk & 0xf) < v) {if (!find_action( 3 + baseindex, static_cast(chunk & 0xf), state, callback)) return false;} + chunk >>= 4; + if (gt ? static_cast(chunk & 0xf) > v : static_cast(chunk & 0xf) < v) {if (!find_action( 4 + baseindex, static_cast(chunk & 0xf), state, callback)) return false;} + chunk >>= 4; + if (gt ? static_cast(chunk & 0xf) > v : static_cast(chunk & 0xf) < v) {if (!find_action( 5 + baseindex, static_cast(chunk & 0xf), state, callback)) return false;} + chunk >>= 4; + if (gt ? static_cast(chunk & 0xf) > v : static_cast(chunk & 0xf) < v) {if (!find_action( 6 + baseindex, static_cast(chunk & 0xf), state, callback)) return false;} + chunk >>= 4; + if (gt ? static_cast(chunk & 0xf) > v : static_cast(chunk & 0xf) < v) {if (!find_action( 7 + baseindex, static_cast(chunk & 0xf), state, callback)) return false;} + chunk >>= 4; + + if (gt ? static_cast(chunk & 0xf) > v : static_cast(chunk & 0xf) < v) {if (!find_action( 8 + baseindex, static_cast(chunk & 0xf), state, callback)) return false;} + chunk >>= 4; + if (gt ? static_cast(chunk & 0xf) > v : static_cast(chunk & 0xf) < v) {if (!find_action( 9 + baseindex, static_cast(chunk & 0xf), state, callback)) return false;} + chunk >>= 4; + if (gt ? static_cast(chunk & 0xf) > v : static_cast(chunk & 0xf) < v) {if (!find_action( 10 + baseindex, static_cast(chunk & 0xf), state, callback)) return false;} + chunk >>= 4; + if (gt ? static_cast(chunk & 0xf) > v : static_cast(chunk & 0xf) < v) {if (!find_action( 11 + baseindex, static_cast(chunk & 0xf), state, callback)) return false;} + chunk >>= 4; + if (gt ? static_cast(chunk & 0xf) > v : static_cast(chunk & 0xf) < v) {if (!find_action( 12 + baseindex, static_cast(chunk & 0xf), state, callback)) return false;} + chunk >>= 4; + if (gt ? static_cast(chunk & 0xf) > v : static_cast(chunk & 0xf) < v) {if (!find_action( 13 + baseindex, static_cast(chunk & 0xf), state, callback)) return false;} + chunk >>= 4; + if (gt ? static_cast(chunk & 0xf) > v : static_cast(chunk & 0xf) < v) {if (!find_action( 14 + baseindex, static_cast(chunk & 0xf), state, callback)) return false;} + chunk >>= 4; + if (gt ? static_cast(chunk & 0xf) > v : static_cast(chunk & 0xf) < v) {if (!find_action( 15 + baseindex, static_cast(chunk & 0xf), state, callback)) return false;} + chunk >>= 4; + } + else if (width == 8) { + if (gt ? static_cast(chunk) > v : static_cast(chunk) < v) {if (!find_action( 0 + baseindex, static_cast(chunk), state, callback)) return false;} + chunk >>= 8; + if (gt ? static_cast(chunk) > v : static_cast(chunk) < v) {if (!find_action( 1 + baseindex, static_cast(chunk), state, callback)) return false;} + chunk >>= 8; + if (gt ? static_cast(chunk) > v : static_cast(chunk) < v) {if (!find_action( 2 + baseindex, static_cast(chunk), state, callback)) return false;} + chunk >>= 8; + if (gt ? static_cast(chunk) > v : static_cast(chunk) < v) {if (!find_action( 3 + baseindex, static_cast(chunk), state, callback)) return false;} + chunk >>= 8; + if (gt ? static_cast(chunk) > v : static_cast(chunk) < v) {if (!find_action( 4 + baseindex, static_cast(chunk), state, callback)) return false;} + chunk >>= 8; + if (gt ? static_cast(chunk) > v : static_cast(chunk) < v) {if (!find_action( 5 + baseindex, static_cast(chunk), state, callback)) return false;} + chunk >>= 8; + if (gt ? static_cast(chunk) > v : static_cast(chunk) < v) {if (!find_action( 6 + baseindex, static_cast(chunk), state, callback)) return false;} + chunk >>= 8; + if (gt ? static_cast(chunk) > v : static_cast(chunk) < v) {if (!find_action( 7 + baseindex, static_cast(chunk), state, callback)) return false;} + chunk >>= 8; + } + else if (width == 16) { + + if (gt ? static_cast(chunk >> 0 * 16) > v : static_cast(chunk >> 0 * 16) < v) {if (!find_action( 0 + baseindex, static_cast(chunk >> 0 * 16), state, callback)) return false;}; + if (gt ? static_cast(chunk >> 1 * 16) > v : static_cast(chunk >> 1 * 16) < v) {if (!find_action( 1 + baseindex, static_cast(chunk >> 1 * 16), state, callback)) return false;}; + if (gt ? static_cast(chunk >> 2 * 16) > v : static_cast(chunk >> 2 * 16) < v) {if (!find_action( 2 + baseindex, static_cast(chunk >> 2 * 16), state, callback)) return false;}; + if (gt ? static_cast(chunk >> 3 * 16) > v : static_cast(chunk >> 3 * 16) < v) {if (!find_action( 3 + baseindex, static_cast(chunk >> 3 * 16), state, callback)) return false;}; + } + else if (width == 32) { + if (gt ? static_cast(chunk) > v : static_cast(chunk) < v) {if (!find_action( 0 + baseindex, static_cast(chunk), state, callback)) return false;} + chunk >>= 32; + if (gt ? static_cast(chunk) > v : static_cast(chunk) < v) {if (!find_action( 1 + baseindex, static_cast(chunk), state, callback)) return false;} + chunk >>= 32; + } + else if (width == 64) { + if (gt ? static_cast(v) > v : static_cast(v) < v) {if (!find_action( 0 + baseindex, static_cast(v), state, callback)) return false;}; + } + + return true; +} +// clang-format on + +/// Find items in this Array that are equal (eq == true) or different (eq = false) from 'value' +template +inline bool Array::compare_equality(int64_t value, size_t start, size_t end, size_t baseindex, + QueryState* state, Callback callback) const +{ + REALM_ASSERT_DEBUG(start <= m_size && (end <= m_size || end == size_t(-1)) && start <= end); + + size_t ee = round_up(start, 64 / no0(width)); + ee = ee > end ? end : ee; + for (; start < ee; ++start) + if (eq ? (get(start) == value) : (get(start) != value)) { + if (!find_action(start + baseindex, get(start), state, callback)) + return false; + } + + if (start >= end) + return true; + + if (width != 32 && width != 64) { + const int64_t* p = reinterpret_cast(m_data + (start * width / 8)); + const int64_t* const e = reinterpret_cast(m_data + (end * width / 8)) - 1; + const uint64_t mask = + (width == 64 + ? ~0ULL + : ((1ULL << (width == 64 ? 0 : width)) - 1ULL)); // Warning free way of computing (1ULL << width) - 1 + const uint64_t valuemask = + ~0ULL / no0(mask) * (value & mask); // the "== ? :" is to avoid division by 0 compiler error + + while (p < e) { + uint64_t chunk = *p; + uint64_t v2 = chunk ^ valuemask; + start = (p - reinterpret_cast(m_data)) * 8 * 8 / no0(width); + size_t a = 0; + + while (eq ? test_zero(v2) : v2) { + + if (find_action_pattern(start + baseindex, cascade(v2), state, callback)) + break; // consumed + + size_t t = find_zero(v2); + a += t; + + if (a >= 64 / no0(width)) + break; + + if (!find_action(a + start + baseindex, get(start + a), state, callback)) + return false; + v2 >>= (t + 1) * width; + a += 1; + } + + ++p; + } + + // Loop ended because we are near end or end of array. No need to optimize search in remainder in this case + // because end of array means that + // lots of search work has taken place prior to ending here. So time spent searching remainder is relatively + // tiny + start = (p - reinterpret_cast(m_data)) * 8 * 8 / no0(width); + } + + while (start < end) { + if (eq ? get(start) == value : get(start) != value) { + if (!find_action(start + baseindex, get(start), state, callback)) + return false; + } + ++start; + } + + return true; +} + +// There exists a couple of find() functions that take more or less template arguments. Always call the one that +// takes as most as possible to get best performance. + +// This is the one installed into the m_vtable->finder slots. +template +bool Array::find(int64_t value, size_t start, size_t end, size_t baseindex, QueryState* state) const +{ + return find(value, start, end, baseindex, state, CallbackDummy()); +} + +template +bool Array::find(int64_t value, size_t start, size_t end, size_t baseindex, QueryState* state, + Callback callback, bool nullable_array, bool find_null) const +{ + REALM_TEMPEX4(return find, cond, action, m_width, Callback, + (value, start, end, baseindex, state, callback, nullable_array, find_null)); +} + +template +bool Array::find(int64_t value, size_t start, size_t end, size_t baseindex, QueryState* state, + Callback callback, bool nullable_array, bool find_null) const +{ + return find_optimized(value, start, end, baseindex, state, callback, + nullable_array, find_null); +} + +#ifdef REALM_COMPILER_SSE +// 'items' is the number of 16-byte SSE chunks. Returns index of packed element relative to first integer of first +// chunk +template +bool Array::find_sse(int64_t value, __m128i* data, size_t items, QueryState* state, size_t baseindex, + Callback callback) const +{ + __m128i search = {0}; + + if (width == 8) + search = _mm_set1_epi8(static_cast(value)); + else if (width == 16) + search = _mm_set1_epi16(static_cast(value)); + else if (width == 32) + search = _mm_set1_epi32(static_cast(value)); + else if (width == 64) { + if (std::is_same::value) + REALM_ASSERT(false); + else + search = _mm_set_epi64x(value, value); + } + + return find_sse_intern(data, &search, items, state, baseindex, callback); +} + +// Compares packed action_data with packed data (equal, less, etc) and performs aggregate action (max, min, sum, +// find_all, etc) on value inside action_data for first match, if any +template +REALM_FORCEINLINE bool Array::find_sse_intern(__m128i* action_data, __m128i* data, size_t items, + QueryState* state, size_t baseindex, Callback callback) const +{ + size_t i = 0; + __m128i compare_result = {0}; + unsigned int resmask; + + // Search loop. Unrolling it has been tested to NOT increase performance (apparently mem bound) + for (i = 0; i < items; ++i) { + // equal / not-equal + if (std::is_same::value || std::is_same::value) { + if (width == 8) + compare_result = _mm_cmpeq_epi8(action_data[i], *data); + if (width == 16) + compare_result = _mm_cmpeq_epi16(action_data[i], *data); + if (width == 32) + compare_result = _mm_cmpeq_epi32(action_data[i], *data); + if (width == 64) { + compare_result = _mm_cmpeq_epi64(action_data[i], *data); // SSE 4.2 only + } + } + + // greater + else if (std::is_same::value) { + if (width == 8) + compare_result = _mm_cmpgt_epi8(action_data[i], *data); + if (width == 16) + compare_result = _mm_cmpgt_epi16(action_data[i], *data); + if (width == 32) + compare_result = _mm_cmpgt_epi32(action_data[i], *data); + if (width == 64) + compare_result = _mm_cmpgt_epi64(action_data[i], *data); + } + // less + else if (std::is_same::value) { + if (width == 8) + compare_result = _mm_cmplt_epi8(action_data[i], *data); + else if (width == 16) + compare_result = _mm_cmplt_epi16(action_data[i], *data); + else if (width == 32) + compare_result = _mm_cmplt_epi32(action_data[i], *data); + else + REALM_ASSERT(false); + } + + resmask = _mm_movemask_epi8(compare_result); + + if (std::is_same::value) + resmask = ~resmask & 0x0000ffff; + + size_t s = i * sizeof(__m128i) * 8 / no0(width); + + while (resmask != 0) { + + uint64_t upper = lower_bits() << (no0(width / 8) - 1); + uint64_t pattern = + resmask & + upper; // fixme, bits at wrong offsets. Only OK because we only use them in 'count' aggregate + if (find_action_pattern(s + baseindex, pattern, state, callback)) + break; + + size_t idx = first_set_bit(resmask) * 8 / no0(width); + s += idx; + if (!find_action( + s + baseindex, get_universal(reinterpret_cast(action_data), s), state, callback)) + return false; + resmask >>= (idx + 1) * no0(width) / 8; + ++s; + } + } + + return true; +} +#endif // REALM_COMPILER_SSE + +template +bool Array::compare_leafs(const Array* foreign, size_t start, size_t end, size_t baseindex, + QueryState* state, Callback callback) const +{ + cond c; + REALM_ASSERT_3(start, <=, end); + if (start == end) + return true; + + + int64_t v; + + // We can compare first element without checking for out-of-range + v = get(start); + if (c(v, foreign->get(start))) { + if (!find_action(start + baseindex, v, state, callback)) + return false; + } + + start++; + + if (start + 3 < end) { + v = get(start); + if (c(v, foreign->get(start))) + if (!find_action(start + baseindex, v, state, callback)) + return false; + + v = get(start + 1); + if (c(v, foreign->get(start + 1))) + if (!find_action(start + 1 + baseindex, v, state, callback)) + return false; + + v = get(start + 2); + if (c(v, foreign->get(start + 2))) + if (!find_action(start + 2 + baseindex, v, state, callback)) + return false; + + start += 3; + } + else if (start == end) { + return true; + } + + bool r; + REALM_TEMPEX4(r = compare_leafs, cond, action, m_width, Callback, + (foreign, start, end, baseindex, state, callback)) + return r; +} + + +template +bool Array::compare_leafs(const Array* foreign, size_t start, size_t end, size_t baseindex, + QueryState* state, Callback callback) const +{ + size_t fw = foreign->m_width; + bool r; + REALM_TEMPEX5(r = compare_leafs_4, cond, action, width, Callback, fw, + (foreign, start, end, baseindex, state, callback)) + return r; +} + + +template +bool Array::compare_leafs_4(const Array* foreign, size_t start, size_t end, size_t baseindex, + QueryState* state, Callback callback) const +{ + cond c; + char* foreign_m_data = foreign->m_data; + + if (width == 0 && foreign_width == 0) { + if (c(0, 0)) { + while (start < end) { + if (!find_action(start + baseindex, 0, state, callback)) + return false; + start++; + } + } + else { + return true; + } + } + + +#if defined(REALM_COMPILER_SSE) + if (sseavx<42>() && width == foreign_width && (width == 8 || width == 16 || width == 32)) { + // We can only use SSE if both bitwidths are equal and above 8 bits and all values are signed + // and the two arrays are aligned the same way + if ((reinterpret_cast(m_data) & 0xf) == (reinterpret_cast(foreign_m_data) & 0xf)) { + while (start < end && (((reinterpret_cast(m_data) & 0xf) * 8 + start * width) % (128) != 0)) { + int64_t v = get_universal(m_data, start); + int64_t fv = get_universal(foreign_m_data, start); + if (c(v, fv)) { + if (!find_action(start + baseindex, v, state, callback)) + return false; + } + start++; + } + if (start == end) + return true; + + + size_t sse_items = (end - start) * width / 128; + size_t sse_end = start + sse_items * 128 / no0(width); + + while (start < sse_end) { + __m128i* a = reinterpret_cast<__m128i*>(m_data + start * width / 8); + __m128i* b = reinterpret_cast<__m128i*>(foreign_m_data + start * width / 8); + + bool continue_search = + find_sse_intern(a, b, 1, state, baseindex + start, callback); + + if (!continue_search) + return false; + + start += 128 / no0(width); + } + } + } +#endif + + while (start < end) { + int64_t v = get_universal(m_data, start); + int64_t fv = get_universal(foreign_m_data, start); + + if (c(v, fv)) { + if (!find_action(start + baseindex, v, state, callback)) + return false; + } + + start++; + } + + return true; +} + + +template +bool Array::compare(int64_t value, size_t start, size_t end, size_t baseindex, QueryState* state, + Callback callback) const +{ + bool ret = false; + + if (std::is_same::value) + ret = compare_equality(value, start, end, baseindex, state, callback); + else if (std::is_same::value) + ret = compare_equality(value, start, end, baseindex, state, callback); + else if (std::is_same::value) + ret = compare_relation(value, start, end, baseindex, state, callback); + else if (std::is_same::value) + ret = compare_relation(value, start, end, baseindex, state, callback); + else + REALM_ASSERT_DEBUG(false); + + return ret; +} + +template +bool Array::compare_relation(int64_t value, size_t start, size_t end, size_t baseindex, QueryState* state, + Callback callback) const +{ + REALM_ASSERT(start <= m_size && (end <= m_size || end == size_t(-1)) && start <= end); + uint64_t mask = (bitwidth == 64 ? ~0ULL + : ((1ULL << (bitwidth == 64 ? 0 : bitwidth)) - + 1ULL)); // Warning free way of computing (1ULL << width) - 1 + + size_t ee = round_up(start, 64 / no0(bitwidth)); + ee = ee > end ? end : ee; + for (; start < ee; start++) { + if (gt ? (get(start) > value) : (get(start) < value)) { + if (!find_action(start + baseindex, get(start), state, callback)) + return false; + } + } + + if (start >= end) + return true; // none found, continue (return true) regardless what find_action() would have returned on match + + const int64_t* p = reinterpret_cast(m_data + (start * bitwidth / 8)); + const int64_t* const e = reinterpret_cast(m_data + (end * bitwidth / 8)) - 1; + + // Matches are rare enough to setup fast linear search for remaining items. We use + // bit hacks from http://graphics.stanford.edu/~seander/bithacks.html#HasLessInWord + + if (bitwidth == 1 || bitwidth == 2 || bitwidth == 4 || bitwidth == 8 || bitwidth == 16) { + uint64_t magic = find_gtlt_magic(value); + + // Bit hacks only work if searched item has its most significant bit clear for 'greater than' or + // 'item <= 1 << bitwidth' for 'less than' + if (value != int64_t((magic & mask)) && value >= 0 && bitwidth >= 2 && + value <= static_cast((mask >> 1) - (gt ? 1 : 0))) { + // 15 ms + while (p < e) { + uint64_t upper = lower_bits() << (no0(bitwidth) - 1); + + const int64_t v = *p; + size_t idx; + + // Bit hacks only works if all items in chunk have their most significant bit clear. Test this: + upper = upper & v; + + if (!upper) { + idx = find_gtlt_fast( + v, magic, state, (p - reinterpret_cast(m_data)) * 8 * 8 / no0(bitwidth) + baseindex, + callback); + } + else + idx = find_gtlt( + value, v, state, (p - reinterpret_cast(m_data)) * 8 * 8 / no0(bitwidth) + baseindex, + callback); + + if (!idx) + return false; + ++p; + } + } + else { + // 24 ms + while (p < e) { + int64_t v = *p; + if (!find_gtlt( + value, v, state, (p - reinterpret_cast(m_data)) * 8 * 8 / no0(bitwidth) + baseindex, + callback)) + return false; + ++p; + } + } + start = (p - reinterpret_cast(m_data)) * 8 * 8 / no0(bitwidth); + } + + // matchcount logic in SIMD no longer pays off for 32/64 bit ints because we have just 4/2 elements + + // Test unaligned end and/or values of width > 16 manually + while (start < end) { + if (gt ? get(start) > value : get(start) < value) { + if (!find_action(start + baseindex, get(start), state, callback)) + return false; + } + ++start; + } + return true; +} + +template +size_t Array::find_first(int64_t value, size_t start, size_t end) const +{ + REALM_ASSERT(start <= m_size && (end <= m_size || end == size_t(-1)) && start <= end); + // todo, would be nice to avoid this in order to speed up find_first loops + QueryState state(act_ReturnFirst, 1); + Finder finder = m_vtable->finder[cond::condition]; + (this->*finder)(value, start, end, 0, &state); + + return static_cast(state.m_state); +} + +//************************************************************************************* +// Finding code ends * +//************************************************************************************* + + +} // namespace realm + +#endif // REALM_ARRAY_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_backlink.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_backlink.hpp new file mode 100644 index 0000000..2ecc8c2 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_backlink.hpp @@ -0,0 +1,86 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_ARRAY_BACKLINK_HPP +#define REALM_ARRAY_BACKLINK_HPP + +#include + +namespace realm { +class ArrayBacklink : public ArrayPayload, private Array { +public: + using Array::Array; + using Array::init_from_parent; + using Array::copy_on_write; + using Array::update_parent; + using Array::get_ref; + using Array::size; + + static int64_t default_value(bool) + { + return 0; + } + + void init_from_ref(ref_type ref) noexcept override + { + Array::init_from_ref(ref); + } + void set_parent(ArrayParent* parent, size_t ndx_in_parent) noexcept override + { + Array::set_parent(parent, ndx_in_parent); + } + void create() + { + Array::create(type_HasRefs); + } + + void insert(size_t ndx, int64_t val) + { + Array::insert(ndx, val); + } + + int64_t get(size_t ndx) const + { + return Array::get(ndx); + } + + void add(int64_t val) + { + Array::add(val); + } + + // nullify forward links corresponding to any backward links at index 'ndx' + void nullify_fwd_links(size_t ndx, CascadeState& state); + void add(size_t ndx, ObjKey key); + bool remove(size_t ndx, ObjKey key); + void erase(size_t ndx); + size_t get_backlink_count(size_t ndx) const; + ObjKey get_backlink(size_t ndx, size_t index) const; + void move(ArrayBacklink& dst, size_t ndx) + { + Array::move(dst, ndx); + } + void clear() + { + Array::truncate_and_destroy_children(0); + } + void verify() const; +}; +} + +#endif /* SRC_REALM_ARRAY_KEY_HPP_ */ diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_basic.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_basic.hpp new file mode 100644 index 0000000..39a3782 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_basic.hpp @@ -0,0 +1,286 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_ARRAY_BASIC_HPP +#define REALM_ARRAY_BASIC_HPP + +#include + +namespace realm { + +/// A BasicArray can currently only be used for simple unstructured +/// types like float, double. +template +class BasicArray : public Array, public ArrayPayload { +public: + using value_type = T; + + explicit BasicArray(Allocator&) noexcept; + ~BasicArray() noexcept override + { + } + + static T default_value(bool) + { + return T(0.0); + } + + void init_from_ref(ref_type ref) noexcept override + { + Array::init_from_ref(ref); + } + + void set_parent(ArrayParent* parent, size_t ndx_in_parent) noexcept override + { + Array::set_parent(parent, ndx_in_parent); + } + + // Disable copying, this is not allowed. + BasicArray& operator=(const BasicArray&) = delete; + BasicArray(const BasicArray&) = delete; + + T get(size_t ndx) const noexcept; + bool is_null(size_t ndx) const noexcept + { + // FIXME: This assumes BasicArray will only ever be instantiated for float-like T. + static_assert(realm::is_any::value, "T can only be float or double"); + auto x = BasicArray::get(ndx); + return null::is_null_float(x); + } + void add(T value); + void set(size_t ndx, T value); + void insert(size_t ndx, T value); + void erase(size_t ndx); + void truncate(size_t size); + void move(BasicArray& dst, size_t ndx) + { + for (size_t i = ndx; i < m_size; i++) { + dst.add(get(i)); + } + truncate(ndx); + } + void clear(); + + size_t find_first(T value, size_t begin = 0, size_t end = npos) const; + void find_all(IntegerColumn* result, T value, size_t add_offset = 0, size_t begin = 0, size_t end = npos) const; + + size_t count(T value, size_t begin = 0, size_t end = npos) const; + bool maximum(T& result, size_t begin = 0, size_t end = npos) const; + bool minimum(T& result, size_t begin = 0, size_t end = npos) const; + + /// Compare two arrays for equality. + bool compare(const BasicArray&) const; + + /// Get the specified element without the cost of constructing an + /// array instance. If an array instance is already available, or + /// you need to get multiple values, then this method will be + /// slower. + static T get(const char* header, size_t ndx) noexcept; + + size_t lower_bound(T value) const noexcept; + size_t upper_bound(T value) const noexcept; + + /// Construct a basic array of the specified size and return just + /// the reference to the underlying memory. All elements will be + /// initialized to `T()`. + static MemRef create_array(size_t size, Allocator&); + + static MemRef create_array(Array::Type leaf_type, bool context_flag, size_t size, T value, Allocator&); + + /// Create a new empty array and attach this accessor to it. This + /// does not modify the parent reference information of this + /// accessor. + /// + /// Note that the caller assumes ownership of the allocated + /// underlying node. It is not owned by the accessor. + void create(Array::Type = type_Normal, bool context_flag = false); + +private: + size_t find(T target, size_t begin, size_t end) const; + + size_t calc_byte_len(size_t count, size_t width) const override; + virtual size_t calc_item_count(size_t bytes, size_t width) const noexcept override; + + template + bool minmax(T& result, size_t begin, size_t end) const; + + /// Calculate the total number of bytes needed for a basic array + /// with the specified number of elements. This includes the size + /// of the header. The result will be upwards aligned to the + /// closest 8-byte boundary. + static size_t calc_aligned_byte_size(size_t size); +}; + +template +class BasicArrayNull : public BasicArray { +public: + using BasicArray::BasicArray; + + static T default_value(bool nullable) + { + return nullable ? null::get_null_float() : T(0.0); + } + void set(size_t ndx, util::Optional value) + { + if (value) { + BasicArray::set(ndx, *value); + } + else { + BasicArray::set(ndx, null::get_null_float()); + } + } + void add(util::Optional value) + { + if (value) { + BasicArray::add(*value); + } + else { + BasicArray::add(null::get_null_float()); + } + } + void insert(size_t ndx, util::Optional value) + { + if (value) { + BasicArray::insert(ndx, *value); + } + else { + BasicArray::insert(ndx, null::get_null_float()); + } + } + + void set_null(size_t ndx) + { + // FIXME: This assumes BasicArray will only ever be instantiated for float-like T. + set(ndx, null::get_null_float()); + } + + util::Optional get(size_t ndx) const noexcept + { + T val = BasicArray::get(ndx); + return null::is_null_float(val) ? util::none : util::make_optional(val); + } + size_t find_first(util::Optional value, size_t begin = 0, size_t end = npos) const + { + if (value) { + return BasicArray::find_first(*value, begin, end); + } + else { + return find_first_null(begin, end); + } + } + void find_all(IntegerColumn* result, util::Optional value, size_t add_offset = 0, size_t begin = 0, + size_t end = npos) const + { + if (value) { + return BasicArray::find_all(result, *value, add_offset, begin, end); + } + else { + return find_all_null(result, add_offset, begin, end); + } + } + size_t find_first_null(size_t begin = 0, size_t end = npos) const; + void find_all_null(IntegerColumn* result, size_t add_offset = 0, size_t begin = 0, size_t end = npos) const; +}; + +// Used only for Basic-types: currently float and double +template +class QueryState : public QueryStateBase { +public: + R m_state; + + template + bool uses_val() + { + return (action == act_Max || action == act_Min || action == act_Sum); + } + + QueryState(Action action, Array* = nullptr, size_t limit = -1) + : QueryStateBase(limit) + { + REALM_ASSERT((std::is_same::value || std::is_same::value)); + if (action == act_Max) + m_state = -std::numeric_limits::infinity(); + else if (action == act_Min) + m_state = std::numeric_limits::infinity(); + else if (action == act_Sum) + m_state = 0.0; + else if (action == act_Count) + m_state = 0.0; + else { + REALM_ASSERT_DEBUG(false); + } + } + + template + inline bool match(size_t index, uint64_t /*indexpattern*/, resulttype value) + { + if (pattern) + return false; + + static_assert(action == act_Sum || action == act_Max || action == act_Min || action == act_Count, + "Search action not supported"); + + if (action == act_Count) { + ++m_match_count; + } + else if (!null::is_null_float(value)) { + ++m_match_count; + if (action == act_Max) { + if (value > m_state) { + m_state = value; + if (m_key_values) { + m_minmax_index = m_key_values->get(index) + m_key_offset; + } + else { + m_minmax_index = int64_t(index); + } + } + } + else if (action == act_Min) { + if (value < m_state) { + m_state = value; + if (m_key_values) { + m_minmax_index = m_key_values->get(index) + m_key_offset; + } + else { + m_minmax_index = int64_t(index); + } + } + } + else if (action == act_Sum) + m_state += value; + else { + REALM_ASSERT_DEBUG(false); + } + } + + return (m_limit > m_match_count); + } +}; + +// Class typedefs for BasicArray's: ArrayFloat and ArrayDouble +typedef BasicArray ArrayFloat; +typedef BasicArray ArrayDouble; +typedef BasicArrayNull ArrayFloatNull; +typedef BasicArrayNull ArrayDoubleNull; + +} // namespace realm + +#include + +#endif // REALM_ARRAY_BASIC_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_basic_tpl.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_basic_tpl.hpp new file mode 100644 index 0000000..9b7e0ca --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_basic_tpl.hpp @@ -0,0 +1,377 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_ARRAY_BASIC_TPL_HPP +#define REALM_ARRAY_BASIC_TPL_HPP + +#include +#include +#include +#include + +#include + +namespace realm { + +template +inline BasicArray::BasicArray(Allocator& allocator) noexcept + : Array(allocator) +{ +} + +template +inline MemRef BasicArray::create_array(size_t init_size, Allocator& allocator) +{ + size_t byte_size_0 = calc_aligned_byte_size(init_size); // Throws + // Adding zero to Array::initial_capacity to avoid taking the + // address of that member + size_t byte_size = std::max(byte_size_0, Array::initial_capacity + 0); // Throws + + MemRef mem = allocator.alloc(byte_size); // Throws + + bool is_inner_bptree_node = false; + bool has_refs = false; + bool context_flag = false; + int width = sizeof(T); + init_header(mem.get_addr(), is_inner_bptree_node, has_refs, context_flag, wtype_Multiply, width, init_size, + byte_size); + + return mem; +} + + +template +inline MemRef BasicArray::create_array(Array::Type type, bool context_flag, size_t init_size, T value, + Allocator& allocator) +{ + REALM_ASSERT(type == Array::type_Normal); + REALM_ASSERT(!context_flag); + MemRef mem = create_array(init_size, allocator); + if (init_size) { + // GCC 7.x emits a false-positive strict aliasing warning for this code. Suppress it, since it + // clutters up the build output. See for details. + REALM_DIAG_PUSH(); + REALM_DIAG(ignored "-Wstrict-aliasing"); + + BasicArray tmp(allocator); + tmp.init_from_mem(mem); + T* p = reinterpret_cast(tmp.m_data); + T* end = p + init_size; + while (p < end) { + *p++ = value; + } + + REALM_DIAG_POP(); + } + return mem; +} + + +template +inline void BasicArray::create(Array::Type type, bool context_flag) +{ + REALM_ASSERT(type == Array::type_Normal); + REALM_ASSERT(!context_flag); + size_t length = 0; + MemRef mem = create_array(length, get_alloc()); // Throws + init_from_mem(mem); +} + + +template +inline void BasicArray::add(T value) +{ + insert(m_size, value); +} + + +template +inline T BasicArray::get(size_t ndx) const noexcept +{ + return *(reinterpret_cast(m_data) + ndx); +} + + +template +inline T BasicArray::get(const char* header, size_t ndx) noexcept +{ + const char* data = get_data_from_header(header); + // This casting assumes that T can be aliged on an 8-bype + // boundary (since data is aligned on an 8-byte boundary.) + return *(reinterpret_cast(data) + ndx); +} + + +template +inline void BasicArray::set(size_t ndx, T value) +{ + REALM_ASSERT_3(ndx, <, m_size); + if (get(ndx) == value) + return; + + // Check if we need to copy before modifying + copy_on_write(); // Throws + + // Set the value + T* data = reinterpret_cast(m_data) + ndx; + *data = value; +} + +template +void BasicArray::insert(size_t ndx, T value) +{ + REALM_ASSERT_3(ndx, <=, m_size); + + // Check if we need to copy before modifying + copy_on_write(); // Throws + + // Make room for the new value + const auto old_size = m_size; + alloc(m_size + 1, m_width); // Throws + + // Move values below insertion + if (ndx != old_size) { + char* src_begin = m_data + ndx * m_width; + char* src_end = m_data + old_size * m_width; + char* dst_end = src_end + m_width; + std::copy_backward(src_begin, src_end, dst_end); + } + + // Set the value + T* data = reinterpret_cast(m_data) + ndx; + *data = value; +} + +template +void BasicArray::erase(size_t ndx) +{ + REALM_ASSERT_3(ndx, <, m_size); + + // Check if we need to copy before modifying + copy_on_write(); // Throws + + // move data under deletion up + if (ndx < m_size - 1) { + char* dst_begin = m_data + ndx * m_width; + const char* src_begin = dst_begin + m_width; + const char* src_end = m_data + m_size * m_width; + realm::safe_copy_n(src_begin, src_end - src_begin, dst_begin); + } + + // Update size (also in header) + --m_size; + set_header_size(m_size); +} + +template +void BasicArray::truncate(size_t to_size) +{ + REALM_ASSERT(is_attached()); + REALM_ASSERT_3(to_size, <=, m_size); + + copy_on_write(); // Throws + + // Update size in accessor and in header. This leaves the capacity + // unchanged. + m_size = to_size; + set_header_size(to_size); +} + +template +inline void BasicArray::clear() +{ + truncate(0); // Throws +} + +template +bool BasicArray::compare(const BasicArray& a) const +{ + size_t n = size(); + if (a.size() != n) + return false; + const T* data_1 = reinterpret_cast(m_data); + const T* data_2 = reinterpret_cast(a.m_data); + return realm::safe_equal(data_1, data_1 + n, data_2); +} + + +template +size_t BasicArray::calc_byte_len(size_t for_size, size_t) const +{ + // FIXME: Consider calling `calc_aligned_byte_size(size)` + // instead. Note however, that calc_byte_len() is supposed to return + // the unaligned byte size. It is probably the case that no harm + // is done by returning the aligned version, and most callers of + // calc_byte_len() will actually benefit if calc_byte_len() was + // changed to always return the aligned byte size. + return header_size + for_size * sizeof(T); +} + +template +size_t BasicArray::calc_item_count(size_t bytes, size_t) const noexcept +{ + size_t bytes_without_header = bytes - header_size; + return bytes_without_header / sizeof(T); +} + +template +size_t BasicArray::find(T value, size_t begin, size_t end) const +{ + if (end == npos) + end = m_size; + REALM_ASSERT(begin <= m_size && end <= m_size && begin <= end); + const T* data = reinterpret_cast(m_data); + const T* i = std::find(data + begin, data + end, value); + return i == data + end ? not_found : size_t(i - data); +} + +template +inline size_t BasicArray::find_first(T value, size_t begin, size_t end) const +{ + return this->find(value, begin, end); +} + +template +void BasicArray::find_all(IntegerColumn* result, T value, size_t add_offset, size_t begin, size_t end) const +{ + size_t first = begin - 1; + for (;;) { + first = this->find(value, first + 1, end); + if (first == not_found) + break; + + Array::add_to_column(result, first + add_offset); + } +} +template +size_t BasicArrayNull::find_first_null(size_t begin, size_t end) const +{ + size_t sz = Array::size(); + if (end == npos) + end = sz; + REALM_ASSERT(begin <= sz && end <= sz && begin <= end); + while (begin != end) { + if (this->is_null(begin)) + return begin; + begin++; + } + return not_found; +} + +template +void BasicArrayNull::find_all_null(IntegerColumn* result, size_t add_offset, size_t begin, size_t end) const +{ + size_t first = begin - 1; + for (;;) { + first = this->find_first_null(first + 1, end); + if (first == not_found) + break; + + Array::add_to_column(result, first + add_offset); + } +} + +template +size_t BasicArray::count(T value, size_t begin, size_t end) const +{ + if (end == npos) + end = m_size; + REALM_ASSERT(begin <= m_size && end <= m_size && begin <= end); + const T* data = reinterpret_cast(m_data); + return std::count(data + begin, data + end, value); +} + +#if 0 +// currently unused +template +double BasicArray::sum(size_t begin, size_t end) const +{ + if (end == npos) + end = m_size; + REALM_ASSERT(begin <= m_size && end <= m_size && begin <= end); + const T* data = reinterpret_cast(m_data); + return std::accumulate(data + begin, data + end, double(0)); +} +#endif + +template +template +bool BasicArray::minmax(T& result, size_t begin, size_t end) const +{ + if (end == npos) + end = m_size; + if (m_size == 0) + return false; + REALM_ASSERT(begin < m_size && end <= m_size && begin < end); + + T m = get(begin); + ++begin; + for (; begin < end; ++begin) { + T val = get(begin); + if (find_max ? val > m : val < m) + m = val; + } + result = m; + return true; +} + +template +bool BasicArray::maximum(T& result, size_t begin, size_t end) const +{ + return minmax(result, begin, end); +} + +template +bool BasicArray::minimum(T& result, size_t begin, size_t end) const +{ + return minmax(result, begin, end); +} + + +template +inline size_t BasicArray::lower_bound(T value) const noexcept +{ + const T* begin = reinterpret_cast(m_data); + const T* end = begin + size(); + return std::lower_bound(begin, end, value) - begin; +} + +template +inline size_t BasicArray::upper_bound(T value) const noexcept +{ + const T* begin = reinterpret_cast(m_data); + const T* end = begin + size(); + return std::upper_bound(begin, end, value) - begin; +} + +template +inline size_t BasicArray::calc_aligned_byte_size(size_t size) +{ + size_t max = std::numeric_limits::max(); + size_t max_2 = max & ~size_t(7); // Allow for upwards 8-byte alignment + if (size > (max_2 - header_size) / sizeof(T)) + throw util::overflow_error("Byte size overflow"); + size_t byte_size = header_size + size * sizeof(T); + REALM_ASSERT_3(byte_size, >, 0); + size_t aligned_byte_size = ((byte_size - 1) | 7) + 1; // 8-byte alignment + return aligned_byte_size; +} + +} // namespace realm + +#endif // REALM_ARRAY_BASIC_TPL_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_binary.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_binary.hpp new file mode 100644 index 0000000..d7e10ff --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_binary.hpp @@ -0,0 +1,117 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_ARRAY_BINARY_HPP +#define REALM_ARRAY_BINARY_HPP + +#include +#include + +namespace realm { + +class ArrayBinary : public ArrayPayload { +public: + using value_type = BinaryData; + + explicit ArrayBinary(Allocator&); + + static BinaryData default_value(bool nullable) + { + return nullable ? BinaryData{} : BinaryData{"", 0}; + } + + void create(); + + ref_type get_ref() const + { + return m_arr->get_ref(); + } + + void set_parent(ArrayParent* parent, size_t ndx_in_parent) noexcept override + { + m_arr->set_parent(parent, ndx_in_parent); + } + + void update_parent() + { + m_arr->update_parent(); + } + + void init_from_mem(MemRef mem) noexcept; + void init_from_ref(ref_type ref) noexcept override + { + init_from_mem(MemRef(m_alloc.translate(ref), ref, m_alloc)); + } + void init_from_parent(); + + size_t size() const; + + void add(BinaryData value); + void set(size_t ndx, BinaryData value); + void set_null(size_t ndx) + { + set(ndx, BinaryData{}); + } + void insert(size_t ndx, BinaryData value); + BinaryData get(size_t ndx) const; + BinaryData get_at(size_t ndx, size_t& pos) const; + bool is_null(size_t ndx) const; + void erase(size_t ndx); + void move(ArrayBinary& dst, size_t ndx); + void clear(); + + size_t find_first(BinaryData value, size_t begin, size_t end) const noexcept; + + /// Get the specified element without the cost of constructing an + /// array instance. If an array instance is already available, or + /// you need to get multiple values, then this method will be + /// slower. + static BinaryData get(const char* header, size_t ndx, Allocator& alloc) noexcept; + + void verify() const; + +private: + static constexpr size_t small_blob_max_size = 64; + + union Storage { + std::aligned_storage::type m_small_blobs; + std::aligned_storage::type m_big_blobs; + }; + + bool m_is_big = false; + + Allocator& m_alloc; + Storage m_storage; + Array* m_arr; + + bool upgrade_leaf(size_t value_size); +}; + +inline BinaryData ArrayBinary::get(const char* header, size_t ndx, Allocator& alloc) noexcept +{ + bool is_big = Array::get_context_flag_from_header(header); + if (!is_big) { + return ArraySmallBlobs::get(header, ndx, alloc); + } + else { + return ArrayBigBlobs::get(header, ndx, alloc); + } +} +} + +#endif /* SRC_REALM_ARRAY_BINARY_HPP_ */ diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_blob.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_blob.hpp new file mode 100644 index 0000000..ab91304 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_blob.hpp @@ -0,0 +1,142 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_ARRAY_BLOB_HPP +#define REALM_ARRAY_BLOB_HPP + +#include + +namespace realm { + + +class ArrayBlob : public Array { +public: + static constexpr size_t max_binary_size = 0xFFFFF8 - Array::header_size; + + explicit ArrayBlob(Allocator&) noexcept; + ~ArrayBlob() noexcept override + { + } + + // Disable copying, this is not allowed. + ArrayBlob& operator=(const ArrayBlob&) = delete; + ArrayBlob(const ArrayBlob&) = delete; + + const char* get(size_t index) const noexcept; + BinaryData get_at(size_t& pos) const noexcept; + bool is_null(size_t index) const noexcept; + ref_type add(const char* data, size_t data_size, bool add_zero_term = false); + void insert(size_t pos, const char* data, size_t data_size, bool add_zero_term = false); + ref_type replace(size_t begin, size_t end, const char* data, size_t data_size, bool add_zero_term = false); + void erase(size_t begin, size_t end); + + /// Get the specified element without the cost of constructing an + /// array instance. If an array instance is already available, or + /// you need to get multiple values, then this method will be + /// slower. + static const char* get(const char* header, size_t index) noexcept; + + /// Create a new empty blob (binary) array and attach this + /// accessor to it. This does not modify the parent reference + /// information of this accessor. + /// + /// Note that the caller assumes ownership of the allocated + /// underlying node. It is not owned by the accessor. + void create(); + + /// Construct a blob of the specified size and return just the + /// reference to the underlying memory. All bytes will be + /// initialized to zero. + static MemRef create_array(size_t init_size, Allocator&); + + void verify() const; +private: + size_t calc_byte_len(size_t for_size, size_t width) const override; + size_t calc_item_count(size_t bytes, size_t width) const noexcept override; +}; + + +// Implementation: + +// Creates new array (but invalid, call init_from_ref() to init) +inline ArrayBlob::ArrayBlob(Allocator& allocator) noexcept + : Array(allocator) +{ +} + +inline bool ArrayBlob::is_null(size_t index) const noexcept +{ + return (get(index) == nullptr); +} + +inline const char* ArrayBlob::get(size_t index) const noexcept +{ + return m_data + index; +} + +inline ref_type ArrayBlob::add(const char* data, size_t data_size, bool add_zero_term) +{ + return replace(m_size, m_size, data, data_size, add_zero_term); +} + +inline void ArrayBlob::insert(size_t pos, const char* data, size_t data_size, bool add_zero_term) +{ + replace(pos, pos, data, data_size, add_zero_term); +} + +inline void ArrayBlob::erase(size_t begin, size_t end) +{ + const char* data = nullptr; + size_t data_size = 0; + replace(begin, end, data, data_size); +} + +inline const char* ArrayBlob::get(const char* header, size_t pos) noexcept +{ + const char* data = get_data_from_header(header); + return data + pos; +} + +inline void ArrayBlob::create() +{ + size_t init_size = 0; + MemRef mem = create_array(init_size, get_alloc()); // Throws + init_from_mem(mem); +} + +inline MemRef ArrayBlob::create_array(size_t init_size, Allocator& allocator) +{ + bool context_flag = false; + int_fast64_t value = 0; + return Array::create(type_Normal, context_flag, wtype_Ignore, init_size, value, allocator); // Throws +} + +inline size_t ArrayBlob::calc_byte_len(size_t for_size, size_t) const +{ + return header_size + for_size; +} + +inline size_t ArrayBlob::calc_item_count(size_t bytes, size_t) const noexcept +{ + return bytes - header_size; +} + + +} // namespace realm + +#endif // REALM_ARRAY_BLOB_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_blobs_big.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_blobs_big.hpp new file mode 100644 index 0000000..a6e1e34 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_blobs_big.hpp @@ -0,0 +1,206 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_ARRAY_BIG_BLOBS_HPP +#define REALM_ARRAY_BIG_BLOBS_HPP + +#include + +namespace realm { + + +class ArrayBigBlobs : public Array { +public: + typedef BinaryData value_type; + + explicit ArrayBigBlobs(Allocator&, bool nullable) noexcept; + + // Disable copying, this is not allowed. + ArrayBigBlobs& operator=(const ArrayBigBlobs&) = delete; + ArrayBigBlobs(const ArrayBigBlobs&) = delete; + + BinaryData get(size_t ndx) const noexcept; + bool is_null(size_t ndx) const; + BinaryData get_at(size_t ndx, size_t& pos) const noexcept; + void set(size_t ndx, BinaryData value, bool add_zero_term = false); + void add(BinaryData value, bool add_zero_term = false); + void insert(size_t ndx, BinaryData value, bool add_zero_term = false); + void erase(size_t ndx); + void truncate(size_t new_size); + void clear(); + void destroy(); + + size_t count(BinaryData value, bool is_string = false, size_t begin = 0, size_t end = npos) const noexcept; + size_t find_first(BinaryData value, bool is_string = false, size_t begin = 0, size_t end = npos) const noexcept; + void find_all(IntegerColumn& result, BinaryData value, bool is_string = false, size_t add_offset = 0, + size_t begin = 0, size_t end = npos); + + /// Get the specified element without the cost of constructing an + /// array instance. If an array instance is already available, or + /// you need to get multiple values, then this method will be + /// slower. + static BinaryData get(const char* header, size_t ndx, Allocator&) noexcept; + + //@{ + /// Those that return a string, discard the terminating zero from + /// the stored value. Those that accept a string argument, add a + /// terminating zero before storing the value. + StringData get_string(size_t ndx) const noexcept; + void add_string(StringData value); + void set_string(size_t ndx, StringData value); + void insert_string(size_t ndx, StringData value); + static StringData get_string(const char* header, size_t ndx, Allocator&, bool nullable) noexcept; + //@} + + /// Create a new empty big blobs array and attach this accessor to + /// it. This does not modify the parent reference information of + /// this accessor. + /// + /// Note that the caller assumes ownership of the allocated + /// underlying node. It is not owned by the accessor. + void create(); + + void verify() const; + +private: + bool m_nullable; +}; + + +// Implementation: + +inline ArrayBigBlobs::ArrayBigBlobs(Allocator& allocator, bool nullable) noexcept + : Array(allocator) + , m_nullable(nullable) +{ +} + +inline BinaryData ArrayBigBlobs::get(size_t ndx) const noexcept +{ + ref_type ref = get_as_ref(ndx); + if (ref == 0) + return {}; // realm::null(); + + const char* blob_header = get_alloc().translate(ref); + if (!get_context_flag_from_header(blob_header)) { + const char* value = ArrayBlob::get(blob_header, 0); + size_t sz = get_size_from_header(blob_header); + return BinaryData(value, sz); + } + return {}; +} + +inline bool ArrayBigBlobs::is_null(size_t ndx) const +{ + ref_type ref = get_as_ref(ndx); + return ref == 0; +} + +inline BinaryData ArrayBigBlobs::get(const char* header, size_t ndx, Allocator& alloc) noexcept +{ + ref_type blob_ref = to_ref(Array::get(header, ndx)); + if (blob_ref == 0) + return {}; + + const char* blob_header = alloc.translate(blob_ref); + if (!get_context_flag_from_header(blob_header)) { + const char* blob_data = Array::get_data_from_header(blob_header); + size_t sz = Array::get_size_from_header(blob_header); + return BinaryData(blob_data, sz); + } + return {}; +} + +inline void ArrayBigBlobs::erase(size_t ndx) +{ + ref_type blob_ref = Array::get_as_ref(ndx); + if (blob_ref != 0) { // nothing to destroy if null + Array::destroy_deep(blob_ref, get_alloc()); // Deep + } + Array::erase(ndx); +} + +inline void ArrayBigBlobs::truncate(size_t new_size) +{ + Array::truncate_and_destroy_children(new_size); +} + +inline void ArrayBigBlobs::clear() +{ + Array::clear_and_destroy_children(); +} + +inline void ArrayBigBlobs::destroy() +{ + Array::destroy_deep(); +} + +inline StringData ArrayBigBlobs::get_string(size_t ndx) const noexcept +{ + BinaryData bin = get(ndx); + if (bin.is_null()) + return realm::null(); + else + return StringData(bin.data(), bin.size() - 1); // Do not include terminating zero +} + +inline void ArrayBigBlobs::set_string(size_t ndx, StringData value) +{ + REALM_ASSERT_DEBUG(!(!m_nullable && value.is_null())); + BinaryData bin(value.data(), value.size()); + bool add_zero_term = true; + set(ndx, bin, add_zero_term); +} + +inline void ArrayBigBlobs::add_string(StringData value) +{ + REALM_ASSERT_DEBUG(!(!m_nullable && value.is_null())); + BinaryData bin(value.data(), value.size()); + bool add_zero_term = true; + add(bin, add_zero_term); +} + +inline void ArrayBigBlobs::insert_string(size_t ndx, StringData value) +{ + REALM_ASSERT_DEBUG(!(!m_nullable && value.is_null())); + BinaryData bin(value.data(), value.size()); + bool add_zero_term = true; + insert(ndx, bin, add_zero_term); +} + +inline StringData ArrayBigBlobs::get_string(const char* header, size_t ndx, Allocator& alloc, + bool nullable = true) noexcept +{ + static_cast(nullable); + BinaryData bin = get(header, ndx, alloc); + REALM_ASSERT_DEBUG(!(!nullable && bin.is_null())); + if (bin.is_null()) + return realm::null(); + else + return StringData(bin.data(), bin.size() - 1); // Do not include terminating zero +} + +inline void ArrayBigBlobs::create() +{ + bool context_flag = true; + Array::create(type_HasRefs, context_flag); // Throws +} + +} // namespace realm + +#endif // REALM_ARRAY_BIG_BLOBS_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_blobs_small.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_blobs_small.hpp new file mode 100644 index 0000000..1f89631 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_blobs_small.hpp @@ -0,0 +1,277 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_ARRAY_BLOBS_SMALL_HPP +#define REALM_ARRAY_BLOBS_SMALL_HPP + +#include +#include +#include + +namespace realm { + +/* +STORAGE FORMAT +--------------------------------------------------------------------------------------- +ArraySmallBlobs stores binary elements using two ArrayInteger and one ArrayBlob. The ArrayBlob can only store one +single concecutive array of bytes (contrary to its 'Array' name that misleadingly indicates it could store multiple +elements). + +Assume we have the strings "a", "", "abc", null, "ab". Then the three arrays will contain: + +ArrayInteger m_offsets 1, 1, 5, 5, 6 +ArrayBlob m_blob aabcab +ArrayInteger m_nulls 0, 0, 0, 1, 0 // 1 indicates null, 0 indicates non-null + +So for each element the ArrayInteger, the ArrayInteger points into the ArrayBlob at the position of the first +byte of the next element. + +m_nulls is always present (except for old database files; see below), so any ArraySmallBlobs is always nullable! +The nullable property (such as throwing exception upon set(null) on non-nullable column, etc) is handled on +column level only. + +DATABASE FILE VERSION CHANGES +--------------------------------------------------------------------------------------- +Old database files do not have any m_nulls array. To be backwardscompatible, many methods will have tests like +`if(Array::size() == 3)` and have a backwards compatible code paths for these (e.g. avoid writing to m_nulls +in set(), etc). This way no file format upgrade is needed to support nulls for BinaryData. +*/ + +class ArraySmallBlobs : public Array { +public: + explicit ArraySmallBlobs(Allocator&) noexcept; + ~ArraySmallBlobs() noexcept override + { + } + + // Disable copying, this is not allowed. + ArraySmallBlobs& operator=(const ArraySmallBlobs&) = delete; + ArraySmallBlobs(const ArraySmallBlobs&) = delete; + + /// Create a new empty binary array and attach this accessor to + /// it. This does not modify the parent reference information of + /// this accessor. + /// + /// Note that the caller assumes ownership of the allocated + /// underlying node. It is not owned by the accessor. + void create(); + + //@{ + /// Overriding functions of Array + void init_from_ref(ref_type) noexcept; + void init_from_mem(MemRef) noexcept; + void init_from_parent() noexcept; + //@} + + bool is_empty() const noexcept; + size_t size() const noexcept; + + BinaryData get(size_t ndx) const noexcept; + StringData get_string(size_t ndx) const; + bool is_null(size_t ndx) const; + + void add(BinaryData value, bool add_zero_term = false); + void set(size_t ndx, BinaryData value, bool add_zero_term = false); + void insert(size_t ndx, BinaryData value, bool add_zero_term = false); + void add_string(StringData value); + void set_string(size_t ndx, StringData value); + void insert_string(size_t ndx, StringData value); + void erase(size_t ndx); + void truncate(size_t new_size); + void clear(); + void destroy(); + + size_t find_first(BinaryData value, bool is_string, size_t begin, size_t end) const noexcept; + + /// Get the specified element without the cost of constructing an + /// array instance. If an array instance is already available, or + /// you need to get multiple values, then this method will be + /// slower. + static BinaryData get(const char* header, size_t ndx, Allocator&) noexcept; + static StringData get_string(const char* header, size_t ndx, Allocator& alloc) noexcept; + + static size_t get_size_from_header(const char*, Allocator&) noexcept; + + /// Construct a binary array of the specified size and return just + /// the reference to the underlying memory. All elements will be + /// initialized to the binary value `defaults`, which can be either + /// null or zero-length non-null (value with size > 0 is not allowed as + /// initialization value). + static MemRef create_array(size_t size, Allocator&, BinaryData defaults); + + bool update_from_parent(size_t old_baseline) noexcept; + +private: + friend class ArrayString; + Array m_offsets; + ArrayBlob m_blob; + Array m_nulls; + + StringData get_string_legacy(size_t ndx) const; +}; + + +// Implementation: + +inline ArraySmallBlobs::ArraySmallBlobs(Allocator& allocator) noexcept + : Array(allocator) + , m_offsets(allocator) + , m_blob(allocator) + , m_nulls(allocator) +{ + m_offsets.set_parent(this, 0); + m_blob.set_parent(this, 1); + m_nulls.set_parent(this, 2); +} + +inline void ArraySmallBlobs::create() +{ + size_t init_size = 0; + BinaryData defaults = BinaryData{}; // This init value is ignored because size = 0 + MemRef mem = create_array(init_size, get_alloc(), defaults); // Throws + init_from_mem(mem); +} + +inline void ArraySmallBlobs::init_from_ref(ref_type ref) noexcept +{ + REALM_ASSERT(ref); + char* header = get_alloc().translate(ref); + init_from_mem(MemRef(header, ref, m_alloc)); +} + +inline void ArraySmallBlobs::init_from_parent() noexcept +{ + ref_type ref = get_ref_from_parent(); + init_from_ref(ref); +} + +inline bool ArraySmallBlobs::is_empty() const noexcept +{ + return m_offsets.is_empty(); +} + +inline size_t ArraySmallBlobs::size() const noexcept +{ + return m_offsets.size(); +} + +inline BinaryData ArraySmallBlobs::get(size_t ndx) const noexcept +{ + REALM_ASSERT_3(ndx, <, m_offsets.size()); + + if (m_nulls.get(ndx)) { + return BinaryData(); + } + else { + size_t begin = ndx ? to_size_t(m_offsets.get(ndx - 1)) : 0; + size_t end = to_size_t(m_offsets.get(ndx)); + + BinaryData bd = BinaryData(m_blob.get(begin), end - begin); + // Old database file (non-nullable column should never return null) + REALM_ASSERT(!bd.is_null()); + return bd; + } +} + +inline bool ArraySmallBlobs::is_null(size_t ndx) const +{ + REALM_ASSERT_3(ndx, <, m_nulls.size()); + + return m_nulls.get(ndx) != 0; +} + +inline StringData ArraySmallBlobs::get_string(size_t ndx) const +{ + BinaryData bin = get(ndx); + if (bin.is_null()) + return realm::null(); + else + return StringData(bin.data(), bin.size() - 1); // Do not include terminating zero +} + +inline StringData ArraySmallBlobs::get_string(const char* header, size_t ndx, Allocator& alloc) noexcept +{ + BinaryData bin = get(header, ndx, alloc); + if (bin.is_null()) + return realm::null(); + else + return StringData(bin.data(), bin.size() - 1); // Do not include terminating zero +} + +inline void ArraySmallBlobs::add_string(StringData value) +{ + add(BinaryData(value.data(), value.size()), true); +} + +inline void ArraySmallBlobs::set_string(size_t ndx, StringData value) +{ + set(ndx, BinaryData(value.data(), value.size()), true); +} + +inline void ArraySmallBlobs::insert_string(size_t ndx, StringData value) +{ + insert(ndx, BinaryData(value.data(), value.size()), true); +} + +inline void ArraySmallBlobs::truncate(size_t new_size) +{ + REALM_ASSERT(new_size == 0 || new_size < m_offsets.size()); + + size_t sz = new_size ? to_size_t(m_offsets.get(new_size - 1)) : 0; + + m_offsets.truncate(new_size); + m_blob.truncate(sz); + m_nulls.truncate(new_size); +} + +inline void ArraySmallBlobs::clear() +{ + m_blob.clear(); + m_offsets.clear(); + m_nulls.clear(); +} + +inline void ArraySmallBlobs::destroy() +{ + m_blob.destroy(); + m_offsets.destroy(); + m_nulls.destroy(); + Array::destroy(); +} + +inline size_t ArraySmallBlobs::get_size_from_header(const char* header, Allocator& alloc) noexcept +{ + ref_type offsets_ref = to_ref(Array::get(header, 0)); + const char* offsets_header = alloc.translate(offsets_ref); + return Array::get_size_from_header(offsets_header); +} + +inline bool ArraySmallBlobs::update_from_parent(size_t old_baseline) noexcept +{ + bool res = Array::update_from_parent(old_baseline); + if (res) { + m_blob.update_from_parent(old_baseline); + m_offsets.update_from_parent(old_baseline); + m_nulls.update_from_parent(old_baseline); + } + return res; +} + +} // namespace realm + +#endif // REALM_ARRAY_BINARY_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_bool.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_bool.hpp new file mode 100644 index 0000000..6b2c402 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_bool.hpp @@ -0,0 +1,148 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_ARRAY_BOOL_HPP +#define REALM_ARRAY_BOOL_HPP + +#include + +namespace realm { + +/// ArrayBool supports both nullable and non-nullable arrays with respect to +/// adding and inserting values. In this way we don't need to distinguish +/// between the two type when adding a row and when adding a column. +/// add, insert and getting of non-nullable values are taken care of by the +/// respective functions in Array. +class ArrayBool : public Array, public ArrayPayload { +public: + using value_type = bool; + + using Array::Array; + using Array::init_from_ref; + using Array::init_from_parent; + using Array::update_parent; + using Array::get_ref; + using Array::size; + using Array::erase; + using Array::truncate_and_destroy_children; + + static bool default_value(bool) + { + return false; + } + void create() + { + Array::create(type_Normal); + } + void init_from_ref(ref_type ref) noexcept override + { + Array::init_from_ref(ref); + } + void set_parent(ArrayParent* parent, size_t ndx_in_parent) noexcept override + { + Array::set_parent(parent, ndx_in_parent); + } + bool is_null(size_t) const + { + return false; + } + void set(size_t ndx, bool value) + { + Array::set(ndx, value ? 1 : 0); + } + bool get(size_t ndx) const + { + return Array::get(ndx) != 0; + } + void add(bool value) + { + Array::add(value); + } + void insert(size_t ndx, bool value) + { + Array::insert(ndx, value); + } + + size_t find_first(util::Optional value, size_t begin = 0, size_t end = npos) const noexcept + { + if (value) { + return Array::find_first(*value, begin, end); + } + else { + return Array::find_first(null_value, begin, end); + } + } + +protected: + // We can still be in two bits as small values are considered unsigned + static constexpr int null_value = 3; +}; + +class ArrayBoolNull : public ArrayBool { +public: + using value_type = util::Optional; + using ArrayBool::ArrayBool; + + static util::Optional default_value(bool nullable) + { + return nullable ? util::none : util::some(false); + } + void set(size_t ndx, util::Optional value) + { + if (value) { + Array::set(ndx, *value); + } + else { + Array::set(ndx, null_value); + } + } + void add(util::Optional value) + { + if (value) { + Array::add(*value); + } + else { + Array::add(null_value); + } + } + void insert(size_t ndx, util::Optional value) + { + if (value) { + Array::insert(ndx, *value); + } + else { + Array::insert(ndx, null_value); + } + } + void set_null(size_t ndx) + { + Array::set(ndx, null_value); + } + bool is_null(size_t ndx) const + { + return Array::get(ndx) == null_value; + } + util::Optional get(size_t ndx) const + { + int64_t val = Array::get(ndx); + return (val == null_value) ? util::none : util::make_optional(val != 0); + } +}; +} + +#endif /* REALM_ARRAY_BOOL_HPP */ diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_decimal128.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_decimal128.hpp new file mode 100644 index 0000000..88c0698 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_decimal128.hpp @@ -0,0 +1,166 @@ +/************************************************************************* + * + * Copyright 2019 Realm Inc. + * + * 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 REALM_ARRAY_DECIMAL128_HPP +#define REALM_ARRAY_DECIMAL128_HPP + +#include +#include + +namespace realm { + +class ArrayDecimal128 : public ArrayPayload, private Array { +public: + using value_type = Decimal128; + + using Array::Array; + using Array::destroy; + using Array::get_ref; + using Array::init_from_mem; + using Array::init_from_parent; + using Array::size; + using Array::truncate; + using Array::update_parent; + using Array::verify; + + static Decimal128 default_value(bool nullable) + { + return nullable ? Decimal128(realm::null()) : Decimal128(0); + } + + void create() + { + auto mem = Array::create(type_Normal, false, wtype_Multiply, 0, 0, m_alloc); // Throws + Array::init_from_mem(mem); + } + + void init_from_ref(ref_type ref) noexcept override + { + Array::init_from_ref(ref); + } + + void set_parent(ArrayParent* parent, size_t ndx_in_parent) noexcept override + { + Array::set_parent(parent, ndx_in_parent); + } + + bool is_null(size_t ndx) const + { + return this->get_width() == 0 || get(ndx).is_null(); + } + + Decimal128 get(size_t ndx) const + { + REALM_ASSERT(ndx < m_size); + auto values = reinterpret_cast(this->m_data); + return values[ndx]; + } + + void add(Decimal128 value) + { + insert(size(), value); + } + + void set(size_t ndx, Decimal128 value); + void set_null(size_t ndx) + { + set(ndx, Decimal128(realm::null())); + } + + void insert(size_t ndx, Decimal128 value); + void erase(size_t ndx); + void move(ArrayDecimal128& dst, size_t ndx); + void clear() + { + truncate(0); + } + + size_t find_first(Decimal128 value, size_t begin = 0, size_t end = npos) const noexcept; + +protected: + size_t calc_byte_len(size_t num_items, size_t) const override + { + return num_items * sizeof(Decimal128) + header_size; + } +}; + +template <> +class QueryState : public QueryStateBase { +public: + Decimal128 m_state; + + template + bool uses_val() + { + return (action == act_Max || action == act_Min || action == act_Sum); + } + + QueryState(Action action, Array* = nullptr, size_t limit = -1) + : QueryStateBase(limit) + { + if (action == act_Max) + m_state = Decimal128("-inf"); + else if (action == act_Min) + m_state = Decimal128("+inf"); + } + + template + inline bool match(size_t index, uint64_t /*indexpattern*/, Decimal128 value) + { + static_assert(action == act_Sum || action == act_Max || action == act_Min || action == act_Count, + "Search action not supported"); + + if (action == act_Count) { + ++m_match_count; + } + else if (!value.is_null()) { + ++m_match_count; + if (action == act_Max) { + if (value > m_state) { + m_state = value; + if (m_key_values) { + m_minmax_index = m_key_values->get(index) + m_key_offset; + } + else { + m_minmax_index = int64_t(index); + } + } + } + else if (action == act_Min) { + if (value < m_state) { + m_state = value; + if (m_key_values) { + m_minmax_index = m_key_values->get(index) + m_key_offset; + } + else { + m_minmax_index = int64_t(index); + } + } + } + else if (action == act_Sum) { + m_state += value; + } + } + + return (m_limit > m_match_count); + } +}; + +} // namespace realm + +#endif /* REALM_ARRAY_DECIMAL128_HPP */ diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_direct.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_direct.hpp new file mode 100644 index 0000000..5fdf023 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_direct.hpp @@ -0,0 +1,380 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_ARRAY_DIRECT_HPP +#define REALM_ARRAY_DIRECT_HPP + +#include +#include + +// clang-format off +/* wid == 16/32 likely when accessing offsets in B tree */ +#define REALM_TEMPEX(fun, wid, arg) \ + if (wid == 16) {fun<16> arg;} \ + else if (wid == 32) {fun<32> arg;} \ + else if (wid == 0) {fun<0> arg;} \ + else if (wid == 1) {fun<1> arg;} \ + else if (wid == 2) {fun<2> arg;} \ + else if (wid == 4) {fun<4> arg;} \ + else if (wid == 8) {fun<8> arg;} \ + else if (wid == 64) {fun<64> arg;} \ + else {REALM_ASSERT_DEBUG(false); fun<0> arg;} + +#define REALM_TEMPEX2(fun, targ, wid, arg) \ + if (wid == 16) {fun arg;} \ + else if (wid == 32) {fun arg;} \ + else if (wid == 0) {fun arg;} \ + else if (wid == 1) {fun arg;} \ + else if (wid == 2) {fun arg;} \ + else if (wid == 4) {fun arg;} \ + else if (wid == 8) {fun arg;} \ + else if (wid == 64) {fun arg;} \ + else {REALM_ASSERT_DEBUG(false); fun arg;} + +#define REALM_TEMPEX3(fun, targ1, targ2, wid, arg) \ + if (wid == 16) {fun arg;} \ + else if (wid == 32) {fun arg;} \ + else if (wid == 0) {fun arg;} \ + else if (wid == 1) {fun arg;} \ + else if (wid == 2) {fun arg;} \ + else if (wid == 4) {fun arg;} \ + else if (wid == 8) {fun arg;} \ + else if (wid == 64) {fun arg;} \ + else {REALM_ASSERT_DEBUG(false); fun arg;} + +#define REALM_TEMPEX4(fun, targ1, targ2, wid, targ3, arg) \ + if (wid == 16) {fun arg;} \ + else if (wid == 32) {fun arg;} \ + else if (wid == 0) {fun arg;} \ + else if (wid == 1) {fun arg;} \ + else if (wid == 2) {fun arg;} \ + else if (wid == 4) {fun arg;} \ + else if (wid == 8) {fun arg;} \ + else if (wid == 64) {fun arg;} \ + else {REALM_ASSERT_DEBUG(false); fun arg;} + +#define REALM_TEMPEX5(fun, targ1, targ2, targ3, targ4, wid, arg) \ + if (wid == 16) {fun arg;} \ + else if (wid == 32) {fun arg;} \ + else if (wid == 0) {fun arg;} \ + else if (wid == 1) {fun arg;} \ + else if (wid == 2) {fun arg;} \ + else if (wid == 4) {fun arg;} \ + else if (wid == 8) {fun arg;} \ + else if (wid == 64) {fun arg;} \ + else {REALM_ASSERT_DEBUG(false); fun arg;} +// clang-format on + +namespace realm { + +/// Takes a 64-bit value and returns the minimum number of bits needed +/// to fit the value. For alignment this is rounded up to nearest +/// log2. Posssible results {0, 1, 2, 4, 8, 16, 32, 64} +size_t bit_width(int64_t value); + +// Direct access methods + +template +void set_direct(char* data, size_t ndx, int_fast64_t value) noexcept +{ + if (width == 0) { + REALM_ASSERT_DEBUG(value == 0); + return; + } + else if (width == 1) { + REALM_ASSERT_DEBUG(0 <= value && value <= 0x01); + size_t byte_ndx = ndx / 8; + size_t bit_ndx = ndx % 8; + typedef unsigned char uchar; + uchar* p = reinterpret_cast(data) + byte_ndx; + *p = uchar((*p & ~(0x01 << bit_ndx)) | (int(value) & 0x01) << bit_ndx); + } + else if (width == 2) { + REALM_ASSERT_DEBUG(0 <= value && value <= 0x03); + size_t byte_ndx = ndx / 4; + size_t bit_ndx = ndx % 4 * 2; + typedef unsigned char uchar; + uchar* p = reinterpret_cast(data) + byte_ndx; + *p = uchar((*p & ~(0x03 << bit_ndx)) | (int(value) & 0x03) << bit_ndx); + } + else if (width == 4) { + REALM_ASSERT_DEBUG(0 <= value && value <= 0x0F); + size_t byte_ndx = ndx / 2; + size_t bit_ndx = ndx % 2 * 4; + typedef unsigned char uchar; + uchar* p = reinterpret_cast(data) + byte_ndx; + *p = uchar((*p & ~(0x0F << bit_ndx)) | (int(value) & 0x0F) << bit_ndx); + } + else if (width == 8) { + REALM_ASSERT_DEBUG(std::numeric_limits::min() <= value && + value <= std::numeric_limits::max()); + *(reinterpret_cast(data) + ndx) = int8_t(value); + } + else if (width == 16) { + REALM_ASSERT_DEBUG(std::numeric_limits::min() <= value && + value <= std::numeric_limits::max()); + *(reinterpret_cast(data) + ndx) = int16_t(value); + } + else if (width == 32) { + REALM_ASSERT_DEBUG(std::numeric_limits::min() <= value && + value <= std::numeric_limits::max()); + *(reinterpret_cast(data) + ndx) = int32_t(value); + } + else if (width == 64) { + REALM_ASSERT_DEBUG(std::numeric_limits::min() <= value && + value <= std::numeric_limits::max()); + *(reinterpret_cast(data) + ndx) = int64_t(value); + } + else { + REALM_ASSERT_DEBUG(false); + } +} + +inline void set_direct(char* data, size_t width, size_t ndx, int_fast64_t value) noexcept +{ + REALM_TEMPEX(set_direct, width, (data, ndx, value)); +} + +template +void fill_direct(char* data, size_t begin, size_t end, int_fast64_t value) noexcept +{ + for (size_t i = begin; i != end; ++i) + set_direct(data, i, value); +} + +template +int64_t get_direct(const char* data, size_t ndx) noexcept +{ + if (w == 0) { + return 0; + } + if (w == 1) { + size_t offset = ndx >> 3; + return (data[offset] >> (ndx & 7)) & 0x01; + } + if (w == 2) { + size_t offset = ndx >> 2; + return (data[offset] >> ((ndx & 3) << 1)) & 0x03; + } + if (w == 4) { + size_t offset = ndx >> 1; + return (data[offset] >> ((ndx & 1) << 2)) & 0x0F; + } + if (w == 8) { + return *reinterpret_cast(data + ndx); + } + if (w == 16) { + size_t offset = ndx * 2; + return *reinterpret_cast(data + offset); + } + if (w == 32) { + size_t offset = ndx * 4; + return *reinterpret_cast(data + offset); + } + if (w == 64) { + size_t offset = ndx * 8; + return *reinterpret_cast(data + offset); + } + REALM_ASSERT_DEBUG(false); + return int64_t(-1); +} + +inline int64_t get_direct(const char* data, size_t width, size_t ndx) noexcept +{ + REALM_TEMPEX(return get_direct, width, (data, ndx)); +} + + +template +inline std::pair get_two(const char* data, size_t ndx) noexcept +{ + return std::make_pair(to_size_t(get_direct(data, ndx + 0)), to_size_t(get_direct(data, ndx + 1))); +} + +inline std::pair get_two(const char* data, size_t width, size_t ndx) noexcept +{ + REALM_TEMPEX(return get_two, width, (data, ndx)); +} + + +template +inline void get_three(const char* data, size_t ndx, ref_type& v0, ref_type& v1, ref_type& v2) noexcept +{ + v0 = to_ref(get_direct(data, ndx + 0)); + v1 = to_ref(get_direct(data, ndx + 1)); + v2 = to_ref(get_direct(data, ndx + 2)); +} + +inline void get_three(const char* data, size_t width, size_t ndx, ref_type& v0, ref_type& v1, ref_type& v2) noexcept +{ + REALM_TEMPEX(get_three, width, (data, ndx, v0, v1, v2)); +} + + +// Lower/upper bound in sorted sequence +// ------------------------------------ +// +// 3 3 3 4 4 4 5 6 7 9 9 9 +// ^ ^ ^ ^ ^ +// | | | | | +// | | | | -- Lower and upper bound of 15 +// | | | | +// | | | -- Lower and upper bound of 8 +// | | | +// | | -- Upper bound of 4 +// | | +// | -- Lower bound of 4 +// | +// -- Lower and upper bound of 1 +// +// These functions are semantically identical to std::lower_bound() and +// std::upper_bound(). +// +// We currently use binary search. See for example +// http://www.tbray.org/ongoing/When/200x/2003/03/22/Binary. +template +inline size_t lower_bound(const char* data, size_t size, int64_t value) noexcept +{ + // The binary search used here is carefully optimized. Key trick is to use a single + // loop controlling variable (size) instead of high/low pair, and to keep updates + // to size done inside the loop independent of comparisons. Further key to speed + // is to avoid branching inside the loop, using conditional moves instead. This + // provides robust performance for random searches, though predictable searches + // might be slightly faster if we used branches instead. The loop unrolling yields + // a final 5-20% speedup depending on circumstances. + + size_t low = 0; + + while (size >= 8) { + // The following code (at X, Y and Z) is 3 times manually unrolled instances of (A) below. + // These code blocks must be kept in sync. Meassurements indicate 3 times unrolling to give + // the best performance. See (A) for comments on the loop body. + // (X) + size_t half = size / 2; + size_t other_half = size - half; + size_t probe = low + half; + size_t other_low = low + other_half; + int64_t v = get_direct(data, probe); + size = half; + low = (v < value) ? other_low : low; + + // (Y) + half = size / 2; + other_half = size - half; + probe = low + half; + other_low = low + other_half; + v = get_direct(data, probe); + size = half; + low = (v < value) ? other_low : low; + + // (Z) + half = size / 2; + other_half = size - half; + probe = low + half; + other_low = low + other_half; + v = get_direct(data, probe); + size = half; + low = (v < value) ? other_low : low; + } + while (size > 0) { + // (A) + // To understand the idea in this code, please note that + // for performance, computation of size for the next iteration + // MUST be INDEPENDENT of the conditional. This allows the + // processor to unroll the loop as fast as possible, and it + // minimizes the length of dependence chains leading up to branches. + // Making the unfolding of the loop independent of the data being + // searched, also minimizes the delays incurred by branch + // mispredictions, because they can be determined earlier + // and the speculation corrected earlier. + + // Counterintuitive: + // To make size independent of data, we cannot always split the + // range at the theoretical optimal point. When we determine that + // the key is larger than the probe at some index K, and prepare + // to search the upper part of the range, you would normally start + // the search at the next index, K+1, to get the shortest range. + // We can only do this when splitting a range with odd number of entries. + // If there is an even number of entries we search from K instead of K+1. + // This potentially leads to redundant comparisons, but in practice we + // gain more performance by making the changes to size predictable. + + // if size is even, half and other_half are the same. + // if size is odd, half is one less than other_half. + size_t half = size / 2; + size_t other_half = size - half; + size_t probe = low + half; + size_t other_low = low + other_half; + int64_t v = get_direct(data, probe); + size = half; + // for max performance, the line below should compile into a conditional + // move instruction. Not all compilers do this. To maximize chance + // of succes, no computation should be done in the branches of the + // conditional. + low = (v < value) ? other_low : low; + }; + + return low; +} + +// See lower_bound() +template +inline size_t upper_bound(const char* data, size_t size, int64_t value) noexcept +{ + size_t low = 0; + while (size >= 8) { + size_t half = size / 2; + size_t other_half = size - half; + size_t probe = low + half; + size_t other_low = low + other_half; + int64_t v = get_direct(data, probe); + size = half; + low = (value >= v) ? other_low : low; + + half = size / 2; + other_half = size - half; + probe = low + half; + other_low = low + other_half; + v = get_direct(data, probe); + size = half; + low = (value >= v) ? other_low : low; + + half = size / 2; + other_half = size - half; + probe = low + half; + other_low = low + other_half; + v = get_direct(data, probe); + size = half; + low = (value >= v) ? other_low : low; + } + + while (size > 0) { + size_t half = size / 2; + size_t other_half = size - half; + size_t probe = low + half; + size_t other_low = low + other_half; + int64_t v = get_direct(data, probe); + size = half; + low = (value >= v) ? other_low : low; + }; + + return low; +} +} + +#endif /* ARRAY_TPL_HPP_ */ diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_integer.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_integer.hpp new file mode 100644 index 0000000..fdb7c0d --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_integer.hpp @@ -0,0 +1,391 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_ARRAY_INTEGER_HPP +#define REALM_ARRAY_INTEGER_HPP + +#include +#include +#include + +namespace realm { + +class ArrayInteger : public Array, public ArrayPayload { +public: + using value_type = int64_t; + + using Array::add; + using Array::get; + using Array::insert; + using Array::move; + using Array::set; + + explicit ArrayInteger(Allocator&) noexcept; + ~ArrayInteger() noexcept override {} + + static value_type default_value(bool) + { + return 0; + } + + void init_from_ref(ref_type ref) noexcept override + { + Array::init_from_ref(ref); + } + void set_parent(ArrayParent* parent, size_t ndx_in_parent) noexcept override + { + Array::set_parent(parent, ndx_in_parent); + } + + // Disable copying, this is not allowed. + ArrayInteger& operator=(const ArrayInteger&) = delete; + ArrayInteger(const ArrayInteger&) = delete; + + void create() + { + Array::create(type_Normal, false, 0, 0); + } + + bool is_null(size_t) const + { + return false; + } +}; + + +class ArrayIntNull : public Array, public ArrayPayload { +public: + using value_type = util::Optional; + + explicit ArrayIntNull(Allocator&) noexcept; + ~ArrayIntNull() noexcept override; + + static value_type default_value(bool nullable) + { + return nullable ? util::none : util::Optional(0); + } + + /// Construct an array of the specified type and size, and return just the + /// reference to the underlying memory. All elements will be initialized to + /// the specified value. + static MemRef create_array(Type, bool context_flag, size_t size, Allocator&); + void create() + { + MemRef r = create_array(type_Normal, false, 0, m_alloc); + init_from_mem(r); + } + + void init_from_ref(ref_type) noexcept override; + void set_parent(ArrayParent* parent, size_t ndx_in_parent) noexcept override + { + Array::set_parent(parent, ndx_in_parent); + } + void init_from_mem(MemRef) noexcept; + void init_from_parent() noexcept; + + size_t size() const noexcept; + bool is_empty() const noexcept; + + void insert(size_t ndx, value_type value); + void add(value_type value); + void set(size_t ndx, value_type value); + value_type get(size_t ndx) const noexcept; + static value_type get(const char* header, size_t ndx) noexcept; + void get_chunk(size_t ndx, value_type res[8]) const noexcept; + void set_null(size_t ndx); + bool is_null(size_t ndx) const noexcept; + int64_t null_value() const noexcept; + + void erase(size_t ndx); + void erase(size_t begin, size_t end); + void move(ArrayIntNull& dst, size_t ndx); + void clear(); + + void move(size_t begin, size_t end, size_t dest_begin); + + bool find(int cond, Action action, value_type value, size_t start, size_t end, size_t baseindex, + QueryState* state) const; + + template + bool find(value_type value, size_t start, size_t end, size_t baseindex, QueryState* state, + Callback callback) const; + + // This is the one installed into the m_finder slots. + template + bool find(int64_t value, size_t start, size_t end, size_t baseindex, QueryState* state) const; + + template + bool find(value_type value, size_t start, size_t end, size_t baseindex, QueryState* state, + Callback callback) const; + + // Optimized implementation for release mode + template + bool find_optimized(value_type value, size_t start, size_t end, size_t baseindex, QueryState* state, + Callback callback) const; + + // Called for each search result + template + bool find_action(size_t index, value_type value, QueryState* state, Callback callback) const; + + template + bool find_action_pattern(size_t index, uint64_t pattern, QueryState* state, Callback callback) const; + + // Wrappers for backwards compatibility and for simple use without + // setting up state initialization etc + template + size_t find_first(value_type value, size_t start = 0, size_t end = npos) const; + + void find_all(IntegerColumn* result, value_type value, size_t col_offset = 0, size_t begin = 0, + size_t end = npos) const; + + + size_t find_first(value_type value, size_t begin = 0, size_t end = npos) const; + +protected: + void avoid_null_collision(int64_t value); + +private: + int_fast64_t choose_random_null(int64_t incoming) const; + void replace_nulls_with(int64_t new_null); + bool can_use_as_null(int64_t value) const; +}; + + +// Implementation: + +inline ArrayInteger::ArrayInteger(Allocator& allocator) noexcept + : Array(allocator) +{ + m_is_inner_bptree_node = false; +} + +inline ArrayIntNull::ArrayIntNull(Allocator& allocator) noexcept + : Array(allocator) +{ +} + +inline ArrayIntNull::~ArrayIntNull() noexcept {} + +inline size_t ArrayIntNull::size() const noexcept +{ + return Array::size() - 1; +} + +inline bool ArrayIntNull::is_empty() const noexcept +{ + return size() == 0; +} + +inline void ArrayIntNull::insert(size_t ndx, value_type value) +{ + if (value) { + avoid_null_collision(*value); + Array::insert(ndx + 1, *value); + } + else { + Array::insert(ndx + 1, null_value()); + } +} + +inline void ArrayIntNull::add(value_type value) +{ + if (value) { + avoid_null_collision(*value); + Array::add(*value); + } + else { + Array::add(null_value()); + } +} + +inline void ArrayIntNull::set(size_t ndx, value_type value) +{ + if (value) { + avoid_null_collision(*value); + Array::set(ndx + 1, *value); + } + else { + Array::set(ndx + 1, null_value()); + } +} + +inline void ArrayIntNull::set_null(size_t ndx) +{ + Array::set(ndx + 1, null_value()); +} + +inline ArrayIntNull::value_type ArrayIntNull::get(size_t ndx) const noexcept +{ + int64_t value = Array::get(ndx + 1); + if (value == null_value()) { + return util::none; + } + return util::some(value); +} + +inline ArrayIntNull::value_type ArrayIntNull::get(const char* header, size_t ndx) noexcept +{ + int64_t null_value = Array::get(header, 0); + int64_t value = Array::get(header, ndx + 1); + if (value == null_value) { + return util::none; + } + else { + return util::some(value); + } +} + +inline bool ArrayIntNull::is_null(size_t ndx) const noexcept +{ + return !get(ndx); +} + +inline int64_t ArrayIntNull::null_value() const noexcept +{ + return Array::get(0); +} + +inline void ArrayIntNull::erase(size_t ndx) +{ + Array::erase(ndx + 1); +} + +inline void ArrayIntNull::erase(size_t begin, size_t end) +{ + Array::erase(begin + 1, end + 1); +} + +inline void ArrayIntNull::clear() +{ + Array::truncate(0); + Array::add(0); +} + +inline void ArrayIntNull::move(size_t begin, size_t end, size_t dest_begin) +{ + Array::move(begin + 1, end + 1, dest_begin + 1); +} + +inline bool ArrayIntNull::find(int cond, Action action, value_type value, size_t start, size_t end, size_t baseindex, + QueryState* state) const +{ + if (value) { + return Array::find(cond, action, *value, start, end, baseindex, state, true /*treat as nullable array*/, + false /*search parameter given in 'value' argument*/); + } + else { + return Array::find(cond, action, 0 /* unused dummy*/, start, end, baseindex, state, + true /*treat as nullable array*/, true /*search for null, ignore value argument*/); + } +} + +template +bool ArrayIntNull::find(value_type value, size_t start, size_t end, size_t baseindex, QueryState* state, + Callback callback) const +{ + if (value) { + return Array::find(*value, start, end, baseindex, state, std::forward(callback), + true /*treat as nullable array*/, + false /*search parameter given in 'value' argument*/); + } + else { + return Array::find(0 /*ignored*/, start, end, baseindex, state, + std::forward(callback), true /*treat as nullable array*/, + true /*search for null, ignore value argument*/); + } +} + + +template +bool ArrayIntNull::find(int64_t value, size_t start, size_t end, size_t baseindex, QueryState* state) const +{ + return Array::find(value, start, end, baseindex, state, true /*treat as nullable array*/, + false /*search parameter given in 'value' argument*/); +} + + +template +bool ArrayIntNull::find(value_type value, size_t start, size_t end, size_t baseindex, QueryState* state, + Callback callback) const +{ + if (value) { + return Array::find(*value, start, end, baseindex, state, std::forward(callback), + true /*treat as nullable array*/, + false /*search parameter given in 'value' argument*/); + } + else { + return Array::find(0 /*ignored*/, start, end, baseindex, state, + std::forward(callback), true /*treat as nullable array*/, + true /*search for null, ignore value argument*/); + } +} + + +template +bool ArrayIntNull::find_action(size_t index, value_type value, QueryState* state, Callback callback) const +{ + if (value) { + return Array::find_action(index, *value, state, callback, true /*treat as nullable array*/, + false /*search parameter given in 'value' argument*/); + } + else { + return Array::find_action(index, 0 /* ignored */, state, callback, + true /*treat as nullable array*/, + true /*search for null, ignore value argument*/); + } +} + + +template +bool ArrayIntNull::find_action_pattern(size_t index, uint64_t pattern, QueryState* state, + Callback callback) const +{ + return Array::find_action_pattern(index, pattern, state, callback, + true /*treat as nullable array*/, + false /*search parameter given in 'value' argument*/); +} + + +template +size_t ArrayIntNull::find_first(value_type value, size_t start, size_t end) const +{ + QueryState state(act_ReturnFirst, 1); + if (value) { + Array::find(*value, start, end, 0, &state, Array::CallbackDummy(), + true /*treat as nullable array*/, + false /*search parameter given in 'value' argument*/); + } + else { + Array::find(0 /*ignored*/, start, end, 0, &state, Array::CallbackDummy(), + true /*treat as nullable array*/, + true /*search for null, ignore value argument*/); + } + + if (state.m_match_count > 0) + return to_size_t(state.m_state); + else + return not_found; +} + +inline size_t ArrayIntNull::find_first(value_type value, size_t begin, size_t end) const +{ + return find_first(value, begin, end); +} +} // namespace realm + +#endif // REALM_ARRAY_INTEGER_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_key.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_key.hpp new file mode 100644 index 0000000..b18cbde --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_key.hpp @@ -0,0 +1,127 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_ARRAY_KEY_HPP +#define REALM_ARRAY_KEY_HPP + +#include +#include +#include + +namespace realm { + +// If this class is used directly in a cluster leaf, the links are stored as the +// link value +1 in order to represent the null_key (-1) as 0. If the class is used +// in BPlusTree class, the values should not be adjusted. +template +class ArrayKeyBase : public ArrayPayload, private Array { +public: + using value_type = ObjKey; + + using Array::is_attached; + using Array::init_from_mem; + using Array::init_from_parent; + using Array::update_parent; + using Array::get_ref; + using Array::size; + using Array::erase; + using Array::clear; + using Array::destroy; + + ArrayKeyBase(Allocator& allocator) + : Array(allocator) + { + } + + static ObjKey default_value(bool) + { + return {}; + } + + void init_from_ref(ref_type ref) noexcept override + { + Array::init_from_ref(ref); + } + + void set_parent(ArrayParent* parent, size_t ndx_in_parent) noexcept override + { + Array::set_parent(parent, ndx_in_parent); + } + + void create() + { + Array::create(type_Normal); + } + + void add(ObjKey value) + { + Array::add(value.value + adj); + } + void set(size_t ndx, ObjKey value) + { + Array::set(ndx, value.value + adj); + } + + void set_null(size_t ndx) + { + Array::set(ndx, 0); + } + void insert(size_t ndx, ObjKey value) + { + Array::insert(ndx, value.value + adj); + } + ObjKey get(size_t ndx) const + { + return ObjKey{Array::get(ndx) - adj}; + } + bool is_null(size_t ndx) const + { + return Array::get(ndx) == 0; + } + void move(ArrayKeyBase& dst, size_t ndx) + { + Array::move(dst, ndx); + } + + size_t find_first(ObjKey value, size_t begin, size_t end) const noexcept + { + return Array::find_first(value.value + adj, begin, end); + } + + void nullify(ObjKey key) + { + size_t begin = find_first(key, 0, Array::size()); + // There must be one + REALM_ASSERT(begin != realm::npos); + Array::erase(begin); + } + void verify() const; +}; + +class ArrayKey : public ArrayKeyBase<1> { +public: + using ArrayKeyBase::ArrayKeyBase; +}; + +class ArrayKeyNonNullable : public ArrayKeyBase<0> { +public: + using ArrayKeyBase::ArrayKeyBase; +}; +} + +#endif /* SRC_REALM_ARRAY_KEY_HPP_ */ diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_list.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_list.hpp new file mode 100644 index 0000000..fa41700 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_list.hpp @@ -0,0 +1,94 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_ARRAY_LIST_HPP +#define REALM_ARRAY_LIST_HPP + +#include + +namespace realm { + +class ArrayList : public ArrayPayload, private Array { +public: + using value_type = ref_type; + + using Array::Array; + using Array::init_from_parent; + using Array::update_parent; + using Array::get_ref; + using Array::size; + using Array::erase; + + static ref_type default_value(bool) + { + return 0; + } + + void init_from_ref(ref_type ref) noexcept override + { + Array::init_from_ref(ref); + } + + void set_parent(ArrayParent* parent, size_t ndx_in_parent) noexcept override + { + Array::set_parent(parent, ndx_in_parent); + } + + void create() + { + Array::create(type_HasRefs); + } + + void add(ref_type value) + { + Array::add(from_ref(value)); + } + void set(size_t ndx, ref_type value) + { + Array::set_as_ref(ndx, value); + } + + void set_null(size_t ndx) + { + Array::set(ndx, 0); + } + void insert(size_t ndx, ref_type value) + { + Array::insert(ndx, from_ref(value)); + } + ref_type get(size_t ndx) const + { + return Array::get_as_ref(ndx); + } + bool is_null(size_t ndx) const + { + return Array::get(ndx) == 0; + } + void truncate_and_destroy_children(size_t ndx) + { + Array::truncate(ndx); + } + + size_t find_first(ref_type value, size_t begin, size_t end) const noexcept + { + return Array::find_first(from_ref(value), begin, end); + } +}; +} + +#endif /* REALM_ARRAY_LIST_HPP */ diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_mixed.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_mixed.hpp new file mode 100644 index 0000000..20f912d --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_mixed.hpp @@ -0,0 +1,134 @@ +/************************************************************************* + * + * Copyright 2018 Realm Inc. + * + * 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 REALM_ARRAY_MIXED_HPP +#define REALM_ARRAY_MIXED_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace realm { + +class ArrayMixed : public ArrayPayload, private Array { +public: + using value_type = Mixed; + + using Array::detach; + using Array::is_attached; + using Array::get_ref; + using Array::set_parent; + using Array::update_parent; + using Array::get_parent; + + explicit ArrayMixed(Allocator&); + + static Mixed default_value(bool) + { + return Mixed{}; + } + + void create(); + void destroy() + { + Array::destroy_deep(); + } + + void init_from_mem(MemRef mem) noexcept; + + void init_from_ref(ref_type ref) noexcept override + { + init_from_mem(MemRef(m_alloc.translate(ref), ref, m_alloc)); + } + void set_parent(ArrayParent* parent, size_t ndx_in_parent) noexcept override + { + Array::set_parent(parent, ndx_in_parent); + } + void init_from_parent() + { + ref_type ref = get_ref_from_parent(); + ArrayMixed::init_from_ref(ref); + } + + size_t size() const + { + return m_composite.size(); + } + + void add(Mixed value); + void set(size_t ndx, Mixed value); + void set_null(size_t ndx); + void insert(size_t ndx, Mixed value); + Mixed get(size_t ndx) const; + bool is_null(size_t ndx) const + { + return m_composite.get(ndx) == 0; + } + + void clear(); + void erase(size_t ndx); + void truncate_and_destroy_children(size_t ndx); + void move(ArrayMixed& dst, size_t ndx); + + size_t find_first(Mixed value, size_t begin = 0, size_t end = realm::npos) const noexcept; + + void verify() const; + +private: + enum { payload_idx_type, payload_idx_int, payload_idx_pair, payload_idx_str, payload_idx_size }; + + static constexpr int64_t s_data_type_mask = 0b0001'1111; + static constexpr int64_t s_payload_idx_mask = 0b1110'0000; + static constexpr int64_t s_payload_idx_shift = 5; + static constexpr int64_t s_data_shift = 8; + + // This primary array contains an aggregation of the actual value - which can be + // either the value itself or an index into one of the payload arrays - the index + // of the payload array and the data_type. + // + // value << s_data_shift | payload_idx << s_payload_idx_shift | data_type + // + // payload_idx one of PayloadIdx + Array m_composite; + + // Used to store big ints, floats and doubles + mutable Array m_ints; + // Used to store timestamps + mutable Array m_int_pairs; + // Used to store String and Binary + mutable ArrayString m_strings; + + DataType get_type(size_t ndx) const + { + return DataType((m_composite.get(ndx) & s_data_type_mask) - 1); + } + int64_t store(const Mixed&); + void ensure_array_accessor(Array& arr, size_t ndx_in_parent) const; + void ensure_int_array() const; + void ensure_int_pair_array() const; + void ensure_string_array() const; + void replace_index(size_t old_ndx, size_t new_ndx, size_t payload_index); + void erase_linked_payload(size_t ndx); +}; +} // namespace realm + +#endif /* REALM_ARRAY_MIXED_HPP */ diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_object_id.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_object_id.hpp new file mode 100644 index 0000000..10f029a --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_object_id.hpp @@ -0,0 +1,233 @@ +/************************************************************************* + * + * Copyright 2019 Realm Inc. + * + * 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 REALM_ARRAY_OBJECT_ID_HPP +#define REALM_ARRAY_OBJECT_ID_HPP + +#include +#include + +namespace realm { + +class ArrayObjectId : public ArrayPayload, protected Array { +public: + using value_type = ObjectId; + + using Array::Array; + using Array::destroy; + using Array::get_ref; + using Array::init_from_mem; + using Array::init_from_parent; + using Array::update_parent; + using Array::verify; + + static ObjectId default_value(bool nullable) + { + REALM_ASSERT(!nullable); + return ObjectId(); + } + + void create() + { + auto mem = Array::create(type_Normal, false, wtype_Multiply, 0, 0, m_alloc); // Throws + Array::init_from_mem(mem); + } + + void init_from_ref(ref_type ref) noexcept override + { + Array::init_from_ref(ref); + } + + void set_parent(ArrayParent* parent, size_t ndx_in_parent) noexcept override + { + Array::set_parent(parent, ndx_in_parent); + } + + size_t size() const + { + auto data_bytes = m_size - div_round_up(m_size); // remove one byte per block. + return data_bytes / s_width; + } + + bool is_null(size_t ndx) const + { + return this->get_width() == 0 || get_pos(ndx).is_null(this); + } + + ObjectId get(size_t ndx) const + { + REALM_ASSERT(is_valid_ndx(ndx)); + REALM_ASSERT(!is_null(ndx)); + return get_pos(ndx).get_value(this); + } + + void add(const ObjectId& value) + { + insert(size(), value); + } + + void set(size_t ndx, const ObjectId& value); + void insert(size_t ndx, const ObjectId& value); + void erase(size_t ndx); + void move(ArrayObjectId& dst, size_t ndx); + void clear() + { + truncate(0); + } + void truncate(size_t ndx) + { + Array::truncate(calc_required_bytes(ndx)); + } + + size_t find_first(const ObjectId& value, size_t begin = 0, size_t end = npos) const noexcept; + +protected: + static constexpr size_t s_width = sizeof(ObjectId); // Size of each element + static_assert(s_width == 12, "Size of ObjectId must be 12"); + + // A block is a byte bitvector indicating null entries and 8 ObjectIds. + static constexpr size_t s_block_size = s_width * 8 + 1; // 97 + + template + static size_t div_round_up(size_t num) + { + return (num + div - 1) / div; + } + + // An accessor for the data at a given index. All casting and offset calculation should be kept here. + struct Pos { + size_t base_byte; + size_t offset; + + void set_value(ArrayObjectId* arr, const ObjectId& val) const + { + reinterpret_cast(arr->m_data + base_byte + 1 /*null bit byte*/)[offset] = val; + } + const ObjectId& get_value(const ArrayObjectId* arr) const + { + return reinterpret_cast(arr->m_data + base_byte + 1 /*null bit byte*/)[offset]; + } + + void set_null(ArrayObjectId* arr, bool new_is_null) const + { + auto& bitvec = arr->m_data[base_byte]; + if (new_is_null) { + bitvec |= 1 << offset; + } + else { + bitvec &= ~(1 << offset); + } + } + bool is_null(const ArrayObjectId* arr) const + { + return arr->m_data[base_byte] & (1 << offset); + } + }; + + static Pos get_pos(size_t ndx) + { + + return Pos{(ndx / 8) * s_block_size, ndx % 8}; + } + + static size_t calc_required_bytes(size_t num_items) + { + return (num_items * s_width) + // ObjectId data + (div_round_up<8>(num_items)); // null bitvectors (1 byte per 8 oids, rounded up) + } + + size_t calc_byte_len(size_t num_items, size_t /*unused width*/ = 0) const override + { + return num_items + Node::header_size; + } + + bool is_valid_ndx(size_t ndx) const + { + return calc_byte_len(ndx) <= m_size; + } +}; + +// The nullable ObjectId array uses the same layout and is compatible with the non-nullable one. It adds support for +// operations on null. Because the base class maintains null markers, we are able to defer to it for many operations. +class ArrayObjectIdNull : public ArrayObjectId { +public: + using ArrayObjectId::ArrayObjectId; + static util::Optional default_value(bool nullable) + { + if (nullable) + return util::none; + return ObjectId(); + } + + void set(size_t ndx, const util::Optional& value) + { + if (value) { + ArrayObjectId::set(ndx, *value); + } + else { + set_null(ndx); + } + } + void add(const util::Optional& value) + { + insert(size(), value); + } + void insert(size_t ndx, const util::Optional& value) + { + if (value) { + ArrayObjectId::insert(ndx, *value); + } + else { + ArrayObjectId::insert(ndx, null_oid); + set_null(ndx); + } + } + void set_null(size_t ndx) + { + copy_on_write(); + auto pos = get_pos(ndx); + pos.set_value(this, null_oid); + pos.set_null(this, true); + } + util::Optional get(size_t ndx) const noexcept + { + auto pos = get_pos(ndx); + if (pos.is_null(this)) { + return util::none; + } + return pos.get_value(this); + } + size_t find_first(const util::Optional& value, size_t begin = 0, size_t end = npos) const + { + if (value) { + return ArrayObjectId::find_first(*value, begin, end); + } + else { + return find_first_null(begin, end); + } + } + size_t find_first_null(size_t begin = 0, size_t end = npos) const; + +private: + static const ObjectId null_oid; +}; + + +} // namespace realm + +#endif /* REALM_ARRAY_OBJECT_ID_HPP */ diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_ref.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_ref.hpp new file mode 100644 index 0000000..7b1789f --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_ref.hpp @@ -0,0 +1,70 @@ +/************************************************************************* + * + * Copyright 2020 Realm Inc. + * + * 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 REALM_ARRAY_REF_HPP_ +#define REALM_ARRAY_REF_HPP_ + +#include + +namespace realm { + +class ArrayRef : public Array { +public: + using value_type = ref_type; + + explicit ArrayRef(Allocator& allocator) noexcept + : Array(allocator) + { + } + + void create(size_t sz = 0) + { + Array::create(type_HasRefs, false, sz, 0); + } + + void add(ref_type value) + { + Array::add(from_ref(value)); + } + + void set(size_t ndx, ref_type value) + { + Array::set(ndx, from_ref(value)); + } + + void insert(size_t ndx, ref_type value) + { + Array::insert(ndx, from_ref(value)); + } + + ref_type get(size_t ndx) const noexcept + { + return to_ref(Array::get(ndx)); + } + void verify() const + { +#ifdef REALM_DEBUG + Array::verify(); + REALM_ASSERT(has_refs()); +#endif + } +}; + +} // namespace realm + +#endif /* REALM_ARRAY_REF_HPP_ */ diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_string.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_string.hpp new file mode 100644 index 0000000..6d41cce --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_string.hpp @@ -0,0 +1,201 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_ARRAY_STRING_HPP +#define REALM_ARRAY_STRING_HPP + +#include +#include +#include + +namespace realm { + +class Spec; + +class ArrayString : public ArrayPayload { +public: + using value_type = StringData; + + explicit ArrayString(Allocator&); + + static StringData default_value(bool nullable) + { + return nullable ? StringData{} : StringData{""}; + } + + // This is only used in the upgrade process + void set_nullability(bool n) + { + m_nullable = n; + } + void create(); + + bool is_attached() const + { + return m_arr->is_attached(); + } + + void detach() const + { + m_arr->detach(); + } + + ref_type get_ref() const + { + return m_arr->get_ref(); + } + ArrayParent* get_parent() const + { + return m_arr->get_parent(); + } + size_t get_ndx_in_parent() const + { + return m_arr->get_ndx_in_parent(); + } + void set_parent(ArrayParent* p, size_t n) noexcept override + { + m_arr->set_parent(p, n); + } + bool need_spec() const override + { + return true; + } + void set_spec(Spec* spec, size_t col_ndx) const override + { + m_spec = spec; + m_col_ndx = col_ndx; + } + + void update_parent() + { + m_arr->update_parent(); + } + + void init_from_mem(MemRef mem) noexcept; + void init_from_ref(ref_type ref) noexcept override + { + init_from_mem(MemRef(m_alloc.translate(ref), ref, m_alloc)); + } + void init_from_parent(); + void destroy(); + + size_t size() const; + + void add(StringData value); + void set(size_t ndx, StringData value); + void set_null(size_t ndx) + { + set(ndx, StringData{}); + } + void insert(size_t ndx, StringData value); + StringData get(size_t ndx) const; + StringData get_legacy(size_t ndx) const; + bool is_null(size_t ndx) const; + void erase(size_t ndx); + void move(ArrayString& dst, size_t ndx); + void clear(); + + size_t find_first(StringData value, size_t begin, size_t end) const noexcept; + + size_t lower_bound(StringData value); + + /// Get the specified element without the cost of constructing an + /// array instance. If an array instance is already available, or + /// you need to get multiple values, then this method will be + /// slower. + static StringData get(const char* header, size_t ndx, Allocator& alloc) noexcept; + + void verify() const; + +private: + static constexpr size_t small_string_max_size = 15; // ArrayStringShort + static constexpr size_t medium_string_max_size = 63; // ArrayStringLong + union Storage { + std::aligned_storage::type m_string_short; + std::aligned_storage::type m_string_long; + std::aligned_storage::type m_big_blobs; + std::aligned_storage::type m_enum; + }; + enum class Type { small_strings, medium_strings, big_strings, enum_strings }; + + Type m_type = Type::small_strings; + + Allocator& m_alloc; + Storage m_storage; + Array* m_arr; + mutable Spec* m_spec = nullptr; + mutable size_t m_col_ndx = realm::npos; + bool m_nullable = true; + + std::unique_ptr m_string_enum_values; + + Type upgrade_leaf(size_t value_size); +}; + +inline StringData ArrayString::get(const char* header, size_t ndx, Allocator& alloc) noexcept +{ + bool long_strings = Array::get_hasrefs_from_header(header); + if (!long_strings) { + return ArrayStringShort::get(header, ndx, true); + } + else { + bool is_big = Array::get_context_flag_from_header(header); + if (!is_big) { + return ArraySmallBlobs::get_string(header, ndx, alloc); + } + else { + return ArrayBigBlobs::get_string(header, ndx, alloc); + } + } +} + +template <> +class QueryState : public QueryStateBase { +public: + StringData m_state; + + template + bool uses_val() + { + return false; + } + + QueryState(Action, Array* = nullptr, size_t limit = -1) + : QueryStateBase(limit) + { + } + + template + inline bool match(size_t, uint64_t, StringData) + { + if (pattern) + return false; + + if (action == act_Count) { + ++m_match_count; + } + else { + REALM_ASSERT_DEBUG(false); + } + + return (m_limit > m_match_count); + } +}; +} + +#endif /* REALM_ARRAY_STRING_HPP */ diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_string_short.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_string_short.hpp new file mode 100644 index 0000000..28028ad --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_string_short.hpp @@ -0,0 +1,173 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_ARRAY_STRING_SHORT_HPP +#define REALM_ARRAY_STRING_SHORT_HPP + +#include + +namespace realm { + +/* +ArrayStringShort stores strings as a concecutive list of fixed-length blocks of m_width bytes. The +longest string it can store is (m_width - 1) bytes before it needs to expand. + +An example of the format for m_width = 4 is following sequence of bytes, where x is payload: + +xxx0 xx01 x002 0003 0004 (strings "xxx",. "xx", "x", "", realm::null()) + +So each string is 0 terminated, and the last byte in a block tells how many 0s are present, except +for a realm::null() which has the byte set to m_width (4). The byte is used to compute the length of a string +in various functions. + +New: If m_witdh = 0, then all elements are realm::null(). So to add an empty string we must expand m_width +New: StringData is null() if-and-only-if StringData::data() == 0. +*/ + +class ArrayStringShort : public Array { +public: + static const size_t max_width = 64; + + typedef StringData value_type; + // Constructor defaults to non-nullable because we use non-nullable ArrayStringShort so many places internally + // in core (data which isn't user payload) where null isn't needed. + explicit ArrayStringShort(Allocator&, bool nullable = false) noexcept; + ~ArrayStringShort() noexcept override + { + } + + bool is_null(size_t ndx) const; + void set_null(size_t ndx); + StringData get(size_t ndx) const noexcept; + void add(); + void add(StringData value); + void set(size_t ndx, StringData value); + void insert(size_t ndx, StringData value); + void erase(size_t ndx); + + size_t count(StringData value, size_t begin = 0, size_t end = npos) const noexcept; + size_t find_first(StringData value, size_t begin = 0, size_t end = npos) const noexcept; + void find_all(IntegerColumn& result, StringData value, size_t add_offset = 0, size_t begin = 0, + size_t end = npos); + + /// Compare two string arrays for equality. + bool compare_string(const ArrayStringShort&) const noexcept; + + /// Get the specified element without the cost of constructing an + /// array instance. If an array instance is already available, or + /// you need to get multiple values, then this method will be + /// slower. + static StringData get(const char* header, size_t ndx, bool nullable) noexcept; + + /// Construct a string array of the specified size and return just + /// the reference to the underlying memory. All elements will be + /// initialized to the empty string. + static MemRef create_array(size_t size, Allocator&); + + /// Create a new empty string array and attach this accessor to + /// it. This does not modify the parent reference information of + /// this accessor. + /// + /// Note that the caller assumes ownership of the allocated + /// underlying node. It is not owned by the accessor. + void create(); + +#ifdef REALM_DEBUG + void string_stats() const; +#endif + +private: + size_t calc_byte_len(size_t num_items, size_t width) const override; + size_t calc_item_count(size_t bytes, size_t width) const noexcept override; + + bool m_nullable; +}; + + +// Implementation: + +// Creates new array (but invalid, call init_from_ref() to init) +inline ArrayStringShort::ArrayStringShort(Allocator& allocator, bool nullable) noexcept + : Array(allocator) + , m_nullable(nullable) +{ +} + +inline void ArrayStringShort::create() +{ + size_t init_size = 0; + MemRef mem = create_array(init_size, get_alloc()); // Throws + init_from_mem(mem); +} + +inline MemRef ArrayStringShort::create_array(size_t init_size, Allocator& allocator) +{ + bool context_flag = false; + int_fast64_t value = 0; + return Array::create(type_Normal, context_flag, wtype_Multiply, init_size, value, allocator); // Throws +} + +inline StringData ArrayStringShort::get(size_t ndx) const noexcept +{ + REALM_ASSERT_3(ndx, <, m_size); + if (m_width == 0) + return m_nullable ? realm::null() : StringData(""); + + const char* data = m_data + (ndx * m_width); + size_t array_size = (m_width - 1) - data[m_width - 1]; + + if (array_size == static_cast(-1)) + return m_nullable ? realm::null() : StringData(""); + + REALM_ASSERT_EX(data[array_size] == 0, data[array_size], + array_size); // Realm guarantees 0 terminated return strings + return StringData(data, array_size); +} + +inline void ArrayStringShort::add(StringData value) +{ + REALM_ASSERT(!(!m_nullable && value.is_null())); + insert(m_size, value); // Throws +} + +inline void ArrayStringShort::add() +{ + add(m_nullable ? realm::null() : StringData("")); // Throws +} + +inline StringData ArrayStringShort::get(const char* header, size_t ndx, bool nullable) noexcept +{ + REALM_ASSERT(ndx < get_size_from_header(header)); + uint_least8_t width = get_width_from_header(header); + const char* data = get_data_from_header(header) + (ndx * width); + + if (width == 0) + return nullable ? realm::null() : StringData(""); + + size_t size = (width - 1) - data[width - 1]; + + if (size == static_cast(-1)) + return nullable ? realm::null() : StringData(""); + + return StringData(data, size); +} + + +} // namespace realm + +#endif // REALM_ARRAY_STRING_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_timestamp.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_timestamp.hpp new file mode 100644 index 0000000..65da075 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_timestamp.hpp @@ -0,0 +1,189 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_ARRAY_TIMESTAMP_HPP +#define REALM_ARRAY_TIMESTAMP_HPP + +#include +#include + +namespace realm { + +class ArrayTimestamp : public ArrayPayload, private Array { +public: + using value_type = Timestamp; + + explicit ArrayTimestamp(Allocator&); + + using Array::update_parent; + using Array::get_parent; + using Array::get_ndx_in_parent; + using Array::get_ref; + + static Timestamp default_value(bool nullable) + { + return nullable ? Timestamp{} : Timestamp{0, 0}; + } + + void create(); + + void init_from_mem(MemRef mem) noexcept; + void init_from_ref(ref_type ref) noexcept override + { + init_from_mem(MemRef(m_alloc.translate(ref), ref, m_alloc)); + } + void set_parent(ArrayParent* parent, size_t ndx_in_parent) noexcept override + { + Array::set_parent(parent, ndx_in_parent); + } + void init_from_parent() + { + init_from_ref(Array::get_ref_from_parent()); + } + + size_t size() const + { + return m_seconds.size(); + } + + void add(Timestamp value) + { + insert(m_seconds.size(), value); + } + void set(size_t ndx, Timestamp value); + void set_null(size_t ndx) + { + // Value in m_nanoseconds is irrelevant if m_seconds is null + m_seconds.set_null(ndx); // Throws + } + void insert(size_t ndx, Timestamp value); + Timestamp get(size_t ndx) const + { + util::Optional seconds = m_seconds.get(ndx); + return seconds ? Timestamp(*seconds, int32_t(m_nanoseconds.get(ndx))) : Timestamp{}; + } + bool is_null(size_t ndx) const + { + return m_seconds.is_null(ndx); + } + void erase(size_t ndx) + { + m_seconds.erase(ndx); + m_nanoseconds.erase(ndx); + } + void move(ArrayTimestamp& dst, size_t ndx) + { + m_seconds.move(dst.m_seconds, ndx); + m_nanoseconds.move(dst.m_nanoseconds, ndx); + } + void clear() + { + m_seconds.clear(); + m_nanoseconds.clear(); + } + + template + size_t find_first(Timestamp value, size_t begin, size_t end) const noexcept; + + size_t find_first(Timestamp value, size_t begin, size_t end) const noexcept; + + void verify() const; + +private: + ArrayIntNull m_seconds; + ArrayInteger m_nanoseconds; +}; + +template <> +size_t ArrayTimestamp::find_first(Timestamp value, size_t begin, size_t end) const noexcept; +template <> +size_t ArrayTimestamp::find_first(Timestamp value, size_t begin, size_t end) const noexcept; +template <> +size_t ArrayTimestamp::find_first(Timestamp value, size_t begin, size_t end) const noexcept; +template <> +size_t ArrayTimestamp::find_first(Timestamp value, size_t begin, size_t end) const noexcept; +template <> +size_t ArrayTimestamp::find_first(Timestamp value, size_t begin, size_t end) const noexcept; +template <> +size_t ArrayTimestamp::find_first(Timestamp value, size_t begin, size_t end) const noexcept; + +inline size_t ArrayTimestamp::find_first(Timestamp value, size_t begin, size_t end) const noexcept +{ + return find_first(value, begin, end); +} + + +template <> +class QueryState : public QueryStateBase { +public: + Timestamp m_state; + + template + bool uses_val() + { + return (action == act_Max || action == act_Min || action == act_Sum); + } + + QueryState(Action action, Array* = nullptr, size_t limit = -1) + : QueryStateBase(limit) + { + if (action == act_Max) + m_state = Timestamp{std::numeric_limits::min(), 0}; + else if (action == act_Min) + m_state = Timestamp{std::numeric_limits::max(), 0}; + else { + REALM_ASSERT_DEBUG(false); + } + } + + template + inline bool match(size_t index, uint64_t /*indexpattern*/, Timestamp value) + { + if (pattern) + return false; + + if (action == act_Count) { + ++m_match_count; + } + else { + ++m_match_count; + if (action == act_Max) { + if (value > m_state) { + m_state = value; + REALM_ASSERT(m_key_values); + m_minmax_index = m_key_values->get(index) + m_key_offset; + } + } + else if (action == act_Min) { + if (value < m_state) { + m_state = value; + REALM_ASSERT(m_key_values); + m_minmax_index = m_key_values->get(index) + m_key_offset; + } + } + else { + REALM_ASSERT_DEBUG(false); + } + } + + return (m_limit > m_match_count); + } +}; +} + +#endif /* SRC_REALM_ARRAY_BINARY_HPP_ */ diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_unsigned.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_unsigned.hpp new file mode 100644 index 0000000..598e0f5 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/array_unsigned.hpp @@ -0,0 +1,115 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_ARRAY_UNSIGNED_HPP +#define REALM_ARRAY_UNSIGNED_HPP + +#include + +namespace realm { + +// Array holding unsigned values only +class ArrayUnsigned : public Node { + +public: + ArrayUnsigned(Allocator& allocator) + : Node(allocator) + { + } + + // Will create an uninitialized array of size 'initial_size' + // Has a width big enough to hold values smaller than 'ubound_value' + void create(size_t initial_size, uint64_t ubound_value); + + void init_from_ref(ref_type ref) noexcept + { + REALM_ASSERT_DEBUG(ref); + char* header = m_alloc.translate(ref); + init_from_mem(MemRef(header, ref, m_alloc)); + } + + bool update_from_parent(size_t old_baseline) noexcept; + + size_t lower_bound(uint64_t value) const noexcept; + size_t upper_bound(uint64_t value) const noexcept; + + void add(uint64_t value) + { + insert(m_size, value); + } + // insert value at index (moving successive elements 1 position forwards) + void insert(size_t ndx, uint64_t value); + // delete value at index + void erase(size_t ndx); + // return value at index + uint64_t get(size_t index) const; + // return tagged value at index + // override value at index + void set(size_t ndx, uint64_t value); + + void adjust(size_t begin, size_t end, int64_t diff) + { + if (diff != 0) { + // FIXME: Should be optimized + for (size_t i = begin; i < end; ++i) + adjust(i, diff); // Throws + } + } + + void truncate(size_t ndx); + + /// The meaning of 'width' depends on the context in which this + /// array is used. + size_t get_width() const noexcept + { + return m_width; + } + +private: + uint_least8_t m_width = 0; // Size of an element (meaning depend on type of array). + uint64_t m_ubound; // max number that can be stored with current m_width + + void init_from_mem(MemRef mem) noexcept + { + Node::init_from_mem(mem); + set_width(get_width_from_header(get_header())); + } + + void adjust(size_t ndx, int64_t diff) + { + if (diff != 0) { + set(ndx, get(ndx) + diff); // Throws + } + } + + void alloc(size_t init_size, size_t new_width) + { + Node::alloc(init_size, new_width); + set_width(uint8_t(new_width)); + } + + void set_width(uint8_t width); + uint8_t bit_width(uint64_t value); + + void _set(size_t ndx, uint8_t width, uint64_t value); + uint64_t _get(size_t ndx, uint8_t width) const; +}; + +} // namespace realm + +#endif /* REALM_ARRAY_UNSIGNED_HPP */ diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/binary_data.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/binary_data.hpp new file mode 100644 index 0000000..b4a110f --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/binary_data.hpp @@ -0,0 +1,244 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_BINARY_DATA_HPP +#define REALM_BINARY_DATA_HPP + +#include +#include +#include + +#include +#include +#include +#include + +namespace realm { + +/// A reference to a chunk of binary data. +/// +/// This class does not own the referenced memory, nor does it in any other way +/// attempt to manage the lifetime of it. +/// +/// \sa StringData +class BinaryData { +public: + BinaryData() noexcept + : m_data(nullptr) + , m_size(0) + { + } + BinaryData(const char* external_data, size_t data_size) noexcept + : m_data(external_data) + , m_size(data_size) + { + } + template + explicit BinaryData(const char (&external_data)[N]) + : m_data(external_data) + , m_size(N) + { + } + template + explicit BinaryData(const std::basic_string&); + + // BinaryData does not store data, callers must manage their own strings. + template + BinaryData(const std::basic_string&&) = delete; + + template + explicit operator std::basic_string() const; + + char operator[](size_t i) const noexcept + { + return m_data[i]; + } + + const char* data() const noexcept + { + return m_data; + } + size_t size() const noexcept + { + return m_size; + } + + /// Is this a null reference? + /// + /// An instance of BinaryData is a null reference when, and only when the + /// stored size is zero (size()) and the stored pointer is the null pointer + /// (data()). + /// + /// In the case of the empty byte sequence, the stored size is still zero, + /// but the stored pointer is **not** the null pointer. Note that the actual + /// value of the pointer is immaterial in this case (as long as it is not + /// zero), because when the size is zero, it is an error to dereference the + /// pointer. + /// + /// Conversion of a BinaryData object to `bool` yields the logical negation + /// of the result of calling this function. In other words, a BinaryData + /// object is converted to true if it is not the null reference, otherwise + /// it is converted to false. + /// + /// It is important to understand that all of the functions and operators in + /// this class, and most of the functions in the Realm API in general + /// makes no distinction between a null reference and a reference to the + /// empty byte sequence. These functions and operators never look at the + /// stored pointer if the stored size is zero. + bool is_null() const noexcept; + + friend bool operator==(const BinaryData&, const BinaryData&) noexcept; + friend bool operator!=(const BinaryData&, const BinaryData&) noexcept; + + //@{ + /// Trivial bytewise lexicographical comparison. + friend bool operator<(const BinaryData&, const BinaryData&) noexcept; + friend bool operator>(const BinaryData&, const BinaryData&) noexcept; + friend bool operator<=(const BinaryData&, const BinaryData&) noexcept; + friend bool operator>=(const BinaryData&, const BinaryData&) noexcept; + //@} + + bool begins_with(BinaryData) const noexcept; + bool ends_with(BinaryData) const noexcept; + bool contains(BinaryData) const noexcept; + + template + friend std::basic_ostream& operator<<(std::basic_ostream&, const BinaryData&); + + explicit operator bool() const noexcept; + +private: + const char* m_data; + size_t m_size; +}; + +/// A read-only chunk of binary data. +class OwnedBinaryData : public OwnedData { +public: + using OwnedData::OwnedData; + + OwnedBinaryData() = default; + OwnedBinaryData(const BinaryData& binary_data) + : OwnedData(binary_data.data(), binary_data.size()) + { + } + + BinaryData get() const + { + return {data(), size()}; + } +}; + + +// Implementation: + +template +inline BinaryData::BinaryData(const std::basic_string& s) + : m_data(s.data()) + , m_size(s.size()) +{ +} + +template +inline BinaryData::operator std::basic_string() const +{ + return std::basic_string(m_data, m_size); +} + +inline bool BinaryData::is_null() const noexcept +{ + return !m_data; +} + +inline bool operator==(const BinaryData& a, const BinaryData& b) noexcept +{ + return a.m_size == b.m_size && a.is_null() == b.is_null() && safe_equal(a.m_data, a.m_data + a.m_size, b.m_data); +} + +inline bool operator!=(const BinaryData& a, const BinaryData& b) noexcept +{ + return !(a == b); +} + +inline bool operator<(const BinaryData& a, const BinaryData& b) noexcept +{ + if (a.is_null() || b.is_null()) + return !a.is_null() < !b.is_null(); + + return std::lexicographical_compare(a.m_data, a.m_data + a.m_size, b.m_data, b.m_data + b.m_size); +} + +inline bool operator>(const BinaryData& a, const BinaryData& b) noexcept +{ + return b < a; +} + +inline bool operator<=(const BinaryData& a, const BinaryData& b) noexcept +{ + return !(b < a); +} + +inline bool operator>=(const BinaryData& a, const BinaryData& b) noexcept +{ + return !(a < b); +} + +inline bool BinaryData::begins_with(BinaryData d) const noexcept +{ + if (is_null() && !d.is_null()) + return false; + + return d.m_size <= m_size && safe_equal(m_data, m_data + d.m_size, d.m_data); +} + +inline bool BinaryData::ends_with(BinaryData d) const noexcept +{ + if (is_null() && !d.is_null()) + return false; + + return d.m_size <= m_size && safe_equal(m_data + m_size - d.m_size, m_data + m_size, d.m_data); +} + +inline bool BinaryData::contains(BinaryData d) const noexcept +{ + if (is_null() && !d.is_null()) + return false; + + return d.m_size == 0 || std::search(m_data, m_data + m_size, d.m_data, d.m_data + d.m_size) != m_data + m_size; +} + +template +inline std::basic_ostream& operator<<(std::basic_ostream& out, const BinaryData& d) +{ + if (d.is_null()) { + out << "null"; + } + else { + out << "BinaryData(" << static_cast(d.m_data) << ", " << d.m_size << ")"; + } + return out; +} + +inline BinaryData::operator bool() const noexcept +{ + return !is_null(); +} + +} // namespace realm + +#endif // REALM_BINARY_DATA_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/bplustree.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/bplustree.hpp new file mode 100644 index 0000000..19e4e08 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/bplustree.hpp @@ -0,0 +1,742 @@ +/************************************************************************* + * + * Copyright 2018 Realm Inc. + * + * 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 REALM_BPLUSTREE_HPP +#define REALM_BPLUSTREE_HPP + +#include +#include +#include +#include +#include + +namespace realm { + +class BPlusTreeBase; +class BPlusTreeInner; + +/*****************************************************************************/ +/* BPlusTreeNode */ +/* Base class for all nodes in the BPlusTree. Provides an abstract interface */ +/* that can be used by the BPlusTreeBase class to manipulate the tree. */ +/*****************************************************************************/ +class BPlusTreeNode { +public: + struct State { + int64_t split_offset; + size_t split_size; + }; + + // Insert an element at 'insert_pos'. May cause node to be split + using InsertFunc = util::FunctionRef; + // Access element at 'ndx'. Insertion/deletion not allowed + using AccessFunc = util::FunctionRef; + // Erase element at erase_pos. May cause nodes to be merged + using EraseFunc = util::FunctionRef; + // Function to be called for all leaves in the tree until the function + // returns 'true'. 'offset' gives index of the first element in the leaf. + using TraverseFunc = util::FunctionRef; + + BPlusTreeNode(BPlusTreeBase* tree) + : m_tree(tree) + { + } + + void change_owner(BPlusTreeBase* tree) + { + m_tree = tree; + } + + bool get_context_flag() const noexcept; + void set_context_flag(bool) noexcept; + + virtual ~BPlusTreeNode(); + + virtual bool is_leaf() const = 0; + virtual bool is_compact() const = 0; + virtual ref_type get_ref() const = 0; + + virtual void init_from_ref(ref_type ref) noexcept = 0; + + virtual void bp_set_parent(ArrayParent* parent, size_t ndx_in_parent) = 0; + virtual void update_parent() = 0; + + // Number of elements in this node + virtual size_t get_node_size() const = 0; + // Size of subtree + virtual size_t get_tree_size() const = 0; + + virtual ref_type bptree_insert(size_t n, State& state, InsertFunc) = 0; + virtual void bptree_access(size_t n, AccessFunc) = 0; + virtual size_t bptree_erase(size_t n, EraseFunc) = 0; + virtual bool bptree_traverse(TraverseFunc) = 0; + + // Move elements over in new node, starting with element at position 'ndx'. + // If this is an inner node, the index offsets should be adjusted with 'adj' + virtual void move(BPlusTreeNode* new_node, size_t ndx, int64_t offset_adj) = 0; + virtual void verify() const = 0; + +protected: + BPlusTreeBase* m_tree; +}; + +/*****************************************************************************/ +/* BPlusTreeLeaf */ +/* Base class for all leaf nodes. */ +/*****************************************************************************/ +class BPlusTreeLeaf : public BPlusTreeNode { +public: + using BPlusTreeNode::BPlusTreeNode; + + bool is_leaf() const override + { + return true; + } + + bool is_compact() const override + { + return true; + } + + ref_type bptree_insert(size_t n, State& state, InsertFunc) override; + void bptree_access(size_t n, AccessFunc) override; + size_t bptree_erase(size_t n, EraseFunc) override; + bool bptree_traverse(TraverseFunc) override; +}; + +/*****************************************************************************/ +/* BPlusTreeBase */ +/* Base class for the actual tree classes. */ +/*****************************************************************************/ +class BPlusTreeBase { +public: + BPlusTreeBase(Allocator& alloc) + : m_alloc(alloc) + { + invalidate_leaf_cache(); + } + virtual ~BPlusTreeBase(); + + BPlusTreeBase& operator=(const BPlusTreeBase& rhs); + BPlusTreeBase& operator=(BPlusTreeBase&& rhs) noexcept; + + Allocator& get_alloc() const + { + return m_alloc; + } + + bool is_attached() const + { + return bool(m_root); + } + + bool get_context_flag() const noexcept + { + return m_root->get_context_flag(); + } + + void set_context_flag(bool cf) noexcept + { + m_root->set_context_flag(cf); + } + + size_t size() const + { + return m_size; + } + + bool is_empty() const + { + return m_size == 0; + } + + ref_type get_ref() const + { + REALM_ASSERT(is_attached()); + return m_root->get_ref(); + } + + void init_from_ref(ref_type ref) + { + auto new_root = create_root_from_ref(ref); + new_root->bp_set_parent(m_parent, m_ndx_in_parent); + + m_root = std::move(new_root); + + invalidate_leaf_cache(); + m_size = m_root->get_tree_size(); + } + + bool init_from_parent() + { + ref_type ref = m_parent->get_child_ref(m_ndx_in_parent); + if (!ref) { + return false; + } + auto new_root = create_root_from_ref(ref); + new_root->bp_set_parent(m_parent, m_ndx_in_parent); + m_root = std::move(new_root); + invalidate_leaf_cache(); + m_size = m_root->get_tree_size(); + return true; + } + + void set_parent(ArrayParent* parent, size_t ndx_in_parent) + { + m_parent = parent; + m_ndx_in_parent = ndx_in_parent; + if (is_attached()) + m_root->bp_set_parent(parent, ndx_in_parent); + } + + void create(); + void destroy(); + void verify() const + { + m_root->verify(); + } + +protected: + template + struct LeafTypeTrait { + using type = typename ColumnTypeTraits::cluster_leaf_type; + }; + + friend class BPlusTreeInner; + friend class BPlusTreeLeaf; + + std::unique_ptr m_root; + Allocator& m_alloc; + ArrayParent* m_parent = nullptr; + size_t m_ndx_in_parent = 0; + size_t m_size = 0; + size_t m_cached_leaf_begin; + size_t m_cached_leaf_end; + + void set_leaf_bounds(size_t b, size_t e) + { + m_cached_leaf_begin = b; + m_cached_leaf_end = e; + } + + void invalidate_leaf_cache() + { + m_cached_leaf_begin = size_t(-1); + m_cached_leaf_end = size_t(-1); + } + + void adjust_leaf_bounds(int incr) + { + m_cached_leaf_end += incr; + } + + void bptree_insert(size_t n, BPlusTreeNode::InsertFunc func); + void bptree_erase(size_t n, BPlusTreeNode::EraseFunc func); + + // Create an un-attached leaf node + virtual std::unique_ptr create_leaf_node() = 0; + // Create a leaf node and initialize it with 'ref' + virtual std::unique_ptr init_leaf_node(ref_type ref) = 0; + + // Initialize the leaf cache with 'mem' + virtual BPlusTreeLeaf* cache_leaf(MemRef mem) = 0; + virtual void replace_root(std::unique_ptr new_root); + std::unique_ptr create_root_from_ref(ref_type ref); +}; + +template <> +struct BPlusTreeBase::LeafTypeTrait { + using type = ArrayKeyNonNullable; +}; + +/*****************************************************************************/ +/* BPlusTree */ +/* Actual implementation of the BPlusTree to hold elements of type T. */ +/*****************************************************************************/ +template +class BPlusTree : public BPlusTreeBase { +public: + using LeafArray = typename LeafTypeTrait::type; + + /** + * Actual class for the leaves. Maps the abstract interface defined + * in BPlusTreeNode onto the specific array class + **/ + class LeafNode : public BPlusTreeLeaf, public LeafArray { + public: + LeafNode(BPlusTreeBase* tree) + : BPlusTreeLeaf(tree) + , LeafArray(tree->get_alloc()) + { + } + + void init_from_ref(ref_type ref) noexcept override + { + LeafArray::init_from_ref(ref); + } + + ref_type get_ref() const override + { + return LeafArray::get_ref(); + } + + void bp_set_parent(realm::ArrayParent* p, size_t n) override + { + LeafArray::set_parent(p, n); + } + + void update_parent() override + { + LeafArray::update_parent(); + } + + size_t get_node_size() const override + { + return LeafArray::size(); + } + + size_t get_tree_size() const override + { + return LeafArray::size(); + } + + void move(BPlusTreeNode* new_node, size_t ndx, int64_t) override + { + LeafNode* dst(static_cast(new_node)); + LeafArray::move(*dst, ndx); + } + void verify() const override + { + LeafArray::verify(); + } + }; + + BPlusTree(Allocator& alloc) + : BPlusTreeBase(alloc) + , m_leaf_cache(this) + { + } + + BPlusTree(const BPlusTree& other) + : BPlusTree(other.get_alloc()) + { + *this = other; + } + + BPlusTree(BPlusTree&& other) noexcept + : BPlusTree(other.get_alloc()) + { + *this = std::move(other); + } + + /********************* Assignment ********************/ + + BPlusTree& operator=(const BPlusTree& rhs) + { + this->BPlusTreeBase::operator=(rhs); + return *this; + } + + BPlusTree& operator=(BPlusTree&& rhs) noexcept + { + this->BPlusTreeBase::operator=(std::move(rhs)); + return *this; + } + + /************ Tree manipulation functions ************/ + + static T default_value(bool nullable = false) + { + return LeafArray::default_value(nullable); + } + + void add(T value) + { + insert(npos, value); + } + + void insert(size_t n, T value) + { + auto func = [value](BPlusTreeNode* node, size_t ndx) { + LeafNode* leaf = static_cast(node); + leaf->LeafArray::insert(ndx, value); + return leaf->size(); + }; + + bptree_insert(n, func); + m_size++; + } + + T get(size_t n) const + { + if (m_cached_leaf_begin <= n && n < m_cached_leaf_end) { + return m_leaf_cache.get(n - m_cached_leaf_begin); + } + else { + T value; + + auto func = [&value](BPlusTreeNode* node, size_t ndx) { + LeafNode* leaf = static_cast(node); + value = leaf->get(ndx); + }; + + m_root->bptree_access(n, func); + + return value; + } + } + + std::vector get_all() const + { + std::vector all_values; + all_values.reserve(m_size); + + auto func = [&all_values](BPlusTreeNode* node, size_t) { + LeafNode* leaf = static_cast(node); + size_t sz = leaf->size(); + for (size_t i = 0; i < sz; i++) { + all_values.push_back(leaf->get(i)); + } + return false; + }; + + m_root->bptree_traverse(func); + + return all_values; + } + + void set(size_t n, T value) + { + auto func = [value](BPlusTreeNode* node, size_t ndx) { + LeafNode* leaf = static_cast(node); + leaf->set(ndx, value); + }; + + m_root->bptree_access(n, func); + } + + void swap(size_t ndx1, size_t ndx2) + { + if constexpr (std::is_same_v || std::is_same_v) { + struct SwapBuffer { + std::string val; + bool n; + SwapBuffer(T v) + : val(v.data(), v.size()) + , n(v.is_null()) + { + } + T get() + { + return n ? T() : T(val); + } + }; + SwapBuffer tmp1{get(ndx1)}; + SwapBuffer tmp2{get(ndx2)}; + set(ndx1, tmp2.get()); + set(ndx2, tmp1.get()); + } + else { + T tmp = get(ndx1); + set(ndx1, get(ndx2)); + set(ndx2, tmp); + } + } + + void erase(size_t n) + { + auto func = [](BPlusTreeNode* node, size_t ndx) { + LeafNode* leaf = static_cast(node); + leaf->LeafArray::erase(ndx); + return leaf->size(); + }; + + bptree_erase(n, func); + m_size--; + } + + void clear() + { + if (m_root->is_leaf()) { + LeafNode* leaf = static_cast(m_root.get()); + leaf->clear(); + } + else { + destroy(); + create(); + if (m_parent) { + m_parent->update_child_ref(m_ndx_in_parent, get_ref()); + } + } + m_size = 0; + } + + void traverse(BPlusTreeNode::TraverseFunc func) const + { + if (m_root) { + m_root->bptree_traverse(func); + } + } + + size_t find_first(T value) const noexcept + { + size_t result = realm::npos; + + auto func = [&result, value](BPlusTreeNode* node, size_t offset) { + LeafNode* leaf = static_cast(node); + size_t sz = leaf->size(); + auto i = leaf->find_first(value, 0, sz); + if (i < sz) { + result = i + offset; + return true; + } + return false; + }; + + m_root->bptree_traverse(func); + + return result; + } + + template + void find_all(T value, Func&& callback) const noexcept + { + auto func = [&callback, value](BPlusTreeNode* node, size_t offset) { + LeafNode* leaf = static_cast(node); + size_t i = -1, sz = leaf->size(); + while ((i = leaf->find_first(value, i + 1, sz)) < sz) { + callback(i + offset); + } + return false; + }; + + m_root->bptree_traverse(func); + } + + void dump_values(std::ostream& o, int level) const + { + std::string indent(" ", level * 2); + + auto func = [&o, indent](BPlusTreeNode* node, size_t) { + LeafNode* leaf = static_cast(node); + size_t sz = leaf->size(); + for (size_t i = 0; i < sz; i++) { + o << indent << leaf->get(i) << std::endl; + } + return false; + }; + + m_root->bptree_traverse(func); + } + +protected: + LeafNode m_leaf_cache; + + /******** Implementation of abstract interface *******/ + + std::unique_ptr create_leaf_node() override + { + std::unique_ptr leaf = std::make_unique(this); + static_cast(leaf.get())->create(); + return leaf; + } + std::unique_ptr init_leaf_node(ref_type ref) override + { + std::unique_ptr leaf = std::make_unique(this); + leaf->init_from_ref(ref); + return leaf; + } + BPlusTreeLeaf* cache_leaf(MemRef mem) override + { + m_leaf_cache.init_from_mem(mem); + return &m_leaf_cache; + } + void replace_root(std::unique_ptr new_root) override + { + // Only copy context flag over in a linklist. + // The flag is in use in other list types + if constexpr (std::is_same_v) { + auto cf = m_root ? m_root->get_context_flag() : false; + BPlusTreeBase::replace_root(std::move(new_root)); + m_root->set_context_flag(cf); + } + else { + BPlusTreeBase::replace_root(std::move(new_root)); + } + } + + template + friend R bptree_sum(const BPlusTree& tree); +}; + +template +inline bool bptree_aggregate_not_null(T) +{ + return true; +} +template +inline R bptree_aggregate_value(T val) +{ + return val; +} +template +inline bool bptree_aggregate_not_null(util::Optional val) +{ + return !!val; +} +template <> +inline bool bptree_aggregate_not_null(Timestamp val) +{ + return !val.is_null(); +} +inline bool bptree_aggregate_not_null(StringData val) +{ + return !val.is_null(); +} +inline bool bptree_aggregate_not_null(BinaryData val) +{ + return !val.is_null(); +} +template <> +inline bool bptree_aggregate_not_null(float val) +{ + return !null::is_null_float(val); +} +template <> +inline bool bptree_aggregate_not_null(double val) +{ + return !null::is_null_float(val); +} +template <> +inline bool bptree_aggregate_not_null(Decimal128 val) +{ + return !val.is_null(); +} +template +inline T bptree_aggregate_value(util::Optional val) +{ + return *val; +} + +template +ColumnSumType bptree_sum(const BPlusTree& tree, size_t* return_cnt = nullptr) +{ + using ResultType = typename AggregateResultType::result_type; + ResultType result{}; + size_t cnt = 0; + + auto func = [&result, &cnt](BPlusTreeNode* node, size_t) { + auto leaf = static_cast::LeafNode*>(node); + size_t sz = leaf->size(); + for (size_t i = 0; i < sz; i++) { + auto val = leaf->get(i); + if (bptree_aggregate_not_null(val)) { + result += bptree_aggregate_value(val); + cnt++; + } + } + return false; + }; + + tree.traverse(func); + + if (return_cnt) + *return_cnt = cnt; + + return result; +} + +template +ColumnMinMaxType bptree_maximum(const BPlusTree& tree, size_t* return_ndx = nullptr) +{ + using ResultType = typename AggregateResultType::result_type; + ResultType max = std::numeric_limits::lowest(); + if (tree.size() == 0) { + return max; + } + + auto func = [&max, return_ndx](BPlusTreeNode* node, size_t offset) { + auto leaf = static_cast::LeafNode*>(node); + size_t sz = leaf->size(); + for (size_t i = 0; i < sz; i++) { + auto val_or_null = leaf->get(i); + if (bptree_aggregate_not_null(val_or_null)) { + auto val = bptree_aggregate_value(val_or_null); + if (val > max) { + max = val; + if (return_ndx) { + *return_ndx = i + offset; + } + } + } + } + return false; + }; + + tree.traverse(func); + + return max; +} + +template +ColumnMinMaxType bptree_minimum(const BPlusTree& tree, size_t* return_ndx = nullptr) +{ + using ResultType = typename AggregateResultType::result_type; + ResultType min = std::numeric_limits::max(); + if (tree.size() == 0) { + return min; + } + + auto func = [&min, return_ndx](BPlusTreeNode* node, size_t offset) { + auto leaf = static_cast::LeafNode*>(node); + size_t sz = leaf->size(); + for (size_t i = 0; i < sz; i++) { + auto val_or_null = leaf->get(i); + if (bptree_aggregate_not_null(val_or_null)) { + auto val = bptree_aggregate_value(val_or_null); + if (val < min) { + min = val; + if (return_ndx) { + *return_ndx = i + offset; + } + } + } + } + return false; + }; + + tree.traverse(func); + + return min; +} + +template +ColumnAverageType bptree_average(const BPlusTree& tree, size_t* return_cnt = nullptr) +{ + size_t cnt; + auto sum = bptree_sum(tree, &cnt); + ColumnAverageType avg{}; + if (cnt != 0) + avg = ColumnAverageType(sum) / cnt; + if (return_cnt) + *return_cnt = cnt; + return avg; +} +} + +#endif /* REALM_BPLUSTREE_HPP */ diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/chunked_binary.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/chunked_binary.hpp new file mode 100644 index 0000000..7c48c08 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/chunked_binary.hpp @@ -0,0 +1,111 @@ +/************************************************************************* + * + * Copyright 2019 Realm Inc. + * + * 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 REALM_NOINST_CHUNKED_BINARY_HPP +#define REALM_NOINST_CHUNKED_BINARY_HPP + +#include +#include +#include + +#include +#include + + +namespace realm { + +/// ChunkedBinaryData manages a vector of BinaryData. It is used to facilitate +/// extracting large binaries from binary columns and tables. +class ChunkedBinaryData { +public: + ChunkedBinaryData() {} + + ChunkedBinaryData(const BinaryData& bd) + : m_begin{bd} + { + } + + ChunkedBinaryData(const BinaryIterator& bd) + : m_begin{bd} + { + } + + ChunkedBinaryData(const BinaryColumn& col, size_t index) + : m_begin{&col, index} + { + } + + /// size() returns the number of bytes in the chunked binary. + /// FIXME: This operation is O(n). + size_t size() const noexcept; + + /// is_null returns true if the chunked binary has zero chunks or if + /// the first chunk points to the nullptr. + bool is_null() const; + + /// FIXME: O(n) + char operator[](size_t index) const; + + std::string hex_dump(const char* separator = " ", int min_digits = -1) const; + + void write_to(util::ResettableExpandableBufferOutputStream& out) const; + + /// copy_to() copies the chunked binary data to \a buffer of size + /// \a buffer_size starting at \a offset in the ChunkedBinary. + /// copy_to() copies until the end of \a buffer or the end of + /// the ChunkedBinary whichever comes first. + /// copy_to() returns the number of copied bytes. + size_t copy_to(char* buffer, size_t buffer_size, size_t offset) const; + + /// copy_to() allocates a buffer of size() in \a dest and + /// copies the chunked binary data to \a dest. + size_t copy_to(std::unique_ptr& dest) const; + + /// get_first_chunk() is used in situations + /// where it is known that there is exactly one + /// chunk. This is the case if the ChunkedBinary + /// has been constructed from BinaryData. + BinaryData get_first_chunk() const; + +private: + BinaryIterator m_begin; + friend class ChunkedBinaryInputStream; +}; + +class ChunkedBinaryInputStream : public _impl::NoCopyInputStream { +public: + explicit ChunkedBinaryInputStream(const ChunkedBinaryData& chunks) + : m_it(chunks.m_begin) + { + } + + bool next_block(const char*& begin, const char*& end) override + { + BinaryData block = m_it.get_next(); + begin = block.data(); + end = begin + block.size(); + return begin != end; + } + +private: + BinaryIterator m_it; +}; + +} // namespace realm + +#endif // REALM_NOINST_CHUNKED_BINARY_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/cluster.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/cluster.hpp new file mode 100644 index 0000000..3502bcc --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/cluster.hpp @@ -0,0 +1,292 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_CLUSTER_HPP +#define REALM_CLUSTER_HPP + +#include +#include +#include +#include +#include +#include + +namespace realm { + +class Spec; +class Table; +class ConstObj; +class Cluster; +class ClusterNodeInner; +class ClusterTree; +class ColumnAttrMask; +class CascadeState; + +struct FieldValue { + FieldValue(ColKey k, Mixed val) + : col_key(k) + , value(val) + { + } + ColKey col_key; + Mixed value; +}; + +using FieldValues = std::vector; + +class ClusterNode : public Array { +public: + // This structure is used to bring information back to the upper nodes when + // inserting new objects or finding existing ones. + struct State { + int64_t split_key; // When a node is split, this variable holds the value of the + // first key in the new node. (Relative to the key offset) + MemRef mem; // MemRef to the Cluster holding the new/found object + size_t index; // The index within the Cluster at which the object is stored. + }; + + struct IteratorState { + IteratorState(Cluster& leaf) + : m_current_leaf(leaf) + { + } + IteratorState(const IteratorState&); + void clear(); + void init(const ConstObj&); + + Cluster& m_current_leaf; + int64_t m_key_offset = 0; + size_t m_current_index = 0; + }; + + ClusterNode(uint64_t offset, Allocator& allocator, const ClusterTree& tree_top) + : Array(allocator) + , m_tree_top(tree_top) + , m_keys(allocator) + , m_offset(offset) + { + m_keys.set_parent(this, 0); + } + virtual ~ClusterNode() + { + } + void init_from_parent() + { + ref_type ref = get_ref_from_parent(); + char* header = m_alloc.translate(ref); + init(MemRef(header, ref, m_alloc)); + } + int64_t get_key_value(size_t ndx) const + { + return m_keys.get(ndx); + } + + virtual bool update_from_parent(size_t old_baseline) noexcept = 0; + virtual bool is_leaf() const = 0; + virtual int get_sub_tree_depth() const = 0; + virtual size_t node_size() const = 0; + /// Number of elements in this subtree + virtual size_t get_tree_size() const = 0; + /// Last key in this subtree + virtual int64_t get_last_key_value() const = 0; + virtual void ensure_general_form() = 0; + + /// Initialize node from 'mem' + virtual void init(MemRef mem) = 0; + /// Descend the tree from the root and copy-on-write the leaf + /// This will update all parents accordingly + virtual MemRef ensure_writeable(ObjKey k) = 0; + + /// Init and potentially Insert a column + virtual void insert_column(ColKey col) = 0; + /// Clear and potentially Remove a column + virtual void remove_column(ColKey col) = 0; + /// Return number of columns created. To be used by upgrade logic + virtual size_t nb_columns() const + { + return realm::npos; + } + /// Create a new object identified by 'key' and update 'state' accordingly + /// Return reference to new node created (if any) + virtual ref_type insert(ObjKey k, const FieldValues& init_values, State& state) = 0; + /// Locate object identified by 'key' and update 'state' accordingly + void get(ObjKey key, State& state) const; + /// Locate object identified by 'key' and update 'state' accordingly + /// Returns `false` if the object doesn't not exist. + virtual bool try_get(ObjKey key, State& state) const = 0; + /// Locate object identified by 'ndx' and update 'state' accordingly + virtual ObjKey get(size_t ndx, State& state) const = 0; + /// Return the index at which key is stored + virtual size_t get_ndx(ObjKey key, size_t ndx) const = 0; + + /// Erase element identified by 'key' + virtual size_t erase(ObjKey key, CascadeState& state) = 0; + + /// Nullify links pointing to element identified by 'key' + virtual void nullify_incoming_links(ObjKey key, CascadeState& state) = 0; + + /// Move elements from position 'ndx' to 'new_node'. The new node is supposed + /// to be a sibling positioned right after this one. All key values must + /// be subtracted 'key_adj' + virtual void move(size_t ndx, ClusterNode* new_leaf, int64_t key_adj) = 0; + + virtual void dump_objects(int64_t key_offset, std::string lead) const = 0; + + ObjKey get_real_key(size_t ndx) const + { + return ObjKey(get_key_value(ndx) + m_offset); + } + const ClusterKeyArray* get_key_array() const + { + return &m_keys; + } + void set_offset(uint64_t offs) + { + m_offset = offs; + } + uint64_t get_offset() const + { + return m_offset; + } + +protected: + const ClusterTree& m_tree_top; + ClusterKeyArray m_keys; + uint64_t m_offset; +}; + +class Cluster : public ClusterNode { +public: + Cluster(uint64_t offset, Allocator& allocator, const ClusterTree& tree_top) + : ClusterNode(offset, allocator, tree_top) + { + } + ~Cluster() override; + + void create(size_t nb_leaf_columns); // Note: leaf columns - may include holes + void init(MemRef mem) override; + bool update_from_parent(size_t old_baseline) noexcept override; + bool is_writeable() const + { + return !Array::is_read_only(); + } + MemRef ensure_writeable(ObjKey k) override; + + bool is_leaf() const override + { + return true; + } + int get_sub_tree_depth() const override + { + return 0; + } + static size_t node_size_from_header(Allocator& alloc, const char* header); + size_t node_size() const override + { + if (!is_attached()) { + return 0; + } + return m_keys.is_attached() ? m_keys.size() : get_size_in_compact_form(); + } + size_t get_tree_size() const override + { + return node_size(); + } + int64_t get_last_key_value() const override + { + auto sz = node_size(); + return sz ? get_key_value(sz - 1) : -1; + } + size_t lower_bound_key(ObjKey key) const + { + if (m_keys.is_attached()) { + return m_keys.lower_bound(uint64_t(key.value)); + } + else { + size_t sz = size_t(Array::get(0)) >> 1; + if (key.value < 0) + return 0; + if (size_t(key.value) > sz) + return sz; + } + return size_t(key.value); + } + + void adjust_keys(int64_t offset) + { + ensure_general_form(); + m_keys.adjust(0, m_keys.size(), offset); + } + + const Table* get_owning_table() const; + ColKey get_col_key(size_t ndx_in_parent) const; + + void ensure_general_form() override; + void insert_column(ColKey col) override; // Does not move columns! + void remove_column(ColKey col) override; // Does not move columns - may leave a 'hole' + size_t nb_columns() const override + { + return size() - s_first_col_index; + } + ref_type insert(ObjKey k, const FieldValues& init_values, State& state) override; + bool try_get(ObjKey k, State& state) const override; + ObjKey get(size_t, State& state) const override; + size_t get_ndx(ObjKey key, size_t ndx) const override; + size_t erase(ObjKey k, CascadeState& state) override; + void nullify_incoming_links(ObjKey key, CascadeState& state) override; + void upgrade_string_to_enum(ColKey col, ArrayString& keys); + + void init_leaf(ColKey col, ArrayPayload* leaf) const; + void add_leaf(ColKey col, ref_type ref); + + void verify() const; + void dump_objects(int64_t key_offset, std::string lead) const override; + +private: + static constexpr size_t s_key_ref_or_size_index = 0; + static constexpr size_t s_first_col_index = 1; + + size_t get_size_in_compact_form() const + { + return size_t(Array::get(s_key_ref_or_size_index)) >> 1; // Size is stored as tagged value + } + friend class ClusterTree; + void insert_row(size_t ndx, ObjKey k, const FieldValues& init_values); + void move(size_t ndx, ClusterNode* new_node, int64_t key_adj) override; + template + void do_create(ColKey col); + template + void do_insert_column(ColKey col, bool nullable); + template + void do_insert_row(size_t ndx, ColKey col, Mixed init_val, bool nullable); + template + void do_move(size_t ndx, ColKey col, Cluster* to); + template + void do_erase(size_t ndx, ColKey col); + void remove_backlinks(ObjKey origin_key, ColKey col, const std::vector& keys, CascadeState& state) const; + void do_erase_key(size_t ndx, ColKey col, CascadeState& state); + void do_insert_key(size_t ndx, ColKey col, Mixed init_val, ObjKey origin_key); + template + void set_spec(T&, ColKey::Idx) const; + template + void verify(ref_type ref, size_t index, util::Optional& sz) const; +}; + +} + +#endif /* SRC_REALM_CLUSTER_HPP_ */ diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/cluster_tree.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/cluster_tree.hpp new file mode 100644 index 0000000..9e164d8 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/cluster_tree.hpp @@ -0,0 +1,282 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_CLUSTER_TREE_HPP +#define REALM_CLUSTER_TREE_HPP + +#include +#include + +namespace realm { + +class ClusterTree { +public: + class ConstIterator; + class Iterator; + using TraverseFunction = util::FunctionRef; + using UpdateFunction = util::FunctionRef; + + ClusterTree(Table* owner, Allocator& alloc, size_t top_position_for_cluster_tree); + static MemRef create_empty_cluster(Allocator& alloc); + + ClusterTree(ClusterTree&&) = default; + + // Disable copying, this is not allowed. + ClusterTree& operator=(const ClusterTree&) = delete; + ClusterTree(const ClusterTree&) = delete; + + bool is_attached() const + { + return m_root->is_attached(); + } + Allocator& get_alloc() const + { + return m_alloc; + } + const Table* get_owner() const + { + return m_owner; + } + TableRef get_table_ref() const; + const Spec& get_spec() const; + + void init_from_ref(ref_type ref); + void init_from_parent(); + bool update_from_parent(size_t old_baseline) noexcept; + + size_t size() const noexcept + { + return m_size; + } + void clear(CascadeState&); + void destroy() + { + m_root->destroy_deep(); + } + void nullify_links(ObjKey, CascadeState&); + bool is_empty() const noexcept + { + return size() == 0; + } + int64_t get_last_key_value() const + { + return m_root->get_last_key_value(); + } + MemRef ensure_writeable(ObjKey k) + { + return m_root->ensure_writeable(k); + } + Array& get_fields_accessor(Array& fallback, MemRef mem) const + { + if (m_root->is_leaf()) { + return *m_root; + } + fallback.init_from_mem(mem); + return fallback; + } + + uint64_t bump_content_version() + { + return m_alloc.bump_content_version(); + } + void bump_storage_version() + { + m_alloc.bump_storage_version(); + } + uint64_t get_content_version() const + { + return m_alloc.get_content_version(); + } + uint64_t get_instance_version() const + { + return m_alloc.get_instance_version(); + } + uint64_t get_storage_version(uint64_t inst_ver) const + { + return m_alloc.get_storage_version(inst_ver); + } + void insert_column(ColKey col) + { + m_root->insert_column(col); + } + void remove_column(ColKey col) + { + m_root->remove_column(col); + } + + // Insert entry for object, but do not create and return the object accessor + void insert_fast(ObjKey k, const FieldValues& init_values, ClusterNode::State& state); + // Create and return object + Obj insert(ObjKey k, const FieldValues&); + // Delete object with given key + void erase(ObjKey k, CascadeState& state); + // Check if an object with given key exists + bool is_valid(ObjKey k) const; + // Lookup and return read-only object + ConstObj get(ObjKey k) const; + // Lookup and return object + Obj get(ObjKey k); + // Lookup ContsObj by index + ConstObj get(size_t ndx) const; + // Lookup Obj by index + Obj get(size_t ndx); + // Get logical index of object identified by k + size_t get_ndx(ObjKey k) const; + // Find the leaf containing the requested object + bool get_leaf(ObjKey key, ClusterNode::IteratorState& state) const noexcept; + // Visit all leaves and call the supplied function. Stop when function returns true. + // Not allowed to modify the tree + bool traverse(TraverseFunction func) const; + // Visit all leaves and call the supplied function. The function can modify the leaf. + void update(UpdateFunction func); + + void enumerate_string_column(ColKey col_key); + void dump_objects() + { + m_root->dump_objects(0, ""); + } + void verify() const; + +private: + friend class ConstObj; + friend class Obj; + friend class Cluster; + friend class ClusterNodeInner; + Table* m_owner; + Allocator& m_alloc; + std::unique_ptr m_root; + size_t m_top_position_for_cluster_tree; + size_t m_size = 0; + + void replace_root(std::unique_ptr leaf); + + std::unique_ptr create_root_from_mem(Allocator& alloc, MemRef mem); + std::unique_ptr create_root_from_ref(Allocator& alloc, ref_type ref) + { + return create_root_from_mem(alloc, MemRef{alloc.translate(ref), ref, alloc}); + } + std::unique_ptr get_node(ref_type ref) const; + + size_t get_column_index(StringData col_name) const; + void remove_all_links(CascadeState&); +}; + +class ClusterTree::ConstIterator { +public: + typedef std::output_iterator_tag iterator_category; + typedef const Obj value_type; + typedef ptrdiff_t difference_type; + typedef const Obj* pointer; + typedef const Obj& reference; + + ConstIterator(const ClusterTree& t, size_t ndx); + ConstIterator(const ConstIterator& other); + + ConstIterator& operator=(const ConstIterator& other) + { + REALM_ASSERT(&m_tree == &other.m_tree); + m_position = other.m_position; + m_key = other.m_key; + m_leaf_invalid = true; + + return *this; + } + + // If the object pointed to by the iterator is deleted, you will get an exception if + // you try to dereference the iterator before advancing it. + + // Random access relative to iterator position. + reference operator[](size_t n); + reference operator*() const + { + return *operator->(); + } + pointer operator->() const; + + // Advance the iterator to the next object in the table. This also holds if the object + // pointed to is deleted. That is - you will get the same result of advancing no matter + // if the previous object is deleted or not. + ConstIterator& operator++(); + + ConstIterator& operator+=(ptrdiff_t adj); + + ConstIterator operator+(ptrdiff_t adj) + { + return ConstIterator(m_tree, get_position() + adj); + } + bool operator==(const ConstIterator& rhs) const + { + return m_key == rhs.m_key; + } + bool operator!=(const ConstIterator& rhs) const + { + return m_key != rhs.m_key; + } + +protected: + const ClusterTree& m_tree; + mutable uint64_t m_storage_version = uint64_t(-1); + mutable Cluster m_leaf; + mutable ClusterNode::IteratorState m_state; + mutable uint64_t m_instance_version = uint64_t(-1); + ObjKey m_key; + mutable bool m_leaf_invalid; + mutable size_t m_position; + mutable size_t m_leaf_start_pos = size_t(-1); + mutable Obj m_obj; + + ObjKey load_leaf(ObjKey key) const; + size_t get_position(); +}; + +class ClusterTree::Iterator : public ClusterTree::ConstIterator { +public: + typedef std::forward_iterator_tag iterator_category; + typedef Obj value_type; + typedef Obj* pointer; + typedef Obj& reference; + + Iterator(const ClusterTree& t, size_t ndx) + : ConstIterator(t, ndx) + { + } + + reference operator*() const + { + return *operator->(); + } + pointer operator->() const + { + return const_cast(ConstIterator::operator->()); + } + Iterator& operator++() + { + return static_cast(ConstIterator::operator++()); + } + Iterator& operator+=(ptrdiff_t adj) + { + return static_cast(ConstIterator::operator+=(adj)); + } + Iterator operator+(ptrdiff_t adj) + { + return Iterator(m_tree, get_position() + adj); + } +}; +} + +#endif /* REALM_CLUSTER_TREE_HPP */ diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/column_binary.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/column_binary.hpp new file mode 100644 index 0000000..254f721 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/column_binary.hpp @@ -0,0 +1,78 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_COLUMN_BINARY_HPP +#define REALM_COLUMN_BINARY_HPP + +#include +#include +#include +#include + +namespace realm { + +class BinaryColumn : public BPlusTree { +public: + using BPlusTree::BPlusTree; + BinaryData get_at(size_t ndx, size_t& pos) const noexcept; +}; + +class BinaryIterator { +public: + BinaryIterator() + { + } + // TODO: When WriteLogCollector is removed, there is no need for this + BinaryIterator(BinaryData binary) + : m_binary(binary) + { + } + + BinaryIterator(const BinaryColumn* col, size_t ndx) + : m_binary_col(col) + , m_ndx(ndx) + { + } + + BinaryData get_next() noexcept + { + if (!end_of_data) { + if (m_binary_col) { + BinaryData ret = m_binary_col->get_at(m_ndx, m_pos); + end_of_data = (m_pos == 0); + return ret; + } + else if (!m_binary.is_null()) { + end_of_data = true; + return m_binary; + } + } + return {}; + } + +private: + bool end_of_data = false; + const BinaryColumn* m_binary_col = nullptr; + size_t m_ndx = 0; + size_t m_pos = 0; + BinaryData m_binary; +}; + +} // namespace realm + +#endif // REALM_COLUMN_BINARY_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/column_fwd.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/column_fwd.hpp new file mode 100644 index 0000000..bc5f583 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/column_fwd.hpp @@ -0,0 +1,44 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_COLUMN_FWD_HPP +#define REALM_COLUMN_FWD_HPP + +#include + +namespace realm { + +class IntegerColumn; +class IntegerColumnIterator; + +// Templated classes +template +class BPlusTree; + +namespace util { +template +class Optional; +} + +// Shortcuts, aka typedefs. +using DoubleColumn = BPlusTree; +using FloatColumn = BPlusTree; + +} // namespace realm + +#endif // REALM_COLUMN_FWD_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/column_integer.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/column_integer.hpp new file mode 100644 index 0000000..593c106 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/column_integer.hpp @@ -0,0 +1,188 @@ +/************************************************************************* + * + * Copyright 2018 Realm Inc. + * + * 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 REALM_COLUMN_INTEGER_HPP +#define REALM_COLUMN_INTEGER_HPP + +#include +#include +#include + +namespace realm { + +class IntegerColumn; + +class IntegerColumnIterator { +public: + typedef std::random_access_iterator_tag iterator_category; + typedef int64_t value_type; + typedef ptrdiff_t difference_type; + typedef const value_type* pointer; + typedef const value_type& reference; + + IntegerColumnIterator(const IntegerColumn* tree, size_t pos) + : m_tree(tree) + , m_pos(pos) + { + } + + size_t get_position() const + { + return m_pos; + } + + int64_t operator->() const; + int64_t operator*() const; + int64_t operator[](size_t ndx) const; + + IntegerColumnIterator& operator++() + { + m_pos++; + return *this; + } + + IntegerColumnIterator operator++(int) + { + IntegerColumnIterator tmp(*this); + operator++(); + return tmp; + } + + IntegerColumnIterator& operator--() + { + m_pos--; + return *this; + } + + IntegerColumnIterator& operator+=(ptrdiff_t adj) + { + m_pos += adj; + return *this; + } + + IntegerColumnIterator& operator-=(ptrdiff_t adj) + { + m_pos -= adj; + return *this; + } + + IntegerColumnIterator operator+(ptrdiff_t adj) + { + return {m_tree, m_pos + adj}; + } + + IntegerColumnIterator operator-(ptrdiff_t adj) + { + return {m_tree, m_pos - adj}; + } + + IntegerColumnIterator operator--(int) + { + IntegerColumnIterator tmp(*this); + operator--(); + return tmp; + } + + ptrdiff_t operator-(const IntegerColumnIterator& rhs) + { + return m_pos - rhs.m_pos; + } + + bool operator!=(const IntegerColumnIterator& rhs) const + { + return m_pos != rhs.m_pos; + } + + bool operator==(const IntegerColumnIterator& rhs) const + { + return m_pos == rhs.m_pos; + } + + bool operator>(const IntegerColumnIterator& rhs) const + { + return m_pos > rhs.m_pos; + } + + bool operator<(const IntegerColumnIterator& rhs) const + { + return m_pos < rhs.m_pos; + } + + bool operator>=(const IntegerColumnIterator& rhs) const + { + return m_pos >= rhs.m_pos; + } + + bool operator<=(const IntegerColumnIterator& rhs) const + { + return m_pos <= rhs.m_pos; + } + +private: + const IntegerColumn* m_tree; + size_t m_pos; +}; + +class IntegerColumn : public BPlusTree { +public: + using const_iterator = IntegerColumnIterator; + + IntegerColumn(Allocator& alloc, ref_type ref = 0) + : BPlusTree(alloc) + { + if (ref != 0) + init_from_ref(ref); + } + + int64_t back() + { + return get(size() - 1); + } + IntegerColumnIterator cbegin() const + { + return IntegerColumnIterator(this, 0); + } + IntegerColumnIterator cend() const + { + return IntegerColumnIterator(this, size()); + } +}; + +inline int64_t IntegerColumnIterator::operator->() const +{ + return m_tree->get(m_pos); +} + +inline int64_t IntegerColumnIterator::operator*() const +{ + return m_tree->get(m_pos); +} + +inline int64_t IntegerColumnIterator::operator[](size_t ndx) const +{ + return m_tree->get(m_pos + ndx); +} + +inline std::ostream& operator<<(std::ostream& out, const IntegerColumnIterator& it) +{ + out << "IntegerColumnIterator at index: " << it.get_position(); + return out; +} +} + +#endif /* REALM_COLUMN_INTEGER_HPP */ diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/column_type.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/column_type.hpp new file mode 100644 index 0000000..5c0d2e0 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/column_type.hpp @@ -0,0 +1,112 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_COLUMN_TYPE_HPP +#define REALM_COLUMN_TYPE_HPP + +namespace realm { + + +// Note: Enumeration value assignments must be kept in sync with +// . +enum ColumnType { + // Column types + col_type_Int = 0, + col_type_Bool = 1, + col_type_String = 2, + col_type_OldStringEnum = 3, // double refs + col_type_Binary = 4, + col_type_OldTable = 5, + col_type_OldMixed = 6, + col_type_OldDateTime = 7, + col_type_Timestamp = 8, + col_type_Float = 9, + col_type_Double = 10, + col_type_Decimal = 11, + col_type_Link = 12, + col_type_LinkList = 13, + col_type_BackLink = 14, + col_type_ObjectId = 15 +}; + + +// Column attributes can be combined using bitwise or. +enum ColumnAttr { + col_attr_None = 0, + col_attr_Indexed = 1, + + /// Specifies that this column forms a unique constraint. It requires + /// `col_attr_Indexed`. + col_attr_Unique = 2, + + /// Reserved for future use. + col_attr_Reserved = 4, + + /// Specifies that the links of this column are strong, not weak. Applies + /// only to link columns (`type_Link` and `type_LinkList`). + col_attr_StrongLinks = 8, + + /// Specifies that elements in the column can be null. + col_attr_Nullable = 16, + + /// Each element is a list of values + col_attr_List = 32 +}; + +class ColumnAttrMask { +public: + ColumnAttrMask() + : m_value(0) + { + } + bool test(ColumnAttr prop) + { + return (m_value & prop) != 0; + } + void set(ColumnAttr prop) + { + m_value |= prop; + } + void reset(ColumnAttr prop) + { + m_value &= ~prop; + } + bool operator==(const ColumnAttrMask& other) const + { + return m_value == other.m_value; + } + bool operator!=(const ColumnAttrMask& other) const + { + return m_value != other.m_value; + } + +private: + friend class Spec; + friend struct ColKey; + friend class Table; + int m_value; + ColumnAttrMask(int64_t val) + : m_value(int(val)) + { + } +}; + + +} // namespace realm + +#endif // REALM_COLUMN_TYPE_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/column_type_traits.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/column_type_traits.hpp new file mode 100644 index 0000000..2ffc21b --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/column_type_traits.hpp @@ -0,0 +1,337 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_COLUMN_TYPE_TRAITS_HPP +#define REALM_COLUMN_TYPE_TRAITS_HPP + +#include +#include +#include +#include +#include + +namespace realm { + +struct ObjKey; +class Decimal128; +class ObjectId; +class Mixed; +class Timestamp; +class ArraySmallBlobs; +class ArrayString; +class ArrayStringShort; +class ArrayBinary; +class ArrayMixed; +class ArrayTimestamp; +class ArrayInteger; +class ArrayRef; +class ArrayIntNull; +class ArrayBool; +class ArrayBoolNull; +class ArrayKey; +class ArrayKeyNonNullable; +class ArrayDecimal128; +class ArrayObjectId; +class ArrayObjectIdNull; +template +class BasicArray; +template +class BasicArrayNull; +struct Link; +template +class Lst; +struct SizeOfList; + +template +struct ColumnTypeTraits; + +template +struct AggregateResultType { + using result_type = T; +}; + +template +struct AggregateResultType, action> { + using result_type = T; +}; + +template <> +struct AggregateResultType { + using result_type = double; +}; + +template <> +struct ColumnTypeTraits { + using leaf_type = ArrayInteger; + using cluster_leaf_type = ArrayInteger; + using sum_type = int64_t; + using minmax_type = int64_t; + using average_type = double; + static const DataType id = type_Int; + static const ColumnType column_id = col_type_Int; + static const ColumnType real_column_type = col_type_Int; +}; + +template <> +struct ColumnTypeTraits { + using cluster_leaf_type = ArrayRef; + static const DataType id = type_Int; + static const ColumnType column_id = col_type_Int; +}; + +template <> +struct ColumnTypeTraits> { + using leaf_type = ArrayIntNull; + using cluster_leaf_type = ArrayIntNull; + using sum_type = int64_t; + using minmax_type = int64_t; + using average_type = double; + static const DataType id = type_Int; + static const ColumnType column_id = col_type_Int; + static const ColumnType real_column_type = col_type_Int; +}; + +template <> +struct ColumnTypeTraits { + using cluster_leaf_type = ArrayBool; + static const DataType id = type_Bool; + static const ColumnType column_id = col_type_Bool; +}; + +template <> +struct ColumnTypeTraits> { + using cluster_leaf_type = ArrayBoolNull; + static const DataType id = type_Bool; + static const ColumnType column_id = col_type_Bool; +}; + +template <> +struct ColumnTypeTraits { + using cluster_leaf_type = ArrayKey; + static const DataType id = type_Link; + static const ColumnType column_id = col_type_Link; +}; + +template <> +struct ColumnTypeTraits { + using cluster_leaf_type = ArrayMixed; + static const DataType id = type_OldMixed; + static const ColumnType column_id = col_type_OldMixed; +}; + +template <> +struct ColumnTypeTraits { + static const ColumnType column_id = col_type_Link; +}; + +template <> +struct ColumnTypeTraits { + using cluster_leaf_type = BasicArray; + using sum_type = double; + using minmax_type = float; + using average_type = double; + static const DataType id = type_Float; + static const ColumnType column_id = col_type_Float; + static const ColumnType real_column_type = col_type_Float; +}; + +template <> +struct ColumnTypeTraits> { + using cluster_leaf_type = BasicArrayNull; + using sum_type = double; + using minmax_type = float; + using average_type = double; + static const DataType id = type_Float; + static const ColumnType column_id = col_type_Float; + static const ColumnType real_column_type = col_type_Float; +}; + +template <> +struct ColumnTypeTraits { + using cluster_leaf_type = BasicArray; + using sum_type = double; + using minmax_type = double; + using average_type = double; + static const DataType id = type_Double; + static const ColumnType column_id = col_type_Double; + static const ColumnType real_column_type = col_type_Double; +}; + +template <> +struct ColumnTypeTraits> { + using cluster_leaf_type = BasicArrayNull; + using sum_type = double; + using minmax_type = double; + using average_type = double; + static const DataType id = type_Double; + static const ColumnType column_id = col_type_Double; + static const ColumnType real_column_type = col_type_Double; +}; + +template <> +struct ColumnTypeTraits { + using cluster_leaf_type = ArrayTimestamp; + using minmax_type = Timestamp; + static const DataType id = type_Timestamp; + static const ColumnType column_id = col_type_Timestamp; +}; + +template <> +struct ColumnTypeTraits { + using cluster_leaf_type = ArrayObjectId; + static const DataType id = type_ObjectId; + static const ColumnType column_id = col_type_ObjectId; +}; + +template <> +struct ColumnTypeTraits> { + using cluster_leaf_type = ArrayObjectIdNull; + static const DataType id = type_ObjectId; + static const ColumnType column_id = col_type_ObjectId; +}; + +template <> +struct ColumnTypeTraits { + using cluster_leaf_type = ArrayString; + static const DataType id = type_String; + static const ColumnType column_id = col_type_String; +}; + +template <> +struct ColumnTypeTraits { + using leaf_type = ArraySmallBlobs; + using cluster_leaf_type = ArrayBinary; + static const DataType id = type_Binary; + static const ColumnType column_id = col_type_Binary; + static const ColumnType real_column_type = col_type_Binary; +}; + +template <> +struct ColumnTypeTraits { + using cluster_leaf_type = ArrayDecimal128; + using sum_type = Decimal128; + using minmax_type = Decimal128; + using average_type = Decimal128; + static const DataType id = type_Decimal; + static const ColumnType column_id = col_type_Decimal; +}; + +template <> +struct ColumnTypeTraits { + static const DataType id = type_Int; +}; + +template <> +struct ColumnTypeTraits { + static const DataType id = type_Int; +}; + +template <> +struct ColumnTypeTraits { + static const DataType id = DataType(-1); +}; + +template +struct ObjectTypeTraits { + constexpr static bool self_contained_null = + realm::is_any_v; +}; + +template +using ColumnClusterLeafType = typename ColumnTypeTraits::cluster_leaf_type; +template +using ColumnSumType = typename ColumnTypeTraits::sum_type; +template +using ColumnMinMaxType = typename ColumnTypeTraits::minmax_type; +template +using ColumnAverageType = typename ColumnTypeTraits::average_type; + +template +struct ColumnTypeTraits> { + static const ColumnType column_id = ColumnTypeTraits::column_id; +}; + +template +struct GetLeafType; +template <> +struct GetLeafType { + using type = ArrayInteger; +}; +template <> +struct GetLeafType { + using type = ArrayIntNull; +}; +template +struct GetLeafType { + // FIXME: Null definition + using type = BasicArray; +}; +template +struct GetLeafType { + // FIXME: Null definition + using type = BasicArray; +}; +template +struct GetLeafType { + // FIXME: Null definition + using type = ArrayTimestamp; +}; +template +struct GetLeafType { + // FIXME: Null definition + using type = ArrayDecimal128; +}; + +template +inline bool value_is_null(const T& val) +{ + return val.is_null(); +} +template +inline bool value_is_null(const util::Optional& val) +{ + return !val; +} +inline bool value_is_null(const int64_t&) +{ + return false; +} +inline bool value_is_null(const bool&) +{ + return false; +} +inline bool value_is_null(const ObjectId&) +{ + return false; +} +inline bool value_is_null(const float& val) +{ + return null::is_null_float(val); +} +inline bool value_is_null(const double& val) +{ + return null::is_null_float(val); +} +inline bool value_is_null(const ObjKey& val) +{ + return !val; +} + +} // namespace realm + +#endif // REALM_COLUMN_TYPE_TRAITS_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/data_type.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/data_type.hpp new file mode 100644 index 0000000..b0509b5 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/data_type.hpp @@ -0,0 +1,67 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_DATA_TYPE_HPP +#define REALM_DATA_TYPE_HPP + +#include + +namespace realm { + +class StringData; +class BinaryData; +class Timestamp; +class Decimal128; + +typedef int64_t Int; +typedef bool Bool; +typedef float Float; +typedef double Double; +typedef realm::StringData String; +typedef realm::BinaryData Binary; +typedef realm::Timestamp Timestamp; +typedef realm::Decimal128 Decimal; + + +// Note: Value assignments must be kept in sync with +// Note: Value assignments must be kept in sync with +// Note: Value assignments must be kept in sync with +// Note: Value assignments must be kept in sync with "com/realm/ColumnType.java" +// Note: Any change to this enum is a file-format breaking change. +enum DataType { + type_Int = 0, + type_Bool = 1, + type_String = 2, + type_Binary = 4, + type_OldTable = 5, + type_OldMixed = 6, + type_OldDateTime = 7, + type_Timestamp = 8, + type_Float = 9, + type_Double = 10, + type_Decimal = 11, + type_Link = 12, + type_LinkList = 13, + type_ObjectId = 15 +}; + +const char* get_data_type_name(DataType type) noexcept; + +} // namespace realm + +#endif // REALM_DATA_TYPE_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/db.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/db.hpp new file mode 100644 index 0000000..c4d4159 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/db.hpp @@ -0,0 +1,1013 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_GROUP_SHARED_HPP +#define REALM_GROUP_SHARED_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace realm { + +namespace _impl { +class WriteLogCollector; +} + +class Transaction; +using TransactionRef = std::shared_ptr; + +/// Thrown by DB::create() if the lock file is already open in another +/// process which can't share mutexes with this process +struct IncompatibleLockFile : std::runtime_error { + IncompatibleLockFile(const std::string& msg) + : std::runtime_error("Incompatible lock file. " + msg) + { + } +}; + +/// Thrown by DB::create() if the type of history +/// (Replication::HistoryType) in the opened Realm file is incompatible with the +/// mode in which the Realm file is opened. For example, if there is a mismatch +/// between the history type in the file, and the history type associated with +/// the replication plugin passed to DB::create(). +/// +/// This exception will also be thrown if the history schema version is lower +/// than required, and no migration is possible +/// (Replication::is_upgradable_history_schema()). +struct IncompatibleHistories : util::File::AccessError { + IncompatibleHistories(const std::string& msg, const std::string& path) + : util::File::AccessError("Incompatible histories. " + msg, path) + { + } +}; + +/// The FileFormatUpgradeRequired exception can be thrown by the DB +/// constructor when opening a database that uses a deprecated file format +/// and/or a deprecated history schema, and the user has indicated he does not +/// want automatic upgrades to be performed. This exception indicates that until +/// an upgrade of the file format is performed, the database will be unavailable +/// for read or write operations. +/// It will also be thrown if a realm which requires upgrade is opened in read-only +/// mode (Group::open). +struct FileFormatUpgradeRequired : util::File::AccessError { + FileFormatUpgradeRequired(const std::string& msg, const std::string& path) + : util::File::AccessError(msg, path) + { + } +}; + + +/// A DB facilitates transactions. +/// +/// Access to a database is done through transactions. Transactions +/// are created by a DB object. No matter how many transactions you +/// use, you only need a single DB object per file. Methods on the DB +/// object are thread-safe. +/// +/// Realm has 3 types of Transactions: +/// * A frozen transaction allows read only access +/// * A read transaction allows read only access but can be promoted +/// to a write transaction. +/// * A write transaction allows write access. A write transaction can +/// be demoted to a read transaction. +/// +/// Frozen transactions are thread safe. Read and write transactions are not. +/// +/// Two processes that want to share a database file must reside on +/// the same host. +/// + +class DB; +using DBRef = std::shared_ptr; + +class DB : public std::enable_shared_from_this { +public: + // Create a DB and associate it with a file. DB Objects can only be associated with one file, + // the association determined on creation of the DB Object. The association can be broken by + // calling DB::close(), but after that no new association can be established. To reopen the + // file (or another file), a new DB object is needed. + static DBRef create(const std::string& file, bool no_create = false, const DBOptions options = DBOptions()); + static DBRef create(Replication& repl, const DBOptions options = DBOptions()); + + ~DB() noexcept; + + // Disable copying to prevent accessor errors. If you really want another + // instance, open another DB object on the same file. But you don't. + DB(const DB&) = delete; + DB& operator=(const DB&) = delete; + /// Close an open database. Calling close() is thread-safe with respect to + /// other calls to close and with respect to deleting transactions. + /// Calling close() while a write transaction is open is an error and close() + /// will throw a LogicError::wrong_transact_state. + /// Calling close() while a read transaction is open is by default treated + /// in the same way, but close(true) will allow the error to be ignored and + /// release resources despite open read transactions. + /// As successfull call to close() leaves transactions (and any associated + /// accessors) in a defunct state and the actual close() operation is not + /// interlocked with access through those accessors, so any access through accessors + /// may constitute a race with a call to close(). + /// Instead of using DB::close() to release resources, we recommend using transactions + /// to control release as follows: + /// * explicitly nullify TransactionRefs at earliest time possible and + /// * for read or write transactions - but not frozen transactions, explicitly call + /// close() at earliest time possible + /// * explicitly nullify any DBRefs you may have. + void close(bool allow_open_read_transactions = false); + + bool is_attached() const noexcept; + + Allocator& get_alloc() + { + return m_alloc; + } + + Replication* get_replication() const + { + return m_replication; + } + + void set_replication(Replication* repl) noexcept + { + m_replication = repl; + } + + +#ifdef REALM_DEBUG + /// Deprecated method, only called from a unit test + /// + /// Reserve disk space now to avoid allocation errors at a later + /// point in time, and to minimize on-disk fragmentation. In some + /// cases, less fragmentation translates into improved + /// performance. + /// + /// When supported by the system, a call to this function will + /// make the database file at least as big as the specified size, + /// and cause space on the target device to be allocated (note + /// that on many systems on-disk allocation is done lazily by + /// default). If the file is already bigger than the specified + /// size, the size will be unchanged, and on-disk allocation will + /// occur only for the initial section that corresponds to the + /// specified size. + /// + /// It is an error to call this function on an unattached shared + /// group. Doing so will result in undefined behavior. + void reserve(size_t size_in_bytes); +#endif + + /// Querying for changes: + /// + /// NOTE: + /// "changed" means that one or more commits has been made to the database + /// since the presented transaction was made. + /// + /// No distinction is made between changes done by another process + /// and changes done by another thread in the same process as the caller. + /// + /// Has db been changed ? + bool has_changed(TransactionRef); + + /// The calling thread goes to sleep until the database is changed, or + /// until wait_for_change_release() is called. After a call to + /// wait_for_change_release() further calls to wait_for_change() will return + /// immediately. To restore the ability to wait for a change, a call to + /// enable_wait_for_change() is required. Return true if the database has + /// changed, false if it might have. + bool wait_for_change(TransactionRef); + + /// release any thread waiting in wait_for_change(). + void wait_for_change_release(); + + /// re-enable waiting for change + void enable_wait_for_change(); + // Transactions: + + using version_type = _impl::History::version_type; + using VersionID = realm::VersionID; + + /// Returns the version of the latest snapshot. + version_type get_version_of_latest_snapshot(); + + /// Thrown by start_read() if the specified version does not correspond to a + /// bound (AKA tethered) snapshot. + struct BadVersion; + + + /// Transactions are obtained from one of the following 3 methods: + TransactionRef start_read(VersionID = VersionID()); + TransactionRef start_frozen(VersionID = VersionID()); + // If nonblocking is true and a write transaction is already active, + // an invalid TransactionRef is returned. + TransactionRef start_write(bool nonblocking = false); + + + // report statistics of last commit done on THIS DB. + // The free space reported is what can be expected to be freed + // by compact(). This may not correspond to the space which is free + // at the point where get_stats() is called, since that will include + // memory required to hold older versions of data, which still + // needs to be available. The locked space is the amount of memory + // that is free in current version, but being used in still live versions. + // Notice that we will always have two live versions - the current and the + // previous. + void get_stats(size_t& free_space, size_t& used_space, util::Optional locked_space = util::none) const; + //@} + + enum TransactStage { + transact_Ready, + transact_Reading, + transact_Writing, + transact_Frozen, + }; + + /// Report the number of distinct versions currently stored in the database. + /// Note: the database only cleans up versions as part of commit, so ending + /// a read transaction will not immediately release any versions. + uint_fast64_t get_number_of_versions(); + + /// Get the size of the currently allocated slab area + size_t get_allocated_size() const; + + /// Compact the database file. + /// - The method will throw if called inside a transaction. + /// - The method will throw if called in unattached state. + /// - The method will return false if other DBs are accessing the + /// database in which case compaction is not done. This is not + /// necessarily an error. + /// It will return true following successful compaction. + /// While compaction is in progress, attempts by other + /// threads or processes to open the database will wait. + /// Likewise, attempts to create new transactions will wait. + /// Be warned that resource requirements for compaction is proportional to + /// the amount of live data in the database. + /// Compaction works by writing the database contents to a temporary + /// database file and then replacing the database with the temporary one. + /// The name of the temporary file is formed by appending + /// ".tmp_compaction_space" to the name of the database + /// + /// If the output_encryption_key is `none` then the file's existing key will + /// be used (if any). If the output_encryption_key is nullptr, the resulting + /// file will be unencrypted. Any other value will change the encryption of + /// the file to the new 64 byte key. + /// + /// FIXME: This function is not yet implemented in an exception-safe manner, + /// therefore, if it throws, the application should not attempt to + /// continue. If may not even be safe to destroy the DB object. + /// + /// WARNING / FIXME: compact() should NOT be exposed publicly on Windows + /// because it's not crash safe! It may corrupt your database if something fails + /// + /// WARNING: Compact() is not thread-safe with respect to a concurrent close() + bool compact(bool bump_version_number = false, util::Optional output_encryption_key = util::none); + +#ifdef REALM_DEBUG + void test_ringbuf(); +#endif + + /// The relation between accessors, threads and the Transaction object. + /// + /// Once created, accessors belong to a transaction and can only be used for + /// access as long as that transaction is still active. Copies of accessors + /// can be created in association with another transaction, the importing transaction, + /// using said transactions import_copy_of() method. This process is called + /// accessor import. Prior to Core 6, the corresponding mechanism was known + /// as "handover". + /// + /// For TableViews, there are 3 forms of import determined by the PayloadPolicy. + /// + /// - with payload move: the payload imported ends up as a payload + /// held by the accessor at the importing side. The accessor on the + /// exporting side will rerun its query and generate a new payload, if + /// TableView::sync_if_needed() is called. If the original payload was in + /// sync at the exporting side, it will also be in sync at the importing + /// side. This policy is selected by PayloadPolicy::Move + /// + /// - with payload copy: a copy of the payload is imported, so both the + /// accessors on the exporting side *and* the accessors created at the + /// importing side has their own payload. This is policy is selected + /// by PayloadPolicy::Copy + /// + /// - without payload: the payload stays with the accessor on the exporting + /// side. On the importing side, the new accessor is created without + /// payload. A call to TableView::sync_if_needed() will trigger generation + /// of a new payload. This policy is selected by PayloadPolicy::Stay. + /// + /// For all other (non-TableView) accessors, importing is done with payload + /// copy, since the payload is trivial. + /// + /// Importing *without* payload is useful when you want to ship a tableview + /// with its query for execution in a background thread. Handover with + /// *payload move* is useful when you want to transfer the result back. + /// + /// Importing *without* payload or with payload copy is guaranteed *not* to + /// change the accessors on the exporting side. + /// + /// Importing is generally *not* thread safe and should be carried out + /// by the thread that "owns" the involved accessors. However, importing + /// *is* thread-safe when it occurs from a *frozen* accessor. + /// + /// Importing is transitive: + /// If the object being imported depends on other views + /// (table- or link- ), those objects will be imported as well. The mode + /// (payload copy, payload move, without payload) is applied + /// recursively. Note: If you are importing a tableview dependent upon + /// another tableview and using MutableSourcePayload::Move, + /// you are on thin ice! + /// + /// On the importing side, the top-level accessor being created during + /// import takes ownership of all other accessors (if any) being created as + /// part of the import. + std::shared_ptr get_metrics() + { + return m_metrics; + } + + // Try to grab a exclusive lock of the given realm path's lock file. If the lock + // can be acquired, the callback will be executed with the lock and then return true. + // Otherwise false will be returned directly. + // The lock taken precludes races with other threads or processes accessing the + // files through a DB. + // It is safe to delete/replace realm files inside the callback. + // WARNING: It is not safe to delete the lock file in the callback. + using CallbackWithLock = std::function; + static bool call_with_lock(const std::string& realm_path, CallbackWithLock callback); + + // Return a list of files/directories core may use of the given realm file path. + // The first element of the pair in the returned list is the path string, the + // second one is to indicate the path is a directory or not. + // The temporary files are not returned by this function. + // It is safe to delete those returned files/directories in the call_with_lock's callback. + static std::vector> get_core_files(const std::string& realm_path); + +protected: + explicit DB(const DBOptions& options); // Is this ever used? + +private: + std::recursive_mutex m_mutex; + int m_transaction_count = 0; + SlabAlloc m_alloc; + Replication* m_replication = nullptr; + struct SharedInfo; + struct ReadCount; + struct ReadLockInfo { + uint_fast64_t m_version = std::numeric_limits::max(); + uint_fast32_t m_reader_idx = 0; + ref_type m_top_ref = 0; + size_t m_file_size = 0; + }; + class ReadLockGuard; + + // Member variables + size_t m_free_space = 0; + size_t m_locked_space = 0; + size_t m_used_space = 0; + uint_fast32_t m_local_max_entry = 0; // highest version observed by this DB + std::vector m_local_locks_held; // tracks all read locks held by this DB + util::File m_file; + util::File::Map m_file_map; // Never remapped, provides access to everything but the ringbuffer + util::File::Map m_reader_map; // provides access to ringbuffer, remapped as needed when it grows + bool m_wait_for_change_enabled = true; // Initially wait_for_change is enabled + bool m_write_transaction_open = false; + std::string m_lockfile_path; + std::string m_lockfile_prefix; + std::string m_db_path; + std::string m_coordination_dir; + const char* m_key; + int m_file_format_version = 0; + util::InterprocessMutex m_writemutex; +#ifdef REALM_ASYNC_DAEMON + util::InterprocessMutex m_balancemutex; +#endif + util::InterprocessMutex m_controlmutex; +#ifdef REALM_ASYNC_DAEMON + util::InterprocessCondVar m_room_to_write; + util::InterprocessCondVar m_work_to_do; + util::InterprocessCondVar m_daemon_becomes_ready; +#endif + util::InterprocessCondVar m_new_commit_available; + util::InterprocessCondVar m_pick_next_writer; + std::function m_upgrade_callback; + + std::shared_ptr m_metrics; + /// Attach this DB instance to the specified database file. + /// + /// While at least one instance of DB exists for a specific + /// database file, a "lock" file will be present too. The lock file will be + /// placed in the same directory as the database file, and its name will be + /// derived by appending ".lock" to the name of the database file. + /// + /// When multiple DB instances refer to the same file, they must + /// specify the same durability level, otherwise an exception will be + /// thrown. + /// + /// \param file Filesystem path to a Realm database file. + /// + /// \param no_create If the database file does not already exist, it will be + /// created (unless this is set to true.) When multiple threads are involved, + /// it is safe to let the first thread, that gets to it, create the file. + /// + /// \param options See DBOptions for details of each option. + /// Sensible defaults are provided if this parameter is left out. + /// + /// \throw util::File::AccessError If the file could not be opened. If the + /// reason corresponds to one of the exception types that are derived from + /// util::File::AccessError, the derived exception type is thrown. Note that + /// InvalidDatabase is among these derived exception types. + /// + /// \throw FileFormatUpgradeRequired if \a DBOptions::allow_upgrade + /// is `false` and an upgrade is required. + /// + /// \throw UnsupportedFileFormatVersion if the file format version or + /// history schema version is one which this version of Realm does not know + /// how to migrate from. + void open(const std::string& file, bool no_create = false, const DBOptions options = DBOptions()); + + /// Open this group in replication mode. The specified Replication instance + /// must remain in existence for as long as the DB. + void open(Replication&, const DBOptions options = DBOptions()); + + + void do_open(const std::string& file, bool no_create, bool is_backend, const DBOptions options); + + Replication* const* get_repl() const noexcept + { + return &m_replication; + } + + // Ring buffer management + bool ringbuf_is_empty() const noexcept; + size_t ringbuf_size() const noexcept; + size_t ringbuf_capacity() const noexcept; + bool ringbuf_is_first(size_t ndx) const noexcept; + void ringbuf_remove_first() noexcept; + size_t ringbuf_find(uint64_t version) const noexcept; + ReadCount& ringbuf_get(size_t ndx) noexcept; + ReadCount& ringbuf_get_first() noexcept; + ReadCount& ringbuf_get_last() noexcept; + void ringbuf_put(const ReadCount& v); + void ringbuf_expand(); + + /// Grab a read lock on the snapshot associated with the specified + /// version. If `version_id == VersionID()`, a read lock will be grabbed on + /// the latest available snapshot. Fails if the snapshot is no longer + /// available. + /// + /// As a side effect update memory mapping to ensure that the ringbuffer + /// entries referenced in the readlock info is accessible. + void grab_read_lock(ReadLockInfo&, VersionID); + + // Release a specific read lock. The read lock MUST have been obtained by a + // call to grab_read_lock(). + void release_read_lock(ReadLockInfo&) noexcept; + + // Release all read locks held by this DB object. After release, further calls to + // release_read_lock for locks already released must be avoided. + void release_all_read_locks() noexcept; + + /// return true if write transaction can commence, false otherwise. + bool do_try_begin_write(); + void do_begin_write(); + version_type do_commit(Transaction&); + void do_end_write() noexcept; + + // make sure the given index is within the currently mapped area. + // if not, expand the mapped area. Returns true if the area is expanded. + bool grow_reader_mapping(uint_fast32_t index); + + // Must be called only by someone that has a lock on the write mutex. + void low_level_commit(uint_fast64_t new_version, Transaction& transaction); + + void do_async_commits(); + + /// Upgrade file format and/or history schema + void upgrade_file_format(bool allow_file_format_upgrade, int target_file_format_version, + int current_hist_schema_version, int target_hist_schema_version); + + int get_file_format_version() const noexcept; + + /// finish up the process of starting a write transaction. Internal use only. + void finish_begin_write(); + + void reset_free_space_tracking() + { + m_alloc.reset_free_space_tracking(); + } + + void close_internal(std::unique_lock, bool allow_open_read_transactions); + friend class Transaction; +}; + +inline void DB::get_stats(size_t& free_space, size_t& used_space, util::Optional locked_space) const +{ + free_space = m_free_space; + used_space = m_used_space; + if (locked_space) { + *locked_space = m_locked_space; + } +} + + +class Transaction : public Group { +public: + Transaction(DBRef _db, SlabAlloc* alloc, DB::ReadLockInfo& rli, DB::TransactStage stage); + // convenience, so you don't need to carry a reference to the DB around + ~Transaction(); + + DB::version_type get_version() const noexcept + { + return m_read_lock.m_version; + } + DB::version_type get_version_of_latest_snapshot() + { + return db->get_version_of_latest_snapshot(); + } + void close(); + bool is_attached() + { + return m_transact_stage != DB::transact_Ready && db->is_attached(); + } + + /// Get the approximate size of the data that would be written to the file if + /// a commit were done at this point. The reported size will always be bigger + /// than what will eventually be needed as we reserve a bit more memory than + /// what will be needed. + size_t get_commit_size() const; + + DB::version_type commit(); + void rollback(); + void end_read(); + + // Live transactions state changes, often taking an observer functor: + DB::version_type commit_and_continue_as_read(); + template + void rollback_and_continue_as_read(O* observer); + void rollback_and_continue_as_read() + { + _impl::NullInstructionObserver* o = nullptr; + rollback_and_continue_as_read(o); + } + template + void advance_read(O* observer, VersionID target_version = VersionID()); + void advance_read(VersionID target_version = VersionID()) + { + _impl::NullInstructionObserver* o = nullptr; + advance_read(o, target_version); + } + template + bool promote_to_write(O* observer, bool nonblocking = false); + bool promote_to_write(bool nonblocking = false) + { + _impl::NullInstructionObserver* o = nullptr; + return promote_to_write(o, nonblocking); + } + TransactionRef freeze(); + // Frozen transactions are created by freeze() or DB::start_frozen() + bool is_frozen() const noexcept override { return m_transact_stage == DB::transact_Frozen; } + TransactionRef duplicate(); + + _impl::History* get_history() const; + + // direct handover of accessor instances + Obj import_copy_of(const ConstObj& original); // slicing is OK for Obj/ConstObj + TableRef import_copy_of(const ConstTableRef original); + LnkLst import_copy_of(const ConstLnkLst& original); + LstBasePtr import_copy_of(const LstBase& original); + LnkLstPtr import_copy_of(const LnkLstPtr& original); + LnkLstPtr import_copy_of(const ConstLnkLstPtr& original); + + // handover of the heavier Query and TableView + std::unique_ptr import_copy_of(Query&, PayloadPolicy); + std::unique_ptr import_copy_of(TableView&, PayloadPolicy); + std::unique_ptr import_copy_of(ConstTableView&, PayloadPolicy); + + /// Get the current transaction type + DB::TransactStage get_transact_stage() const noexcept; + + /// Get a version id which may be used to request a different transaction locked to specific version. + VersionID get_version_of_current_transaction(); + + void upgrade_file_format(int target_file_format_version); + +private: + DBRef get_db() const + { + return db; + } + + Replication* const* get_repl() const final + { + return db->get_repl(); + } + + template + bool internal_advance_read(O* observer, VersionID target_version, _impl::History&, bool); + void set_transact_stage(DB::TransactStage stage) noexcept; + void do_end_read() noexcept; + void commit_and_continue_writing(); + void initialize_replication(); + + DBRef db; + mutable std::unique_ptr<_impl::History> m_history_read; + mutable _impl::History* m_history = nullptr; + + DB::ReadLockInfo m_read_lock; + DB::TransactStage m_transact_stage = DB::transact_Ready; + + friend class DB; + friend class DisableReplication; +}; + +class DisableReplication { +public: + DisableReplication(Transaction& t) + : m_tr(t) + , m_owner(t.get_db()) + , m_repl(m_owner->get_replication()) + , m_version(t.get_version()) + { + m_owner->set_replication(nullptr); + t.get_version(); + t.m_history = nullptr; + } + + ~DisableReplication() + { + m_owner->set_replication(m_repl); + if (m_version != m_tr.get_version()) + m_tr.initialize_replication(); + } + +private: + Transaction& m_tr; + DBRef m_owner; + Replication* m_repl; + DB::version_type m_version; +}; + + +/* + * classes providing backward Compatibility with the older + * ReadTransaction and WriteTransaction types. + */ + +class ReadTransaction { +public: + ReadTransaction(DBRef sg) + : trans(sg->start_read()) + { + } + + ~ReadTransaction() noexcept + { + } + + operator Transaction&() + { + return *trans; + } + + bool has_table(StringData name) const noexcept + { + return trans->has_table(name); + } + + ConstTableRef get_table(TableKey key) const + { + return trans->get_table(key); // Throws + } + + ConstTableRef get_table(StringData name) const + { + return trans->get_table(name); // Throws + } + + const Group& get_group() const noexcept + { + return *trans.get(); + } + + /// Get the version of the snapshot to which this read transaction is bound. + DB::version_type get_version() const noexcept + { + return trans->get_version(); + } + +private: + TransactionRef trans; +}; + + +class WriteTransaction { +public: + WriteTransaction(DBRef sg) + : trans(sg->start_write()) + { + } + + ~WriteTransaction() noexcept + { + } + + operator Transaction&() + { + return *trans; + } + + bool has_table(StringData name) const noexcept + { + return trans->has_table(name); + } + + TableRef get_table(TableKey key) const + { + return trans->get_table(key); // Throws + } + + TableRef get_table(StringData name) const + { + return trans->get_table(name); // Throws + } + + TableRef add_table(StringData name) const + { + return trans->add_table(name); // Throws + } + + TableRef add_embedded_table(StringData name) const + { + return trans->add_embedded_table(name); // Throws + } + + TableRef get_or_add_table(StringData name, bool* was_added = nullptr) const + { + return trans->get_or_add_table(name, was_added); // Throws + } + + Group& get_group() const noexcept + { + return *trans.get(); + } + + /// Get the version of the snapshot on which this write transaction is + /// based. + DB::version_type get_version() const noexcept + { + return trans->get_version(); + } + + DB::version_type commit() + { + return trans->commit(); + } + + void rollback() noexcept + { + trans->rollback(); + } + +private: + TransactionRef trans; +}; + + +// Implementation: + +struct DB::BadVersion : std::exception { +}; + +inline bool DB::is_attached() const noexcept +{ + return m_file_map.is_attached(); +} + +inline DB::TransactStage Transaction::get_transact_stage() const noexcept +{ + return m_transact_stage; +} + +class DB::ReadLockGuard { +public: + ReadLockGuard(DB& shared_group, ReadLockInfo& read_lock) noexcept + : m_shared_group(shared_group) + , m_read_lock(&read_lock) + { + } + ~ReadLockGuard() noexcept + { + if (m_read_lock) + m_shared_group.release_read_lock(*m_read_lock); + } + void release() noexcept + { + m_read_lock = 0; + } + +private: + DB& m_shared_group; + ReadLockInfo* m_read_lock; +}; + +template +inline void Transaction::advance_read(O* observer, VersionID version_id) +{ + if (m_transact_stage != DB::transact_Reading) + throw LogicError(LogicError::wrong_transact_state); + + // It is an error if the new version precedes the currently bound one. + if (version_id.version < m_read_lock.m_version) + throw LogicError(LogicError::bad_version); + + auto hist = get_history(); // Throws + if (!hist) + throw LogicError(LogicError::no_history); + + internal_advance_read(observer, version_id, *hist, false); // Throws +} + +template +inline bool Transaction::promote_to_write(O* observer, bool nonblocking) +{ + if (m_transact_stage != DB::transact_Reading) + throw LogicError(LogicError::wrong_transact_state); + + if (nonblocking) { + bool succes = db->do_try_begin_write(); + if (!succes) { + return false; + } + } + else { + db->do_begin_write(); // Throws + } + try { + Replication* repl = db->get_replication(); + if (!repl) + throw LogicError(LogicError::no_history); + + VersionID version = VersionID(); // Latest + m_history = repl->_get_history_write(); + bool history_updated = internal_advance_read(observer, version, *m_history, true); // Throws + + REALM_ASSERT(repl); // Presence of `repl` follows from the presence of `hist` + DB::version_type current_version = m_read_lock.m_version; + repl->initiate_transact(*this, current_version, history_updated); // Throws + + // If the group has no top array (top_ref == 0), create a new node + // structure for an empty group now, to be ready for modifications. See + // also Group::attach_shared(). + if (!m_top.is_attached()) + create_empty_group(); // Throws + } + catch (...) { + db->do_end_write(); + m_history = nullptr; + throw; + } + + set_transact_stage(DB::transact_Writing); + return true; +} + +template +inline void Transaction::rollback_and_continue_as_read(O* observer) +{ + if (m_transact_stage != DB::transact_Writing) + throw LogicError(LogicError::wrong_transact_state); + + Replication* repl = db->get_replication(); + if (!repl) + throw LogicError(LogicError::no_history); + + BinaryData uncommitted_changes = repl->get_uncommitted_changes(); + + // FIXME: We are currently creating two transaction log parsers, one here, + // and one in advance_transact(). That is wasteful as the parser creation is + // expensive. + _impl::SimpleInputStream in(uncommitted_changes.data(), uncommitted_changes.size()); + _impl::TransactLogParser parser; // Throws + _impl::TransactReverser reverser; + parser.parse(in, reverser); // Throws + + if (observer && uncommitted_changes.size()) { + _impl::ReversedNoCopyInputStream reversed_in(reverser); + parser.parse(reversed_in, *observer); // Throws + observer->parse_complete(); // Throws + } + + // Mark all managed space (beyond the attached file) as free. + db->reset_free_space_tracking(); // Throws + + ref_type top_ref = m_read_lock.m_top_ref; + size_t file_size = m_read_lock.m_file_size; + _impl::ReversedNoCopyInputStream reversed_in(reverser); + advance_transact(top_ref, file_size, reversed_in, false); // Throws + + db->do_end_write(); + + repl->abort_transact(); + + m_history = nullptr; + set_transact_stage(DB::transact_Reading); +} + +template +inline bool Transaction::internal_advance_read(O* observer, VersionID version_id, _impl::History& hist, bool writable) +{ + DB::ReadLockInfo new_read_lock; + db->grab_read_lock(new_read_lock, version_id); // Throws + REALM_ASSERT(new_read_lock.m_version >= m_read_lock.m_version); + if (new_read_lock.m_version == m_read_lock.m_version) { + db->release_read_lock(new_read_lock); + // _impl::History::update_early_from_top_ref() was not called + // update allocator wrappers merely to update write protection + update_allocator_wrappers(writable); + return false; + } + + DB::ReadLockGuard g(*db, new_read_lock); + { + DB::version_type new_version = new_read_lock.m_version; + size_t new_file_size = new_read_lock.m_file_size; + ref_type new_top_ref = new_read_lock.m_top_ref; + + // Synchronize readers view of the file + SlabAlloc& alloc = m_alloc; + alloc.update_reader_view(new_file_size); + update_allocator_wrappers(writable); + using gf = _impl::GroupFriend; + // remap(new_file_size); // Throws + ref_type hist_ref = gf::get_history_ref(alloc, new_top_ref); + + hist.update_from_ref_and_version(hist_ref, new_version); + } + + if (observer) { + // This has to happen in the context of the originally bound snapshot + // and while the read transaction is still in a fully functional state. + _impl::TransactLogParser parser; + DB::version_type old_version = m_read_lock.m_version; + DB::version_type new_version = new_read_lock.m_version; + _impl::ChangesetInputStream in(hist, old_version, new_version); + parser.parse(in, *observer); // Throws + observer->parse_complete(); // Throws + } + + // The old read lock must be retained for as long as the change history is + // accessed (until Group::advance_transact() returns). This ensures that the + // oldest needed changeset remains in the history, even when the history is + // implemented as a separate unversioned entity outside the Realm (i.e., the + // old implementation and ShortCircuitHistory in + // test_lang_Bind_helper.cpp). On the other hand, if it had been the case, + // that the history was always implemented as a versioned entity, that was + // part of the Realm state, then it would not have been necessary to retain + // the old read lock beyond this point. + + { + DB::version_type old_version = m_read_lock.m_version; + DB::version_type new_version = new_read_lock.m_version; + ref_type new_top_ref = new_read_lock.m_top_ref; + size_t new_file_size = new_read_lock.m_file_size; + _impl::ChangesetInputStream in(hist, old_version, new_version); + advance_transact(new_top_ref, new_file_size, in, writable); // Throws + } + g.release(); + db->release_read_lock(m_read_lock); + m_read_lock = new_read_lock; + + return true; // _impl::History::update_early_from_top_ref() was called +} + +inline int DB::get_file_format_version() const noexcept +{ + return m_file_format_version; +} + +} // namespace realm + +#endif // REALM_GROUP_SHARED_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/db_options.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/db_options.hpp new file mode 100644 index 0000000..fbc26d1 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/db_options.hpp @@ -0,0 +1,123 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_GROUP_SHARED_OPTIONS_HPP +#define REALM_GROUP_SHARED_OPTIONS_HPP + +#include +#include + +namespace realm { + +struct DBOptions { + + /// The persistence level of the DB. + /// uint16_t is the type of DB::SharedInfo::durability + enum class Durability : uint16_t { + Full, + MemOnly, + Async, ///< Not yet supported on windows. + Unsafe // If you use this, you loose ACID property + }; + + explicit DBOptions(Durability level = Durability::Full, const char* key = nullptr, bool allow_upgrade = true, + std::function file_upgrade_callback = std::function(), + std::string temp_directory = sys_tmp_dir, bool track_metrics = false, + size_t metrics_history_size = 10000) + : durability(level) + , encryption_key(key) + , allow_file_format_upgrade(allow_upgrade) + , upgrade_callback(file_upgrade_callback) + , temp_dir(temp_directory) + , enable_metrics(track_metrics) + , metrics_buffer_size(metrics_history_size) + + { + } + + explicit DBOptions(const char* key) + : durability(Durability::Full) + , encryption_key(key) + , allow_file_format_upgrade(true) + , upgrade_callback(std::function()) + , temp_dir(sys_tmp_dir) + , enable_metrics(false) + , metrics_buffer_size(10000) + { + } + + /// The persistence level of the Realm file. See Durability. + Durability durability; + + /// The key to encrypt and decrypt the Realm file with, or nullptr to + /// indicate that encryption should not be used. + const char* encryption_key; + + /// If \a allow_file_format_upgrade is set to `true`, this function will + /// automatically upgrade the file format used in the specified Realm file + /// if necessary (and if it is possible). In order to prevent this, set \a + /// allow_upgrade to `false`. + /// + /// If \a allow_upgrade is set to `false`, only two outcomes are possible: + /// + /// - the specified Realm file is already using the latest file format, and + /// can be used, or + /// + /// - the specified Realm file uses a deprecated file format, resulting a + /// the throwing of FileFormatUpgradeRequired. + bool allow_file_format_upgrade; + + /// Optionally allows a custom function to be called immediately after the + /// Realm file is upgraded. The two parameters in the function are the + /// previous version and the version just upgraded to, respectively. + /// If the callback function throws, the Realm file will safely abort the + /// upgrade (rollback the transaction) but the DB will not be opened. + std::function upgrade_callback; + + /// A path to a directory where Realm can write temporary files or pipes to. + /// This string should include a trailing slash '/'. + std::string temp_dir; + + /// Controls the feature of collecting various metrics to the DB. + /// A prerequisite is compiling with REALM_METRICS=ON. + bool enable_metrics; + + /// The maximum number of entries stored by the metrics (if enabled). If this number + /// is exceeded without being consumed, only the most recent entries will be stored. + size_t metrics_buffer_size; + + /// sys_tmp_dir will be used if the temp_dir is empty when creating DBOptions. + /// It must be writable and allowed to create pipe/fifo file on it. + /// set_sys_tmp_dir is not a thread-safe call and it is only supposed to be called once + // when process starts. + static void set_sys_tmp_dir(const std::string& dir) noexcept + { + sys_tmp_dir = dir; + } + static std::string get_sys_tmp_dir() noexcept + { + return sys_tmp_dir; + } + +private: + static std::string sys_tmp_dir; +}; + +} // end namespace realm + +#endif // REALM_GROUP_SHARED_OPTIONS_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/decimal128.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/decimal128.hpp new file mode 100644 index 0000000..9203f28 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/decimal128.hpp @@ -0,0 +1,154 @@ +/************************************************************************* + * + * Copyright 2019 Realm Inc. + * + * 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 REALM_DECIMAL_HPP +#define REALM_DECIMAL_HPP + +#include + +#include +#include + +#include "null.hpp" + +namespace realm { + +class Decimal128 { +public: + struct Bid64 { + Bid64(uint64_t x) + : w(x) + { + } + uint64_t w; + }; + struct Bid128 { + uint64_t w[2]; + }; + Decimal128(); + explicit Decimal128(int64_t); + explicit Decimal128(uint64_t); + explicit Decimal128(int); + explicit Decimal128(double); + Decimal128(Bid128 coefficient, int exponent, bool sign); + explicit Decimal128(Bid64); + explicit Decimal128(StringData); + explicit Decimal128(Bid128 val) + { + m_value = val; + } + Decimal128(null) noexcept; + static Decimal128 nan(const char*); + static bool is_valid_str(StringData) noexcept; + + bool is_null() const; + bool is_nan() const; + + bool operator==(const Decimal128& rhs) const; + bool operator!=(const Decimal128& rhs) const; + bool operator<(const Decimal128& rhs) const; + bool operator>(const Decimal128& rhs) const; + bool operator<=(const Decimal128& rhs) const; + bool operator>=(const Decimal128& rhs) const; + + int compare(const Decimal128& rhs) const; + + Decimal128 operator*(int64_t mul) const; + Decimal128 operator*(size_t mul) const; + Decimal128 operator*(int mul) const; + Decimal128 operator*(Decimal128 mul) const; + Decimal128& operator*=(Decimal128 mul) + { + return *this = *this * mul; + } + Decimal128 operator/(int64_t div) const; + Decimal128 operator/(size_t div) const; + Decimal128 operator/(int div) const; + Decimal128 operator/(Decimal128 div) const; + Decimal128& operator/=(Decimal128 div) + { + return *this = *this / div; + } + Decimal128& operator+=(Decimal128); + Decimal128 operator+(Decimal128 rhs) const + { + auto ret(*this); + ret += rhs; + return ret; + } + Decimal128& operator-=(Decimal128); + Decimal128 operator-(Decimal128 rhs) const + { + auto ret(*this); + ret -= rhs; + return ret; + } + + std::string to_string() const; + Bid64 to_bid64() const; + const Bid128* raw() const + { + return &m_value; + } + Bid128* raw() + { + return &m_value; + } + void unpack(Bid128& coefficient, int& exponent, bool& sign) const noexcept; + +private: + Bid128 m_value; + + enum class ParseError { None, Invalid, TooLongBeforeRadix, TooLong }; + + ParseError from_string(const char* ps) noexcept; + void from_int64_t(int64_t val); +}; + +inline std::ostream& operator<<(std::ostream& ostr, const Decimal128& id) +{ + ostr << id.to_string(); + return ostr; +} + +} // namespace realm + +namespace std { +template <> +struct numeric_limits { + static constexpr bool is_integer = false; + static realm::Decimal128 lowest() noexcept + { + return realm::Decimal128("-Inf"); + } + static realm::Decimal128 max() noexcept + { + return realm::Decimal128("+Inf"); + } +}; + +template <> +struct hash { + size_t operator()(const realm::Decimal128& d) const noexcept + { + return static_cast(d.raw()->w[0] ^ d.raw()->w[1]); + } +}; +} // namespace std + +#endif /* REALM_DECIMAL_HPP */ diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/disable_sync_to_disk.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/disable_sync_to_disk.hpp new file mode 100644 index 0000000..f642d6f --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/disable_sync_to_disk.hpp @@ -0,0 +1,37 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_DISABLE_SYNC_TO_DISK_HPP +#define REALM_DISABLE_SYNC_TO_DISK_HPP + +#include + +namespace realm { + +/// Completely disable synchronization with storage device to speed up unit +/// testing. This is an unsafe mode of operation, and should never be used in +/// production. This function is thread safe. +void disable_sync_to_disk(); + +/// Returns true after disable_sync_to_disk() has been called. This function is +/// thread safe. +bool get_disable_sync_to_disk() noexcept; + +} // namespace realm + +#endif // REALM_DISABLE_SYNC_TO_DISK_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/exceptions.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/exceptions.hpp new file mode 100644 index 0000000..7ed3328 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/exceptions.hpp @@ -0,0 +1,397 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_EXCEPTIONS_HPP +#define REALM_EXCEPTIONS_HPP + +#include + +#include +#include +#include + +namespace realm { + +using util::ExceptionWithBacktrace; + +/// Thrown by various functions to indicate that a specified table does not +/// exist. +class NoSuchTable : public ExceptionWithBacktrace { +public: + const char* message() const noexcept override; +}; + + +/// Thrown by various functions to indicate that a specified table name is +/// already in use. +class TableNameInUse : public ExceptionWithBacktrace { +public: + const char* message() const noexcept override; +}; + + +// Thrown by functions that require a table to **not** be the target of link +// columns, unless those link columns are part of the table itself. +class CrossTableLinkTarget : public ExceptionWithBacktrace { +public: + const char* message() const noexcept override; +}; + + +/// Thrown by various functions to indicate that the dynamic type of a table +/// does not match a particular other table type (dynamic or static). +class DescriptorMismatch : public ExceptionWithBacktrace { +public: + const char* message() const noexcept override; +}; + + +/// The UnsupportedFileFormatVersion exception is thrown by DB::open() +/// constructor when opening a database that uses a deprecated file format +/// and/or a deprecated history schema which this version of Realm cannot +/// upgrade from. +class UnsupportedFileFormatVersion : public ExceptionWithBacktrace<> { +public: + UnsupportedFileFormatVersion(int source_version); + /// The unsupported version of the file. + int source_version = 0; +}; + + +/// Thrown when a sync agent attempts to join a session in which there is +/// already a sync agent. A session may only contain one sync agent at any given +/// time. +class MultipleSyncAgents : public ExceptionWithBacktrace { +public: + const char* message() const noexcept override; +}; + + +/// Thrown when memory can no longer be mapped to. When mmap/remap fails. +class AddressSpaceExhausted : public std::runtime_error { +public: + AddressSpaceExhausted(const std::string& msg); + /// runtime_error::what() returns the msg provided in the constructor. +}; + +/// Thrown when creating references that are too large to be contained in our ref_type (size_t) +class MaximumFileSizeExceeded : public std::runtime_error { +public: + MaximumFileSizeExceeded(const std::string& msg); + /// runtime_error::what() returns the msg provided in the constructor. +}; + +/// Thrown when writing fails because the disk is full. +class OutOfDiskSpace : public std::runtime_error { +public: + OutOfDiskSpace(const std::string& msg); + /// runtime_error::what() returns the msg provided in the constructor. +}; + +/// Thrown when a key can not by found +class KeyNotFound : public std::runtime_error { +public: + KeyNotFound(const std::string& msg) + : std::runtime_error(msg) + { + } +}; + +/// Thrown when a column can not by found +class ColumnNotFound : public std::runtime_error { +public: + ColumnNotFound() + : std::runtime_error("Column not found") + { + } +}; + +/// Thrown when a column key is already used +class ColumnAlreadyExists : public std::runtime_error { +public: + ColumnAlreadyExists() + : std::runtime_error("Column already exists") + { + } +}; + +/// Thrown when a key is already existing when trying to create a new object +class KeyAlreadyUsed : public std::runtime_error { +public: + KeyAlreadyUsed(const std::string& msg) + : std::runtime_error(msg) + { + } +}; + +// SerialisationError intentionally does not inherit ExceptionWithBacktrace +// because the query-based-sync permissions queries generated on the server +// use a LinksToNode which is not currently serialisable (this limitation can +// be lifted in core 6 given stable ids). Coupled with query metrics which +// serialize all queries, the capturing of the stack for these frequent +// permission queries shows up in performance profiles. +class SerialisationError : public std::runtime_error { +public: + SerialisationError(const std::string& msg); + /// runtime_error::what() returns the msg provided in the constructor. +}; + +// thrown when a user constructed link path is not a valid input +class InvalidPathError : public std::runtime_error { +public: + InvalidPathError(const std::string& msg); + /// runtime_error::what() returns the msg provided in the constructor. +}; + +class DuplicatePrimaryKeyValueException : public std::logic_error { +public: + DuplicatePrimaryKeyValueException(std::string object_type, std::string property); + + std::string const& object_type() const + { + return m_object_type; + } + std::string const& property() const + { + return m_property; + } + +private: + std::string m_object_type; + std::string m_property; +}; + + +/// The \c LogicError exception class is intended to be thrown only when +/// applications (or bindings) violate rules that are stated (or ought to have +/// been stated) in the documentation of the public API, and only in cases +/// where the violation could have been easily and efficiently predicted by the +/// application. In other words, this exception class is for the cases where +/// the error is due to incorrect use of the public API. +/// +/// This class is not supposed to be caught by applications. It is not even +/// supposed to be considered part of the public API, and therefore the +/// documentation of the public API should **not** mention the \c LogicError +/// exception class by name. Note how this contrasts with other exception +/// classes, such as \c NoSuchTable, which are part of the public API, and are +/// supposed to be mentioned in the documentation by name. The \c LogicError +/// exception is part of Realm's private API. +/// +/// In other words, the \c LogicError class should exclusively be used in +/// replacement (or in addition to) asserts (debug or not) in order to +/// guarantee program interruption, while still allowing for complete +/// test-cases to be written and run. +/// +/// To this effect, the special `CHECK_LOGIC_ERROR()` macro is provided as a +/// test framework plugin to allow unit tests to check that the functions in +/// the public API do throw \c LogicError when rules are violated. +/// +/// The reason behind hiding this class from the public API is to prevent users +/// from getting used to the idea that "Undefined Behaviour" equates a specific +/// exception being thrown. The whole point of properly documenting "Undefined +/// Behaviour" cases is to help the user know what the limits are, without +/// constraining the database to handle every and any use-case thrown at it. +/// +/// FIXME: This exception class should probably be moved to the `_impl` +/// namespace, in order to avoid some confusion. +class LogicError : public ExceptionWithBacktrace { +public: + enum ErrorKind { + string_too_big, + binary_too_big, + table_name_too_long, + column_name_too_long, + column_name_in_use, + invalid_column_name, + table_index_out_of_range, + row_index_out_of_range, + column_index_out_of_range, + string_position_out_of_range, + link_index_out_of_range, + bad_version, + illegal_type, + + /// Indicates that an argument has a value that is illegal in combination + /// with another argument, or with the state of an involved object. + illegal_combination, + + /// Indicates a data type mismatch, such as when `Table::find_pkey_int()` is + /// called and the type of the primary key is not `type_Int`. + type_mismatch, + + /// Indicates that two involved tables are not in the same group. + group_mismatch, + + /// Indicates that an involved descriptor is of the wrong kind, i.e., if + /// it is a subtable descriptor, and the function requires a root table + /// descriptor. + wrong_kind_of_descriptor, + + /// Indicates that an involved table is of the wrong kind, i.e., if it + /// is a subtable, and the function requires a root table, or if it is a + /// free-standing table, and the function requires a group-level table. + wrong_kind_of_table, + + /// Indicates that an involved accessor is was detached, i.e., was not + /// attached to an underlying object. + detached_accessor, + + /// Indicates that a specified row index of a target table (a link) is + /// out of range. This is used for disambiguation in cases such as + /// Table::set_link() where one specifies both a row index of the origin + /// table, and a row index of the target table. + target_row_index_out_of_range, + + // Indicates that an involved column lacks a search index. + no_search_index, + + /// Indicates that a modification was attempted that would have produced a + /// duplicate primary value. + unique_constraint_violation, + + /// User attempted to insert null in non-nullable column + column_not_nullable, + + /// Group::open() is called on a group accessor that is already in the + /// attached state. Or Group::open() or Group::commit() is called on a + /// group accessor that is managed by a DB object. + wrong_group_state, + + /// No active transaction on a particular Transaction object (e.g. after commit) + /// or the Transaction object is of the wrong type (write to a read-only transaction) + wrong_transact_state, + + /// Attempted use of a continuous transaction through a DB + /// object with no history. See Replication::get_history(). + no_history, + + /// Durability setting (as passed to the DB constructor) was + /// not consistent across the session. + mixed_durability, + + /// History type (as specified by the Replication implementation passed + /// to the DB constructor) was not consistent across the + /// session. + mixed_history_type, + + /// History schema version (as specified by the Replication + /// implementation passed to the DB constructor) was not + /// consistent across the session. + mixed_history_schema_version, + + /// Adding rows to a table with no columns is not supported. + table_has_no_columns, + + /// Referring to a column that has been deleted. + column_does_not_exist, + + /// You can not add index on a subtable of a subtable + subtable_of_subtable_index, + + /// You try to instantiate a list object not matching column type + list_type_mismatch + }; + + LogicError(ErrorKind message); + + const char* message() const noexcept override; + ErrorKind kind() const noexcept; + +private: + ErrorKind m_kind; +}; + + +// Implementation: + +// LCOV_EXCL_START (Wording of what() strings are not to be tested) + +inline const char* NoSuchTable::message() const noexcept +{ + return "No such table exists"; +} + +inline const char* TableNameInUse::message() const noexcept +{ + return "The specified table name is already in use"; +} + +inline const char* CrossTableLinkTarget::message() const noexcept +{ + return "Table is target of cross-table link columns"; +} + +inline const char* DescriptorMismatch::message() const noexcept +{ + return "Table descriptor mismatch"; +} + +inline UnsupportedFileFormatVersion::UnsupportedFileFormatVersion(int version) + : ExceptionWithBacktrace<>( + util::format("Database has an unsupported version (%1) and cannot be upgraded", version)) + , source_version(version) +{ +} + +inline const char* MultipleSyncAgents::message() const noexcept +{ + return "Multiple sync agents attempted to join the same session"; +} + +// LCOV_EXCL_STOP + +inline AddressSpaceExhausted::AddressSpaceExhausted(const std::string& msg) + : std::runtime_error(msg) +{ +} + +inline MaximumFileSizeExceeded::MaximumFileSizeExceeded(const std::string& msg) + : std::runtime_error(msg) +{ +} + +inline OutOfDiskSpace::OutOfDiskSpace(const std::string& msg) + : std::runtime_error(msg) +{ +} + +inline SerialisationError::SerialisationError(const std::string& msg) + : std::runtime_error(msg) +{ +} + +inline InvalidPathError::InvalidPathError(const std::string& msg) + : runtime_error(msg) +{ +} + +inline LogicError::LogicError(LogicError::ErrorKind k) + : m_kind(k) +{ +} + +inline LogicError::ErrorKind LogicError::kind() const noexcept +{ + return m_kind; +} + + +} // namespace realm + + +#endif // REALM_EXCEPTIONS_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/global_key.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/global_key.hpp new file mode 100644 index 0000000..bda1935 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/global_key.hpp @@ -0,0 +1,161 @@ +/************************************************************************* + * + * Copyright 2019 Realm Inc. + * + * 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 REALM_GLOBAL_KEY_HPP +#define REALM_GLOBAL_KEY_HPP + +#include +#include +#include +#include + +namespace realm { + +class StringData; +class Mixed; + +/// GlobalKeys are globally unique for a given class (table), and up to 128 bits +/// wide. They are represented as two 64-bit integers, each of which may +/// frequently be small, for best on-wire compressibility. +/// +/// We define a way to map from 128-bit on-write GlobalKeys to local 64-bit ObjKeys. +/// +/// The three object ID types are: +/// a. Global Keyss for objects in tables without primary keys. +/// b. Global Keys for objects in tables with integer primary keys. +/// c. Global Keys for objects in tables with other primary key types. +/// +/// For objects without primary keys (a), a "squeezed" tuple of the +/// client_file_ident and a peer-local sequence number is used as the local +/// ObjKey. The on-write Object ID is the "unsqueezed" format. +/// +/// For integer primary keys (b), the GlobalKey just the integer value as the low +/// part. +/// +/// For objects with other types of primary keys (c), the GlobalKey is a 128-bit +/// hash of the primary key value. However, the local object ID must be a 63-bit +/// integer, because that is the maximum size integer that can be used in an ObjKey. +/// The solution is to optimistically use the lower 62 bits of the on-wire GlobalKey. +/// If this results in a ObjKey which is already in use, a new local ObjKey is +/// generated with the 63th bit set and using a locally generated sequence number for +/// the lower bits. The mapping between GlobalKey and ObjKey is stored in the Table +/// structure. + +struct GlobalKey { + constexpr GlobalKey(uint64_t h, uint64_t l) + : m_lo(l) + , m_hi(h) + { + } + static GlobalKey from_string(StringData); + + constexpr GlobalKey(realm::util::None = realm::util::none) + : m_lo(-1) + , m_hi(-1) + { + } + + // Construct an GlobalKey from either a string, an integer or a GlobalId + GlobalKey(Mixed pk); + + // Construct an object id from the local squeezed ObjKey + GlobalKey(ObjKey squeezed, uint64_t sync_file_id) + { + uint64_t u = uint64_t(squeezed.value); + + m_lo = (u & 0xff) | ((u & 0xffffff0000) >> 8); + m_hi = ((u & 0xff00) >> 8) | ((u & 0xffffff0000000000) >> 32); + if (m_hi == 0) + m_hi = sync_file_id; + } + + constexpr GlobalKey(const GlobalKey&) noexcept = default; + GlobalKey& operator=(const GlobalKey&) noexcept = default; + + constexpr uint64_t lo() const + { + return m_lo; + } + constexpr uint64_t hi() const + { + return m_hi; + } + + std::string to_string() const; + + constexpr bool operator<(const GlobalKey& other) const + { + return (m_hi == other.m_hi) ? (m_lo < other.m_lo) : (m_hi < other.m_hi); + } + constexpr bool operator==(const GlobalKey& other) const + { + return m_hi == other.m_hi && m_lo == other.m_lo; + } + constexpr bool operator!=(const GlobalKey& other) const + { + return !(*this == other); + } + + explicit constexpr operator bool() const noexcept + { + return (*this != GlobalKey{}); + } + + // Generate a local ObjKey from the GlobalKey. If the object is created + // in this realm (sync_file_id == hi) then 0 is used for hi. In this + // way we achieves that objects created before first contact with the + // server does not need to change key. + ObjKey get_local_key(uint64_t sync_file_id) + { + REALM_ASSERT(m_hi <= 0x3fffffff); + REALM_ASSERT(lo() <= std::numeric_limits::max()); + + auto high = m_hi; + if (high == sync_file_id) + high = 0; + uint64_t a = m_lo & 0xff; + uint64_t b = (high & 0xff) << 8; + uint64_t c = (m_lo & 0xffffff00) << 8; + uint64_t d = (high & 0x3fffff00) << 32; + + return ObjKey(int64_t(a | b | c | d)); + } + +private: + uint64_t m_lo; + uint64_t m_hi; +}; + +std::ostream& operator<<(std::ostream&, const GlobalKey&); +std::istream& operator>>(std::istream&, GlobalKey&); + +} // namespace realm + +namespace std { + +template <> +struct hash { + size_t operator()(realm::GlobalKey oid) const + { + return std::hash{}(oid.lo()) ^ std::hash{}(oid.hi()); + } +}; + +} // namespace std + +#endif /* REALM_OBJECT_ID_HPP */ diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/group.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/group.hpp new file mode 100644 index 0000000..959c1e2 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/group.hpp @@ -0,0 +1,1381 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_GROUP_HPP +#define REALM_GROUP_HPP + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace realm { + +class DB; +class TableKeys; + +namespace _impl { +class GroupFriend; +class TransactLogConvenientEncoder; +class TransactLogParser; +} + + +/// A group is a collection of named tables. +/// +class Group : public ArrayParent { +public: + /// Construct a free-standing group. This group instance will be + /// in the attached state, but neither associated with a file, nor + /// with an external memory buffer. + Group(); + + enum OpenMode { + /// Open in read-only mode. Fail if the file does not already exist. + mode_ReadOnly, + /// Open in read/write mode. Create the file if it doesn't exist. + mode_ReadWrite, + /// Open in read/write mode. Fail if the file does not already exist. + mode_ReadWriteNoCreate + }; + + /// Equivalent to calling open(const std::string&, const char*, OpenMode) + /// on an unattached group accessor. + explicit Group(const std::string& file, const char* encryption_key = nullptr, OpenMode = mode_ReadOnly); + + /// Equivalent to calling open(BinaryData, bool) on an unattached + /// group accessor. Note that if this constructor throws, the + /// ownership of the memory buffer will remain with the caller, + /// regardless of whether \a take_ownership is set to `true` or + /// `false`. + explicit Group(BinaryData, bool take_ownership = true); + + struct unattached_tag { + }; + + /// Create a Group instance in its unattached state. It may then + /// be attached to a database file later by calling one of the + /// open() methods. You may test whether this instance is + /// currently in its attached state by calling + /// is_attached(). Calling any other method (except the + /// destructor) while in the unattached state has undefined + /// behavior. + Group(unattached_tag) noexcept; + + // FIXME: Implement a proper copy constructor (fairly trivial). + Group(const Group&) = delete; + Group& operator=(const Group&) = delete; + + ~Group() noexcept override; + + /// Attach this Group instance to the specified database file. + /// + /// By default, the specified file is opened in read-only mode + /// (mode_ReadOnly). This allows opening a file even when the + /// caller lacks permission to write to that file. The opened + /// group may still be modified freely, but the changes cannot be + /// written back to the same file using the commit() function. An + /// attempt to do that, will cause an exception to be thrown. When + /// opening in read-only mode, it is an error if the specified + /// file does not already exist in the file system. + /// + /// Alternatively, the file can be opened in read/write mode + /// (mode_ReadWrite). This allows use of the commit() function, + /// but, of course, it also requires that the caller has + /// permission to write to the specified file. When opening in + /// read-write mode, an attempt to create the specified file will + /// be made, if it does not already exist in the file system. + /// + /// In any case, if the file already exists, it must contain a + /// valid Realm database. In many cases invalidity will be + /// detected and cause the InvalidDatabase exception to be thrown, + /// but you should not rely on it. + /// + /// Note that changes made to the database via a Group instance + /// are not automatically committed to the specified file. You + /// may, however, at any time, explicitly commit your changes by + /// calling the commit() method, provided that the specified + /// open-mode is not mode_ReadOnly. Alternatively, you may call + /// write() to write the entire database to a new file. Writing + /// the database to a new file does not end, or in any other way + /// change the association between the Group instance and the file + /// that was specified in the call to open(). + /// + /// A Realm file that contains a history (see Replication::HistoryType) may + /// be opened via Group::open(), as long as the application can ensure that + /// there is no concurrent access to the file (see below for more on + /// concurrency), but if the file is modified via Group::commit() the + /// history will be discarded. To retain the history, the application must + /// instead access the file in shared mode, i.e., via DB, and + /// supply the right kind of replication plugin (see + /// Replication::get_history_type()). + /// + /// A file that is passed to Group::open(), may not be modified by + /// a third party until after the Group object is + /// destroyed. Behavior is undefined if a file is modified by a + /// third party while any Group object is associated with it. + /// + /// Calling open() on a Group instance that is already in the + /// attached state has undefined behavior. + /// + /// Accessing a Realm database file through manual construction + /// of a Group object does not offer any level of thread safety or + /// transaction safety. When any of those kinds of safety are a + /// concern, consider using a DB instead. When accessing + /// a database file in read/write mode through a manually + /// constructed Group object, it is entirely the responsibility of + /// the application that the file is not accessed in any way by a + /// third party during the life-time of that group object. It is, + /// on the other hand, safe to concurrently access a database file + /// by multiple manually created Group objects, as long as all of + /// them are opened in read-only mode, and there is no other party + /// that modifies the file concurrently. + /// + /// Do not call this function on a group instance that is managed + /// by a shared group. Doing so will result in undefined behavior. + /// + /// Even if this function throws, it may have the side-effect of + /// creating the specified file, and the file may get left behind + /// in an invalid state. Of course, this can only happen if + /// read/write mode (mode_ReadWrite) was requested, and the file + /// did not already exist. + /// + /// \param file File system path to a Realm database file. + /// + /// \param encryption_key 32-byte key used to encrypt and decrypt + /// the database file, or nullptr to disable encryption. + /// + /// \param mode Specifying a mode that is not mode_ReadOnly + /// requires that the specified file can be opened in read/write + /// mode. In general there is no reason to open a group in + /// read/write mode unless you want to be able to call + /// Group::commit(). + /// + /// \throw util::File::AccessError If the file could not be + /// opened. If the reason corresponds to one of the exception + /// types that are derived from util::File::AccessError, the + /// derived exception type is thrown. Note that InvalidDatabase is + /// among these derived exception types. + void open(const std::string& file, const char* encryption_key = nullptr, OpenMode mode = mode_ReadOnly); + + /// Attach this Group instance to the specified memory buffer. + /// + /// This is similar to constructing a group from a file except + /// that in this case the database is assumed to be stored in the + /// specified memory buffer. + /// + /// If \a take_ownership is `true`, you pass the ownership of the + /// specified buffer to the group. In this case the buffer will + /// eventually be freed using std::free(), so the buffer you pass, + /// must have been allocated using std::malloc(). + /// + /// On the other hand, if \a take_ownership is set to `false`, it + /// is your responsibility to keep the memory buffer alive during + /// the lifetime of the group, and in case the buffer needs to be + /// deallocated afterwards, that is your responsibility too. + /// + /// If this function throws, the ownership of the memory buffer + /// will remain with the caller, regardless of whether \a + /// take_ownership is set to `true` or `false`. + /// + /// Calling open() on a Group instance that is already in the + /// attached state has undefined behavior. + /// + /// Do not call this function on a group instance that is managed + /// by a shared group. Doing so will result in undefined behavior. + /// + /// \throw InvalidDatabase If the specified buffer does not appear + /// to contain a valid database. + void open(BinaryData, bool take_ownership = true); + + /// A group may be created in the unattached state, and then later + /// attached to a file with a call to open(). Calling any method + /// other than open(), and is_attached() on an unattached instance + /// results in undefined behavior. + bool is_attached() const noexcept; + /// A group is frozen only if it is actually a frozen transaction. + virtual bool is_frozen() const noexcept { return false; } + /// Returns true if, and only if the number of tables in this + /// group is zero. + bool is_empty() const noexcept; + + size_t size() const noexcept; + + int get_history_schema_version() noexcept; + + Replication* get_replication() const + { + return *get_repl(); + } + + /// The sync file id is set when a client synchronizes with the server for the + /// first time. It is used when generating GlobalKeys for tables without a primary + /// key, where it is used as the "hi" part. This ensures global uniqueness of + /// GlobalKeys. + uint64_t get_sync_file_id() const noexcept; + void set_sync_file_id(uint64_t id); + + /// Returns the keys for all tables in this group. + TableKeys get_table_keys() const; + + /// \defgroup group_table_access Table Accessors + /// + /// has_table() returns true if, and only if this group contains a table + /// with the specified name. + /// + /// find_table() returns the key of the first table in this group with the + /// specified name, or `realm::not_found` if this group does not contain a + /// table with the specified name. + /// + /// get_table_name() returns the name of table with the specified key. + /// + /// The versions of get_table(), that accepts a \a name argument, return a + /// table with the specified name, or null if no such table exists. + /// + /// add_table() adds a table with the specified name to this group. It + /// throws TableNameInUse if \a require_unique_name is true and \a name + /// clashes with the name of an existing table. If \a require_unique_name is + /// false, it is possible to add more than one table with the same + /// name. Whenever a table is added the key assigned to it is returned. + /// + /// get_or_add_table() checks if a table exists in this group with the specified + /// name. If it doesn't exist, a table is created. + /// + /// remove_table() removes the specified table from this group. A table can + /// be removed only when it is not the target of a link column of a + /// different table. + /// + /// rename_table() changes the name of a preexisting table. If \a + /// require_unique_name is false, it becomes possible to have more than one + /// table with a given name in a single group. + /// + /// The template functions work exactly like their non-template namesakes + /// except as follows: The template versions of get_table() and + /// get_or_add_table() throw DescriptorMismatch if the dynamic type of the + /// specified table does not match the statically specified custom table + /// type. The template versions of add_table() and get_or_add_table() set + /// the dynamic type (descriptor) to match the statically specified custom + /// table type. + /// + /// \param key Key of table in this group. + /// + /// \param name Name of table. All strings are valid table names as long as + /// they are valid UTF-8 encodings and the number of bytes does not exceed + /// `max_table_name_length`. A call to add_table() or get_or_add_table() + /// with a name that is longer than `max_table_name_length` will cause an + /// exception to be thrown. + /// + /// \param new_name New name for preexisting table. + /// + /// \param require_unique_name When set to true (the default), it becomes + /// impossible to add a table with a name that is already in use, or to + /// rename a table to a name that is already in use. + /// + /// \param was_added When specified, the boolean variable is set to true if + /// the table was added, and to false otherwise. If the function throws, the + /// boolean variable retains its original value. + /// + /// \return get_table(), add_table(), and get_or_add_table() return a table + /// accessor attached to the requested (or added) table. get_table() may + /// return null. + /// + /// \throw DescriptorMismatch Thrown by get_table() and get_or_add_table() + /// tf the dynamic table type does not match the statically specified custom + /// table type (\a T). + /// + /// \throw NoSuchTable Thrown by remove_table() and rename_table() if there + /// is no table with the specified \a name. + /// + /// \throw TableNameInUse Thrown by add_table() if \a require_unique_name is + /// true and \a name clashes with the name of a preexisting table. Thrown by + /// rename_table() if \a require_unique_name is true and \a new_name clashes + /// with the name of a preexisting table. + /// + /// \throw CrossTableLinkTarget Thrown by remove_table() if the specified + /// table is the target of a link column of a different table. + /// + //@{ + + static const size_t max_table_name_length = 63; + + bool has_table(StringData name) const noexcept; + TableKey find_table(StringData name) const noexcept; + StringData get_table_name(TableKey key) const; + + TableRef get_table(TableKey key); + ConstTableRef get_table(TableKey key) const; + + // Catch some implicit conversions + TableRef get_table(int) = delete; + ConstTableRef get_table(int) const = delete; + + TableRef get_table(StringData name); + ConstTableRef get_table(StringData name) const; + + TableRef add_table(StringData name); + TableRef add_embedded_table(StringData name); + TableRef add_table_with_primary_key(StringData name, DataType pk_type, StringData pk_name, bool nullable = false); + TableRef get_or_add_table(StringData name, bool* was_added = nullptr); + + void remove_table(TableKey key); + void remove_table(StringData name); + + void rename_table(TableKey key, StringData new_name, bool require_unique_name = true); + void rename_table(StringData name, StringData new_name, bool require_unique_name = true); + + //@} + + // Serialization + + /// Write this database to the specified output stream. + /// + /// \param out The destination output stream to write to. + /// + /// \param pad If true, the file is padded to ensure the footer is aligned + /// to the end of a page + void write(std::ostream& out, bool pad = false) const; + + /// Write this database to a new file. It is an error to specify a + /// file that already exists. This is to protect against + /// overwriting a database file that is currently open, which + /// would cause undefined behaviour. + /// + /// \param file A filesystem path. + /// + /// \param encryption_key 32-byte key used to encrypt the database file, + /// or nullptr to disable encryption. + /// + /// \param version If different from 0, the new file will be a full fledged + /// realm file with free list and history info. The version of the commit + /// will be set to the value given here. + /// + /// \throw util::File::AccessError If the file could not be + /// opened. If the reason corresponds to one of the exception + /// types that are derived from util::File::AccessError, the + /// derived exception type is thrown. In particular, + /// util::File::Exists will be thrown if the file exists already. + void write(const std::string& file, const char* encryption_key = nullptr, uint64_t version = 0, + bool write_history = true) const; + + /// Write this database to a memory buffer. + /// + /// Ownership of the returned buffer is transferred to the + /// caller. The memory will have been allocated using + /// std::malloc(). + BinaryData write_to_mem() const; + + /// Commit changes to the attached file. This requires that the + /// attached file is opened in read/write mode. + /// + /// Calling this function on an unattached group, a free-standing + /// group, a group whose attached file is opened in read-only + /// mode, a group that is attached to a memory buffer, or a group + /// that is managed by a shared group, is an error and will result + /// in undefined behavior. + /// + /// Table accesors will remain valid across the commit. Note that + /// this is not the case when working with proper transactions. + void commit(); + + //@{ + /// Some operations on Tables in a Group can cause indirect changes to other + /// fields, including in other Tables in the same Group. Specifically, + /// removing a row will set any links to that row to null, and if it had the + /// last strong links to other rows, will remove those rows. When this + /// happens, The cascade notification handler will be called with a + /// CascadeNotification containing information about what indirect changes + /// will occur, before any changes are made. + /// + /// has_cascade_notification_handler() returns true if and only if there is + /// currently a non-null notification handler registered. + /// + /// set_cascade_notification_handler() replaces the current handler (if any) + /// with the passed in handler. Pass in nullptr to remove the current handler + /// without registering a new one. + /// + /// CascadeNotification contains a vector of rows which will be removed and + /// a vector of links which will be set to null (or removed, for entries in + /// LinkLists). + struct CascadeNotification { + struct row { + /// Key identifying a group-level table. + TableKey table_key; + + /// Key identifying object to be removed. + ObjKey key; + + row() = default; + + row(TableKey tk, ObjKey k) + : table_key(tk) + , key(k) + { + } + bool operator==(const row& r) const noexcept + { + return table_key == r.table_key && key == r.key; + } + bool operator!=(const row& r) const noexcept + { + return !(*this == r); + } + /// Trivial lexicographic order + bool operator<(const row& r) const noexcept + { + return table_key < r.table_key || (table_key == r.table_key && key < r.key); + } + }; + + struct link { + link() = default; + link(TableKey tk, ColKey ck, ObjKey k, ObjKey otk) + : origin_table(tk) + , origin_col_key(ck) + , origin_key(k) + , old_target_key(otk) + { + } + TableKey origin_table; ///< A group-level table. + ColKey origin_col_key; ///< Link column being nullified. + ObjKey origin_key; ///< Row in column being nullified. + /// The target row index which is being removed. Mostly relevant for + /// LinkList (to know which entries are being removed), but also + /// valid for Link. + ObjKey old_target_key; + }; + + /// A sorted list of rows which will be removed by the current operation. + std::vector rows; + + /// An unordered list of links which will be nullified by the current + /// operation. + std::vector links; + }; + + bool has_cascade_notification_handler() const noexcept; + void set_cascade_notification_handler(std::function new_handler) noexcept; + + //@} + + //@{ + /// During sync operation, schema changes may happen at runtime as connected + /// clients update their schema as part of an app update. Since this is a + /// relatively rare event, no attempt is made at limiting the amount of work + /// the handler is required to do to update its information about table and + /// column indices (i.e., all table and column indices must be recalculated). + /// + /// At the time of writing, only additive schema changes may occur in that + /// scenario. + /// + /// has_schema_change_notification_handler() returns true iff there is currently + /// a non-null notification handler registered. + /// + /// set_schema_change_notification_handler() replaces the current handler (if any) + /// with the passed in handler. Pass in nullptr to remove the current handler + /// without registering a new one. + + bool has_schema_change_notification_handler() const noexcept; + void set_schema_change_notification_handler(std::function new_handler) noexcept; + + //@} + + // Conversion + template + void to_json(S& out, size_t link_depth = 0, std::map* renames = nullptr) const; + + /// Compare two groups for equality. Two groups are equal if, and + /// only if, they contain the same tables in the same order, that + /// is, for each table T at index I in one of the groups, there is + /// a table at index I in the other group that is equal to T. + /// Tables are equal if they have the same content and the same table name. + bool operator==(const Group&) const; + + /// Compare two groups for inequality. See operator==(). + bool operator!=(const Group& g) const + { + return !(*this == g); + } + + /// Control of what to include when computing memory usage + enum SizeAggregateControl { + size_of_state = 1, ///< size of tables, indexes, toplevel array + size_of_history = 2, ///< size of the in-file history compartment + size_of_freelists = 4, ///< size of the freelists + size_of_all = 7 + }; + /// Compute the sum of the sizes in number of bytes of all the array nodes + /// that currently make up this group. When this group represents a snapshot + /// in a Realm file (such as during a read transaction via a Transaction + /// instance), this function computes the footprint of that snapshot within + /// the Realm file. + /// + /// If this group accessor is the detached state, this function returns + /// zero. + size_t compute_aggregated_byte_size(SizeAggregateControl ctrl = SizeAggregateControl::size_of_all) const noexcept; + /// Return the size taken up by the current snapshot. This is in contrast to + /// the number returned by DB::get_stats() which will return the + /// size of the last snapshot done in that DB. If the snapshots are + /// identical, the numbers will of course be equal. + size_t get_used_space() const noexcept; + + void verify() const; + void validate_primary_columns(); +#ifdef REALM_DEBUG + void print() const; + void print_free() const; + MemStats get_stats(); + void enable_mem_diagnostics(bool enable = true) + { + m_alloc.enable_debug(enable); + } +#endif + +protected: + virtual Replication* const* get_repl() const + { + return &Table::g_dummy_replication; + } + +private: + static constexpr char g_class_name_prefix[] = "class_"; + static constexpr size_t g_class_name_prefix_len = 6; + + // nullptr, if we're sharing an allocator provided during initialization + std::unique_ptr m_local_alloc; + // in-use allocator. If local, then equal to m_local_alloc. + SlabAlloc& m_alloc; + + int m_file_format_version; + /// `m_top` is the root node (or top array) of the Realm, and has the + /// following layout: + /// + ///
+    ///
+    ///                                                     Introduced in file
+    ///   Slot  Value                                       format version
+    ///   ---------------------------------------------------------------------
+    ///    1st   m_table_names
+    ///    2nd   m_tables
+    ///    3rd   Logical file size
+    ///    4th   GroupWriter::m_free_positions (optional)
+    ///    5th   GroupWriter::m_free_lengths   (optional)
+    ///    6th   GroupWriter::m_free_versions  (optional)
+    ///    7th   Transaction number / version  (optional)
+    ///    8th   History type         (optional)             4
+    ///    9th   History ref          (optional)             4
+    ///   10th   History version      (optional)             7
+    ///   11th   Sync File Id         (optional)            10
+    ///
+    /// 
+ /// + /// The 'History type' slot stores a value of type + /// Replication::HistoryType. The 'History version' slot stores a history + /// schema version as returned by Replication::get_history_schema_version(). + /// + /// The first three entries are mandatory. In files created by + /// Group::write(), none of the optional entries are present and the size of + /// `m_top` is 3. In files updated by Group::commit(), the 4th and 5th entry + /// are present, and the size of `m_top` is 5. In files updated by way of a + /// transaction (Transaction::commit()), the 4th, 5th, 6th, and 7th entry + /// are present, and the size of `m_top` is 7. In files that contain a + /// changeset history, the 8th, 9th, and 10th entry are present. The 11th entry + /// will be present if the file is syncked and the client has received a client + /// file id from the server. + /// + /// When a group accessor is attached to a newly created file or an empty + /// memory buffer where there is no top array yet, `m_top`, `m_tables`, and + /// `m_table_names` will be left in the detached state until the initiation + /// of the first write transaction. In particular, they will remain in the + /// detached state during read transactions that precede the first write + /// transaction. + Array m_top; + Array m_tables; + ArrayStringShort m_table_names; + uint64_t m_last_seen_mapping_version = 0; + + typedef std::vector TableAccessors; + mutable TableAccessors m_table_accessors; + mutable std::mutex m_accessor_mutex; + mutable int m_num_tables = 0; + bool m_attached = false; + bool m_is_writable = true; + const bool m_is_shared; + + std::function m_notify_handler; + std::function m_schema_change_handler; + std::shared_ptr m_metrics; + size_t m_total_rows; + + class TableRecycler : public std::vector { + public: + ~TableRecycler() + { + for (auto t : *this) { + delete t; + } + } + }; + + static constexpr size_t s_table_name_ndx = 0; + static constexpr size_t s_table_refs_ndx = 1; + static constexpr size_t s_file_size_ndx = 2; + static constexpr size_t s_free_pos_ndx = 3; + static constexpr size_t s_free_size_ndx = 4; + static constexpr size_t s_free_version_ndx = 5; + static constexpr size_t s_version_ndx = 6; + static constexpr size_t s_hist_type_ndx = 7; + static constexpr size_t s_hist_ref_ndx = 8; + static constexpr size_t s_hist_version_ndx = 9; + static constexpr size_t s_sync_file_id_ndx = 10; + + static constexpr size_t s_group_max_size = 11; + + // We use the classic approach to construct a FIFO from two LIFO's, + // insertion is done into recycler_1, removal is done from recycler_2, + // and when recycler_2 is empty, recycler_1 is reversed into recycler_2. + // this i O(1) for each entry. + static TableRecycler g_table_recycler_1; + static TableRecycler g_table_recycler_2; + // number of tables held back before being recycled. We hold back recycling + // the latest to increase the probability of detecting race conditions + // without crashing. + const static int g_table_recycling_delay = 100; + static std::mutex g_table_recycler_mutex; + + struct shared_tag { + }; + Group(shared_tag) noexcept; + + Group(SlabAlloc* alloc) noexcept; + void init_array_parents() noexcept; + + void open(ref_type top_ref, const std::string& file_path); + + // If the underlying memory mappings have been extended, this method is used + // to update all the tables' allocator wrappers. The allocator wrappers are + // configure to either allow or deny changes. + void update_allocator_wrappers(bool writable); + + /// If `top_ref` is not zero, attach this group accessor to the specified + /// underlying node structure. If `top_ref` is zero and \a + /// create_group_when_missing is true, create a new node structure that + /// represents an empty group, and attach this group accessor to it. + void attach(ref_type top_ref, bool writable, bool create_group_when_missing); + + /// Detach this group accessor from the underlying node structure. If this + /// group accessors is already in the detached state, this function does + /// nothing (idempotency). + void detach() noexcept; + + /// \param writable Must be set to true when, and only when attaching for a + /// write transaction. + void attach_shared(ref_type new_top_ref, size_t new_file_size, bool writable); + + void create_empty_group(); + void remove_table(size_t table_ndx, TableKey key); + + void reset_free_space_tracking(); + + void remap(size_t new_file_size); + void remap_and_update_refs(ref_type new_top_ref, size_t new_file_size, bool writable); + + /// Recursively update refs stored in all cached array + /// accessors. This includes cached array accessors in any + /// currently attached table accessors. This ensures that the + /// group instance itself, as well as any attached table accessor + /// that exists across Group::commit() will remain valid. This + /// function is not appropriate for use in conjunction with + /// commits via shared group. + void update_refs(ref_type top_ref, size_t old_baseline) noexcept; + + // Overriding method in ArrayParent + void update_child_ref(size_t, ref_type) override; + + // Overriding method in ArrayParent + ref_type get_child_ref(size_t) const noexcept override; + + class TableWriter; + class DefaultTableWriter; + + static void write(std::ostream&, int file_format_version, TableWriter&, bool no_top_array, + bool pad_for_encryption, uint_fast64_t version_number); + + Table* do_get_table(size_t ndx); + const Table* do_get_table(size_t ndx) const; + Table* do_get_table(StringData name); + const Table* do_get_table(StringData name) const; + Table* do_add_table(StringData name, bool is_embedded, bool do_repl = true); + + void create_and_insert_table(TableKey key, StringData name); + Table* create_table_accessor(size_t table_ndx); + void recycle_table_accessor(Table*); + + void detach_table_accessors() noexcept; // Idempotent + + void mark_all_table_accessors() noexcept; + + void write(util::File& file, const char* encryption_key, uint_fast64_t version_number, bool write_history) const; + void write(std::ostream&, bool pad, uint_fast64_t version_numer, bool write_history) const; + + std::shared_ptr get_metrics() const noexcept; + void set_metrics(std::shared_ptr other) noexcept; + void update_num_objects(); + class TransactAdvancer; + void advance_transact(ref_type new_top_ref, size_t new_file_size, _impl::NoCopyInputStream&, bool writable); + void refresh_dirty_accessors(); + void flush_accessors_for_commit(); + + /// \brief The version of the format of the node structure (in file or in + /// memory) in use by Realm objects associated with this group. + /// + /// Every group contains a file format version field, which is returned + /// by this function. The file format version field is set to the file format + /// version specified by the attached file (or attached memory buffer) at the + /// time of attachment and the value is used to determine if a file format + /// upgrade is required. + /// + /// A value of zero means that the file format is not yet decided. This is + /// only possible for empty Realms where top-ref is zero. (When group is created + /// with the unattached_tag). The version number will then be determined in the + /// subsequent call to Group::open. + /// + /// In shared mode (when a Realm file is opened via a DB instance) + /// it can happen that the file format is upgraded asyncronously (via + /// another DB instance), and in that case the file format version + /// field can get out of date, but only for a short while. It is always + /// guaranteed to be, and remain up to date after the opening process completes + /// (when DB::do_open() returns). + /// + /// An empty Realm file (one whose top-ref is zero) may specify a file + /// format version of zero to indicate that the format is not yet + /// decided. In that case the file format version must be changed to a proper + /// before the opening process completes (Group::open() or DB::open()). + /// + /// File format versions: + /// + /// 1 Initial file format version + /// + /// 2 Various changes. + /// + /// 3 Supporting null on string columns broke the file format in following + /// way: Index appends an 'X' character to all strings except the null + /// string, to be able to distinguish between null and empty + /// string. Bumped to 3 because of null support of String columns and + /// because of new format of index. + /// + /// 4 Introduction of optional in-Realm history of changes (additional + /// entries in Group::m_top). Since this change is not forward + /// compatible, the file format version had to be bumped. This change is + /// implemented in a way that achieves backwards compatibility with + /// version 3 (and in turn with version 2). + /// + /// 5 Introduced the new Timestamp column type that replaces DateTime. + /// When opening an older database file, all DateTime columns will be + /// automatically upgraded Timestamp columns. + /// + /// 6 Introduced a new structure for the StringIndex. Moved the commit + /// logs into the Realm file. Changes to the transaction log format + /// including reshuffling instructions. This is the format used in + /// milestone 2.0.0. + /// + /// 7 Introduced "history schema version" as 10th entry in top array. + /// + /// 8 Subtables can now have search index. + /// + /// 9 Replication instruction values shuffled, instr_MoveRow added. + /// + /// 10 Cluster based table layout. Memory mapping changes which require + /// special treatment of large files of preceding versions. + /// + /// 11 Same as 10, but version 11 files will have search index added on + /// string primary key columns. + /// + /// 12 - 19 Room for new file formats in legacy code. + /// + /// 20 New data types: Decimal128 and ObjectId. Embedded tables. + /// + /// IMPORTANT: When introducing a new file format version, be sure to review + /// the file validity checks in Group::open() and DB::do_open, the file + /// format selection logic in + /// Group::get_target_file_format_version_for_session(), and the file format + /// upgrade logic in Group::upgrade_file_format(). + + int get_file_format_version() const noexcept; + void set_file_format_version(int) noexcept; + int get_committed_file_format_version() const noexcept; + + /// The specified history type must be a value of Replication::HistoryType. + static int get_target_file_format_version_for_session(int current_file_format_version, int history_type) noexcept; + + void send_cascade_notification(const CascadeNotification& notification) const; + void send_schema_change_notification() const; + + static void get_version_and_history_info(const Array& top, _impl::History::version_type& version, + int& history_type, int& history_schema_version) noexcept; + static ref_type get_history_ref(const Array& top) noexcept; + void set_history_schema_version(int version); + template + void set_history_parent(Accessor& history_root) noexcept; + void prepare_top_for_history(int history_type, int history_schema_version, uint64_t file_ident); + template + void prepare_history_parent(Accessor& history_root, int history_type, int history_schema_version, + uint64_t file_ident); + static void validate_top_array(const Array& arr, const SlabAlloc& alloc); + + size_t find_table_index(StringData name) const noexcept; + TableKey ndx2key(size_t ndx) const; + size_t key2ndx(TableKey key) const; + size_t key2ndx_checked(TableKey key) const; + void set_size() const noexcept; + std::map get_primary_key_columns_from_pk_table(TableRef pk_table); + void check_table_name_uniqueness(StringData name) + { + if (m_table_names.find_first(name) != not_found) + throw TableNameInUse(); + } + + friend class Table; + friend class GroupWriter; + friend class DB; + friend class _impl::GroupFriend; + friend class _impl::TransactLogConvenientEncoder; + friend class _impl::TransactLogParser; + friend class TrivialReplication; + friend class metrics::QueryInfo; + friend class metrics::Metrics; + friend class Transaction; + friend class TableKeyIterator; + friend class CascadeState; +}; + +class TableKeyIterator { +public: + bool operator!=(const TableKeyIterator& other) + { + return m_pos != other.m_pos; + } + TableKeyIterator& operator++(); + TableKey operator*(); + +private: + friend class TableKeys; + const Group* m_group; + size_t m_pos; + size_t m_index_in_group = 0; + TableKey m_table_key; + + TableKeyIterator(const Group* g, size_t p) + : m_group(g) + , m_pos(p) + { + } + void load_key(); +}; + +class TableKeys { +public: + TableKeys(const Group* g) + : m_iter(g, 0) + { + } + size_t size() const + { + return m_iter.m_group->size(); + } + bool empty() const + { + return size() == 0; + } + TableKey operator[](size_t p) const; + TableKeyIterator begin() const + { + return TableKeyIterator(m_iter.m_group, 0); + } + TableKeyIterator end() const + { + return TableKeyIterator(m_iter.m_group, size()); + } + +private: + mutable TableKeyIterator m_iter; +}; + +// Implementation + +inline TableKeys Group::get_table_keys() const +{ + return TableKeys(this); +} + +inline bool Group::is_attached() const noexcept +{ + return m_attached; +} + +inline bool Group::is_empty() const noexcept +{ + if (!is_attached()) + return false; + return size() == 0; +} + +inline size_t Group::key2ndx(TableKey key) const +{ + size_t idx = key.value & 0xFFFF; + return idx; +} + +inline StringData Group::get_table_name(TableKey key) const +{ + size_t table_ndx = key2ndx_checked(key); + return m_table_names.get(table_ndx); +} + +inline bool Group::has_table(StringData name) const noexcept +{ + size_t ndx = find_table_index(name); + return ndx != not_found; +} + +inline size_t Group::find_table_index(StringData name) const noexcept +{ + if (m_table_names.is_attached()) + return m_table_names.find_first(name); + return not_found; +} + +inline TableKey Group::find_table(StringData name) const noexcept +{ + if (!is_attached()) + return TableKey(); + size_t ndx = find_table_index(name); + return (ndx != npos) ? ndx2key(ndx) : TableKey{}; +} + +inline TableRef Group::get_table(TableKey key) +{ + if (!is_attached()) + throw LogicError(LogicError::detached_accessor); + auto ndx = key2ndx_checked(key); + Table* table = do_get_table(ndx); // Throws + return TableRef(table, table ? table->m_alloc.get_instance_version() : 0); +} + +inline ConstTableRef Group::get_table(TableKey key) const +{ + if (!is_attached()) + throw LogicError(LogicError::detached_accessor); + auto ndx = key2ndx_checked(key); + const Table* table = do_get_table(ndx); // Throws + return ConstTableRef(table, table ? table->m_alloc.get_instance_version() : 0); +} + +inline TableRef Group::get_table(StringData name) +{ + if (!is_attached()) + throw LogicError(LogicError::detached_accessor); + Table* table = do_get_table(name); // Throws + return TableRef(table, table ? table->m_alloc.get_instance_version() : 0); +} + +inline ConstTableRef Group::get_table(StringData name) const +{ + if (!is_attached()) + throw LogicError(LogicError::detached_accessor); + const Table* table = do_get_table(name); // Throws + return ConstTableRef(table, table ? table->m_alloc.get_instance_version() : 0); +} + +inline TableRef Group::add_table(StringData name) +{ + if (!is_attached()) + throw LogicError(LogicError::detached_accessor); + check_table_name_uniqueness(name); + Table* table = do_add_table(name, false); // Throws + return TableRef(table, table->m_alloc.get_instance_version()); +} + +inline TableRef Group::add_embedded_table(StringData name) +{ + if (!is_attached()) + throw LogicError(LogicError::detached_accessor); + check_table_name_uniqueness(name); + Table* table = do_add_table(name, true); // Throws + return TableRef(table, table->m_alloc.get_instance_version()); +} + +inline TableRef Group::get_or_add_table(StringData name, bool* was_added) +{ + if (!is_attached()) + throw LogicError(LogicError::detached_accessor); + auto table = do_get_table(name); + if (was_added) + *was_added = !table; + if (!table) { + table = do_add_table(name, false); + } + return TableRef(table, table->m_alloc.get_instance_version()); +} + +template +void Group::to_json(S& out, size_t link_depth, std::map* renames) const +{ + if (!is_attached()) + throw LogicError(LogicError::detached_accessor); + + std::map renames2; + renames = renames ? renames : &renames2; + + out << "{" << std::endl; + + auto keys = get_table_keys(); + bool first = true; + for (size_t i = 0; i < keys.size(); ++i) { + auto key = keys[i]; + StringData name = get_table_name(key); + std::map& m = *renames; + if (m[name] != "") + name = m[name]; + + ConstTableRef table = get_table(key); + + if (!table->is_embedded()) { + if (!first) + out << ","; + out << "\"" << name << "\""; + out << ":"; + table->to_json(out, link_depth, renames); + out << std::endl; + first = false; + } + } + + out << "}" << std::endl; +} + +inline void Group::init_array_parents() noexcept +{ + m_table_names.set_parent(&m_top, 0); + m_tables.set_parent(&m_top, 1); +} + +inline void Group::update_child_ref(size_t child_ndx, ref_type new_ref) +{ + m_tables.set(child_ndx, new_ref); +} + +inline ref_type Group::get_child_ref(size_t child_ndx) const noexcept +{ + return m_tables.get_as_ref(child_ndx); +} + +inline bool Group::has_cascade_notification_handler() const noexcept +{ + return !!m_notify_handler; +} + +inline void +Group::set_cascade_notification_handler(std::function new_handler) noexcept +{ + m_notify_handler = std::move(new_handler); +} + +inline void Group::send_cascade_notification(const CascadeNotification& notification) const +{ + REALM_ASSERT_DEBUG(m_notify_handler); + m_notify_handler(notification); +} + +inline bool Group::has_schema_change_notification_handler() const noexcept +{ + return !!m_schema_change_handler; +} + +inline void Group::set_schema_change_notification_handler(std::function new_handler) noexcept +{ + m_schema_change_handler = std::move(new_handler); +} + +inline void Group::send_schema_change_notification() const +{ + if (m_schema_change_handler) + m_schema_change_handler(); +} + +inline ref_type Group::get_history_ref(const Array& top) noexcept +{ + bool has_history = (top.is_attached() && top.size() > s_hist_type_ndx); + if (has_history) { + // This function is only used is shared mode (from DB) + REALM_ASSERT(top.size() > s_hist_version_ndx); + return top.get_as_ref(s_hist_ref_ndx); + } + return 0; +} + +inline void Group::set_sync_file_id(uint64_t id) +{ + while (m_top.size() < s_sync_file_id_ndx + 1) + m_top.add(0); + m_top.set(s_sync_file_id_ndx, RefOrTagged::make_tagged(id)); +} + +inline void Group::set_history_schema_version(int version) +{ + while (m_top.size() < s_hist_version_ndx + 1) + m_top.add(0); + m_top.set(s_hist_version_ndx, RefOrTagged::make_tagged(unsigned(version))); // Throws +} + +template +inline void Group::set_history_parent(Accessor& history_root) noexcept +{ + history_root.set_parent(&m_top, 8); +} + +template +void Group::prepare_history_parent(Accessor& history_root, int history_type, int history_schema_version, + uint64_t file_ident) +{ + prepare_top_for_history(history_type, history_schema_version, file_ident); + set_history_parent(history_root); +} + +class Group::TableWriter { +public: + struct HistoryInfo { + ref_type ref = 0; + int type = 0; + int version = 0; + uint64_t sync_file_id = 0; + }; + + virtual ref_type write_names(_impl::OutputStream&) = 0; + virtual ref_type write_tables(_impl::OutputStream&) = 0; + virtual HistoryInfo write_history(_impl::OutputStream&) = 0; + virtual ~TableWriter() noexcept + { + } +}; + +inline const Table* Group::do_get_table(size_t ndx) const +{ + return const_cast(this)->do_get_table(ndx); // Throws +} + +inline const Table* Group::do_get_table(StringData name) const +{ + return const_cast(this)->do_get_table(name); // Throws +} + +inline void Group::reset_free_space_tracking() +{ + // if used whith a shared allocator, free space should never be reset through + // Group, but rather through the proper owner of the allocator, which is the DB object. + REALM_ASSERT(m_local_alloc); + m_alloc.reset_free_space_tracking(); // Throws +} + +inline std::shared_ptr Group::get_metrics() const noexcept +{ + return m_metrics; +} + +inline void Group::set_metrics(std::shared_ptr shared) noexcept +{ + m_metrics = shared; +} + +// The purpose of this class is to give internal access to some, but +// not all of the non-public parts of the Group class. +class _impl::GroupFriend { +public: + static Allocator& get_alloc(const Group& group) noexcept + { + return group.m_alloc; + } + + static ref_type get_top_ref(const Group& group) noexcept + { + return group.m_top.get_ref(); + } + + static ref_type get_history_ref(Allocator& alloc, ref_type top_ref) noexcept + { + Array top(alloc); + if (top_ref != 0) + top.init_from_ref(top_ref); + return Group::get_history_ref(top); + } + + static ref_type get_history_ref(const Group& group) noexcept + { + return Group::get_history_ref(group.m_top); + } + + static int get_file_format_version(const Group& group) noexcept + { + return group.get_file_format_version(); + } + + static void get_version_and_history_info(const Allocator& alloc, ref_type top_ref, + _impl::History::version_type& version, + int& history_type, + int& history_schema_version) noexcept + { + Array top{const_cast(alloc)}; + if (top_ref != 0) + top.init_from_ref(top_ref); + Group::get_version_and_history_info(top, version, history_type, history_schema_version); + } + + static void set_history_schema_version(Group& group, int version) + { + group.set_history_schema_version(version); // Throws + } + + template + static void set_history_parent(Group& group, Accessor& history_root) noexcept + { + group.set_history_parent(history_root); + } + + template + static void prepare_history_parent(Group& group, Accessor& history_root, int history_type, + int history_schema_version, uint64_t file_ident = 0) + { + group.prepare_history_parent(history_root, history_type, history_schema_version, file_ident); // Throws + } + + // This is used by upgrade functions in Sync + static Table* get_table_by_ndx(Group& group, size_t ndx) + { + return group.do_get_table(ndx); + } + + static int get_target_file_format_version_for_session(int current_file_format_version, int history_type) noexcept + { + return Group::get_target_file_format_version_for_session(current_file_format_version, history_type); + } +}; + + +class CascadeState { +public: + enum class Mode { + /// If we remove the last link to an object, delete that object, even if + /// the link we removed was not a strong link + All, + /// If we remove the last link to an object, delete that object only if + /// the link we removed was a strong link + Strong, + /// Never delete objects due to removing links + None + }; + + struct Link { + TableKey origin_table; ///< A group-level table. + ColKey origin_col_key; ///< Link column being nullified. + ObjKey origin_key; ///< Row in column being nullified. + /// The target row index which is being removed. Mostly relevant for + /// LinkList (to know which entries are being removed), but also + /// valid for Link. + ObjKey old_target_key; + }; + + CascadeState(Mode mode = Mode::Strong, Group* g = nullptr) noexcept + : m_mode(mode) + , m_group(g) + { + } + + /// Indicate which links to take action on. Either all, strong or none. + Mode m_mode; + + std::vector> m_to_be_deleted; + std::vector m_to_be_nullified; + Group* m_group = nullptr; + + bool notification_handler() const noexcept + { + return m_group && m_group->has_cascade_notification_handler(); + } + + void send_notifications(Group::CascadeNotification& notifications) const + { + REALM_ASSERT_DEBUG(notification_handler()); + m_group->send_cascade_notification(notifications); + } + + bool enqueue_for_cascade(const Obj& target_obj, bool link_is_strong, bool last_removed) + { + // Check if the object should be cascade deleted + if (m_mode == Mode::None || !last_removed) { + return false; + } + if (m_mode == Mode::All || link_is_strong) { + bool has_backlinks = target_obj.has_backlinks(m_mode == Mode::Strong); + if (!has_backlinks) { + // Object has no more backlinks - add to list for deletion + m_to_be_deleted.emplace_back(target_obj.get_table()->get_key(), target_obj.get_key()); + return true; + } + } + return false; + } + + void enqueue_for_nullification(Table& src_table, ColKey src_col_key, ObjKey origin_key, ObjKey target_key) + { + // Nullify immediately if we don't need to send cascade notifications + if (!notification_handler()) { + Obj obj = src_table.get_object(origin_key); + obj.nullify_link(src_col_key, target_key); + return; + } + + // Otherwise enqueue it + m_to_be_nullified.push_back({src_table.get_key(), src_col_key, origin_key, target_key}); + } + + void send_notifications() + { + if (!notification_handler()) { + return; + } + Group::CascadeNotification notification; + for (auto& o : m_to_be_deleted) + notification.rows.emplace_back(o.first, o.second); + for (auto& l : m_to_be_nullified) + notification.links.emplace_back(l.origin_table, l.origin_col_key, l.origin_key, l.old_target_key); + send_notifications(notification); + } +}; + +} // namespace realm + +#endif // REALM_GROUP_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/group_writer.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/group_writer.hpp new file mode 100644 index 0000000..95adedc --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/group_writer.hpp @@ -0,0 +1,201 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_GROUP_WRITER_HPP +#define REALM_GROUP_WRITER_HPP + +#include // unint8_t etc +#include +#include + +#include +#include +#include +#include +#include + + +namespace realm { + +// Pre-declarations +class Group; +class SlabAlloc; + + +/// This class is not supposed to be reused for multiple write sessions. In +/// particular, do not reuse it in case any of the functions throw. +/// +/// FIXME: Move this class to namespace realm::_impl and to subdir src/realm/impl. +class GroupWriter : public _impl::ArrayWriterBase { +public: + // For groups in transactional mode (Group::m_is_shared), this constructor + // must be called while a write transaction is in progress. + // + // The constructor adds free-space tracking information to the specified + // group, if it is not already present (4th and 5th entry in + // Group::m_top). If the specified group is in transactional mode + // (Group::m_is_shared), the constructor also adds version tracking + // information to the group, if it is not already present (6th and 7th entry + // in Group::m_top). + using Durability = DBOptions::Durability; + GroupWriter(Group&, Durability dura = Durability::Full); + ~GroupWriter(); + + void set_versions(uint64_t current, uint64_t read_lock) noexcept; + + /// Write all changed array nodes into free space. + /// + /// Returns the new top ref. When in full durability mode, call + /// commit() with the returned top ref. + ref_type write_group(); + + /// Flush changes to physical medium, then write the new top ref + /// to the file header, then flush again. Pass the top ref + /// returned by write_group(). + void commit(ref_type new_top_ref); + + size_t get_file_size() const noexcept; + + ref_type write_array(const char*, size_t, uint32_t) override; + +#ifdef REALM_DEBUG + void dump(); +#endif + + size_t get_free_space_size() const + { + return m_free_space_size; + } + + size_t get_locked_space_size() const + { + return m_locked_space_size; + } + +private: + class MapWindow; + Group& m_group; + SlabAlloc& m_alloc; + Array m_free_positions; // 4th slot in Group::m_top + Array m_free_lengths; // 5th slot in Group::m_top + Array m_free_versions; // 6th slot in Group::m_top + uint64_t m_current_version = 0; + uint64_t m_readlock_version; + size_t m_window_alignment; + size_t m_free_space_size = 0; + size_t m_locked_space_size = 0; + Durability m_durability; + + struct FreeSpaceEntry { + FreeSpaceEntry(size_t r, size_t s, uint64_t v) + : ref(r) + , size(s) + , released_at_version(v) + { + } + size_t ref; + size_t size; + uint64_t released_at_version; + }; + class FreeList : public std::vector { + public: + FreeList() = default; + // Merge adjacent chunks + void merge_adjacent_entries_in_freelist(); + // Copy free space entries to structure where entries are sorted by size + void move_free_in_file_to_size_map(std::multimap& size_map); + }; + // m_free_in_file; + std::vector m_not_free_in_file; + std::multimap m_size_map; + using FreeListElement = std::multimap::iterator; + + void read_in_freelist(); + size_t recreate_freelist(size_t reserve_pos); + // Currently cached memory mappings. We keep as many as 16 1MB windows + // open for writing. The allocator will favor sequential allocation + // from a modest number of windows, depending upon fragmentation, so + // 16 windows should be more than enough. If more than 16 windows are + // needed, the least recently used is sync'ed and closed to make room + // for a new one. The windows are kept in MRU (most recently used) order. + const static int num_map_windows = 16; + std::vector> m_map_windows; + + // Get a suitable memory mapping for later access: + // potentially adding it to the cache, potentially closing + // the least recently used and sync'ing it to disk + MapWindow* get_window(ref_type start_ref, size_t size); + + // Sync all cached memory mappings + void sync_all_mappings(); + + /// Allocate a chunk of free space of the specified size. The + /// specified size must be 8-byte aligned. Extend the file if + /// required. The returned chunk is removed from the amount of + /// remaing free space. The returned chunk is guaranteed to be + /// within a single contiguous memory mapping. + /// + /// \return The position within the database file of the allocated + /// chunk. + size_t get_free_space(size_t size); + + /// Find a block of free space that is at least as big as the + /// specified size and which will allow an allocation that is mapped + /// inside a contiguous address range. The specified size does not + /// need to be 8-byte aligned. Extend the file if required. + /// The returned chunk is not removed from the amount of remaing + /// free space. + /// + /// \return A pair (`chunk_ndx`, `chunk_size`) where `chunk_ndx` + /// is the index of a chunk whose size is at least the requestd + /// size, and `chunk_size` is the size of that chunk. + FreeListElement reserve_free_space(size_t size); + + FreeListElement search_free_space_in_free_list_element(FreeListElement element, size_t size); + + /// Search only a range of the free list for a block as big as the + /// specified size. Return a pair with index and size of the found chunk. + FreeListElement search_free_space_in_part_of_freelist(size_t size); + + /// Extend the file to ensure that a chunk of free space of the + /// specified size is available. The specified size does not need + /// to be 8-byte aligned. This function guarantees that it will + /// add at most one entry to the free-lists. + /// + /// \return A pair (`chunk_ndx`, `chunk_size`) where `chunk_ndx` + /// is the index of a chunk whose size is at least the requestd + /// size, and `chunk_size` is the size of that chunk. + FreeListElement extend_free_space(size_t requested_size); + + void write_array_at(MapWindow* window, ref_type, const char* data, size_t size); + FreeListElement split_freelist_chunk(FreeListElement, size_t alloc_pos); +}; + + +// Implementation: + +inline void GroupWriter::set_versions(uint64_t current, uint64_t read_lock) noexcept +{ + REALM_ASSERT(read_lock <= current); + m_current_version = current; + m_readlock_version = read_lock; +} + +} // namespace realm + +#endif // REALM_GROUP_WRITER_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/handover_defs.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/handover_defs.hpp new file mode 100644 index 0000000..ad8bfba --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/handover_defs.hpp @@ -0,0 +1,34 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_HANDOVER_DEFS +#define REALM_HANDOVER_DEFS + +#include +#include + +#include + +namespace realm { + +enum class PayloadPolicy { Copy, Stay, Move }; + + +} // end namespace Realm + +#endif diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/history.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/history.hpp new file mode 100644 index 0000000..9710d0b --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/history.hpp @@ -0,0 +1,35 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_HISTORY_HPP +#define REALM_HISTORY_HPP + +#include +#include + +#include + + +namespace realm { + +std::unique_ptr make_in_realm_history(const std::string& realm_path); + +} // namespace realm + + +#endif // REALM_HISTORY_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/impl/array_writer.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/impl/array_writer.hpp new file mode 100644 index 0000000..f039ad5 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/impl/array_writer.hpp @@ -0,0 +1,44 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_ARRAY_WRITER_HPP +#define REALM_ARRAY_WRITER_HPP + +#include + +namespace realm { +namespace _impl { + +class ArrayWriterBase { +public: + virtual ~ArrayWriterBase() + { + } + + /// Write the specified array data and its checksum into free + /// space. + /// + /// Returns the ref (position in the target stream) of the written copy of + /// the specified array data. + virtual ref_type write_array(const char* data, size_t size, uint32_t checksum) = 0; +}; + +} // namespace impl_ +} // namespace realm + +#endif // REALM_ARRAY_WRITER_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/impl/clamped_hex_dump.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/impl/clamped_hex_dump.hpp new file mode 100644 index 0000000..0d5c0a7 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/impl/clamped_hex_dump.hpp @@ -0,0 +1,30 @@ + +#ifndef REALM_IMPL_CLAMPED_HEX_DUMP_HPP +#define REALM_IMPL_CLAMPED_HEX_DUMP_HPP + +#include +#include + +namespace realm { +namespace _impl { + +/// Limit the amount of dumped data to 1024 bytes. For use in connection with +/// logging. +inline std::string clamped_hex_dump(BinaryData blob, std::size_t max_size = 1024) +{ + bool was_clipped = false; + std::size_t size_2 = blob.size(); + if (size_2 > max_size) { + size_2 = max_size; + was_clipped = true; + } + std::string str = util::hex_dump(blob.data(), size_2); // Throws + if (was_clipped) + str += "..."; // Throws + return str; +} + +} // namespace _impl +} // namespace realm + +#endif // REALM_IMPL_CLAMPED_HEX_DUMP_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/impl/clock.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/impl/clock.hpp new file mode 100644 index 0000000..8c36078 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/impl/clock.hpp @@ -0,0 +1,33 @@ + +#ifndef REALM_IMPL_CLOCK_HPP +#define REALM_IMPL_CLOCK_HPP + +#include +#include + +#include + +namespace realm { +namespace _impl { + +inline sync::milliseconds_type realtime_clock_now() noexcept +{ + using clock = std::chrono::system_clock; + auto time_since_epoch = clock::now().time_since_epoch(); + auto millis_since_epoch = std::chrono::duration_cast(time_since_epoch).count(); + return sync::milliseconds_type(millis_since_epoch); +} + + +inline sync::milliseconds_type monotonic_clock_now() noexcept +{ + using clock = std::chrono::steady_clock; + auto time_since_epoch = clock::now().time_since_epoch(); + auto millis_since_epoch = std::chrono::duration_cast(time_since_epoch).count(); + return sync::milliseconds_type(millis_since_epoch); +} + +} // namespace _impl +} // namespace realm + +#endif // REALM_IMPL_CLOCK_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/impl/cont_transact_hist.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/impl/cont_transact_hist.hpp new file mode 100644 index 0000000..7e6c1e0 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/impl/cont_transact_hist.hpp @@ -0,0 +1,140 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_IMPL_CONT_TRANSACT_HIST_HPP +#define REALM_IMPL_CONT_TRANSACT_HIST_HPP + +#include +#include + +#include +#include + +namespace realm { + +class Group; +class BinaryIterator; + +namespace _impl { + +/// Read-only access to history of changesets as needed to enable continuous +/// transactions. +class History { +public: + using version_type = VersionID::version_type; + + virtual ~History() noexcept {} + + /// May be called during any transaction + /// + /// It is a precondition for calls to this function that the reader view is + /// updated - that is, the mapping is updated to provide full visibility to + /// the file. + /// + virtual void update_from_ref_and_version(ref_type, version_type) = 0; + virtual void update_from_parent(version_type version) = 0; + + /// Get all changesets between the specified versions. References to those + /// changesets will be made available in successive entries of `buffer`. The + /// number of retrieved changesets is exactly `end_version - + /// begin_version`. If this number is greater than zero, the changeset made + /// available in `buffer[0]` is the one that brought the database from + /// `begin_version` to `begin_version + 1`. + /// + /// It is an error to specify a version (for \a begin_version or \a + /// end_version) that is outside the range [V,W] where V is the version that + /// immediately precedes the first changeset available in the history as the + /// history appears in the **latest** available snapshot, and W is the + /// version that immediately succeeds the last changeset available in the + /// history as the history appears in the snapshot bound to the **current** + /// transaction. This restriction is necessary to allow for different kinds + /// of implementations of the history (separate standalone history or + /// history as part of versioned Realm state). + /// + /// The callee retains ownership of the memory referenced by those entries, + /// i.e., the memory referenced by `buffer[i].changeset` is **not** handed + /// over to the caller. + /// + /// This function may be called only during a transaction (prior to + /// initiation of commit operation), and only after a successful invocation + /// of update_early_from_top_ref(). In that case, the caller may assume that + /// the memory references stay valid for the remainder of the transaction + /// (up until initiation of the commit operation). + virtual void get_changesets(version_type begin_version, version_type end_version, BinaryIterator* buffer) const + noexcept = 0; + + /// \brief Specify the version of the oldest bound snapshot. + /// + /// This function must be called by the associated SharedGroup object during + /// each successfully committed write transaction. It must be called before + /// the transaction is finalized (Replication::finalize_commit()) or aborted + /// (Replication::abort_transact()), but after the initiation of the commit + /// operation (Replication::prepare_commit()). This allows history + /// implementations to add new history entries before trimming off old ones, + /// and this, in turn, guarantees that the history never becomes empty, + /// except in the initial empty Realm state. + /// + /// The caller must pass the version (\a version) of the oldest snapshot + /// that is currently (or was recently) bound via a transaction of the + /// current session. This gives the history implementation an opportunity to + /// trim off leading (early) history entries. + /// + /// Since this function must be called during a write transaction, there + /// will always be at least one snapshot that is currently bound via a + /// transaction. + /// + /// The caller must guarantee that the passed version (\a version) is less + /// than or equal to `begin_version` in all future invocations of + /// get_changesets(). + /// + /// The caller is allowed to pass a version that is less than the version + /// passed in a preceding invocation. + /// + /// This function should be called as late as possible, to maximize the + /// trimming opportunity, but at a time where the write transaction is still + /// open for additional modifications. This is necessary because some types + /// of histories are stored inside the Realm file. + virtual void set_oldest_bound_version(version_type version) = 0; + + virtual void verify() const = 0; + + virtual void set_group(Group* group, bool updated = false) + { + m_group = group; + m_updated = updated; + } + + void ensure_updated(version_type version) const + { + if (!m_updated) { + const_cast(this)->update_from_parent(version); + m_updated = true; + } + } + +protected: + Group* m_group = nullptr; + +private: + mutable bool m_updated = false; +}; + +} // namespace _impl +} // namespace realm + +#endif // REALM_IMPL_CONTINUOUS_TRANSACTIONS_HISTORY_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/impl/destroy_guard.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/impl/destroy_guard.hpp new file mode 100644 index 0000000..f5b5e37 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/impl/destroy_guard.hpp @@ -0,0 +1,237 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_IMPL_DESTROY_GUARD_HPP +#define REALM_IMPL_DESTROY_GUARD_HPP + +#include +#include + +namespace realm { +namespace _impl { + + +/// Calls `ptr->destroy()` if the guarded pointer (`ptr`) is not null +/// when the guard is destroyed. For arrays (`T` = `Array`) this means +/// that the array is destroyed in a shallow fashion. See +/// `DeepArrayDestroyGuard` for an alternative. +template +class DestroyGuard { +public: + DestroyGuard() noexcept; + + DestroyGuard(T*) noexcept; + + ~DestroyGuard() noexcept; + + // Default implementations of copy/assign can trigger multiple destructions + DestroyGuard(const DestroyGuard&) = delete; + DestroyGuard& operator=(const DestroyGuard&) = delete; + + void reset(T*) noexcept; + + T* get() const noexcept; + + T* release() noexcept; + +private: + T* m_ptr; +}; + +using ShallowArrayDestroyGuard = DestroyGuard; + + +/// Calls `ptr->destroy_deep()` if the guarded Array pointer (`ptr`) +/// is not null when the guard is destroyed. +class DeepArrayDestroyGuard { +public: + DeepArrayDestroyGuard() noexcept; + + DeepArrayDestroyGuard(Array*) noexcept; + + ~DeepArrayDestroyGuard() noexcept; + + // Default implementations of copy/assign can trigger multiple destructions + DeepArrayDestroyGuard(const DeepArrayDestroyGuard&) = delete; + DeepArrayDestroyGuard& operator=(const DeepArrayDestroyGuard&) = delete; + + void reset(Array*) noexcept; + + Array* get() const noexcept; + + Array* release() noexcept; + +private: + Array* m_ptr; +}; + + +/// Calls `Array::destroy_deep(ref, alloc)` if the guarded 'ref' +/// (`ref`) is not zero when the guard is destroyed. +class DeepArrayRefDestroyGuard { +public: + DeepArrayRefDestroyGuard(Allocator&) noexcept; + + DeepArrayRefDestroyGuard(ref_type, Allocator&) noexcept; + + ~DeepArrayRefDestroyGuard() noexcept; + + // Default implementations of copy/assign can trigger multiple destructions + DeepArrayRefDestroyGuard(const DeepArrayRefDestroyGuard&) = delete; + DeepArrayRefDestroyGuard& operator=(const DeepArrayRefDestroyGuard&) = delete; + + void reset(ref_type) noexcept; + + ref_type get() const noexcept; + + ref_type release() noexcept; + +private: + ref_type m_ref; + Allocator& m_alloc; +}; + + +// Implementation: + +// DestroyGuard + +template +inline DestroyGuard::DestroyGuard() noexcept + : m_ptr(nullptr) +{ +} + +template +inline DestroyGuard::DestroyGuard(T* ptr) noexcept + : m_ptr(ptr) +{ +} + +template +inline DestroyGuard::~DestroyGuard() noexcept +{ + if (m_ptr) + m_ptr->destroy(); +} + +template +inline void DestroyGuard::reset(T* ptr) noexcept +{ + if (m_ptr) + m_ptr->destroy(); + m_ptr = ptr; +} + +template +inline T* DestroyGuard::get() const noexcept +{ + return m_ptr; +} + +template +inline T* DestroyGuard::release() noexcept +{ + T* ptr = m_ptr; + m_ptr = nullptr; + return ptr; +} + + +// DeepArrayDestroyGuard + +inline DeepArrayDestroyGuard::DeepArrayDestroyGuard() noexcept + : m_ptr(nullptr) +{ +} + +inline DeepArrayDestroyGuard::DeepArrayDestroyGuard(Array* ptr) noexcept + : m_ptr(ptr) +{ +} + +inline DeepArrayDestroyGuard::~DeepArrayDestroyGuard() noexcept +{ + if (m_ptr) + m_ptr->destroy_deep(); +} + +inline void DeepArrayDestroyGuard::reset(Array* ptr) noexcept +{ + if (m_ptr) + m_ptr->destroy_deep(); + m_ptr = ptr; +} + +inline Array* DeepArrayDestroyGuard::get() const noexcept +{ + return m_ptr; +} + +inline Array* DeepArrayDestroyGuard::release() noexcept +{ + Array* ptr = m_ptr; + m_ptr = nullptr; + return ptr; +} + + +// DeepArrayRefDestroyGuard + +inline DeepArrayRefDestroyGuard::DeepArrayRefDestroyGuard(Allocator& alloc) noexcept + : m_ref(0) + , m_alloc(alloc) +{ +} + +inline DeepArrayRefDestroyGuard::DeepArrayRefDestroyGuard(ref_type ref, Allocator& alloc) noexcept + : m_ref(ref) + , m_alloc(alloc) +{ +} + +inline DeepArrayRefDestroyGuard::~DeepArrayRefDestroyGuard() noexcept +{ + if (m_ref) + Array::destroy_deep(m_ref, m_alloc); +} + +inline void DeepArrayRefDestroyGuard::reset(ref_type ref) noexcept +{ + if (m_ref) + Array::destroy_deep(m_ref, m_alloc); + m_ref = ref; +} + +inline ref_type DeepArrayRefDestroyGuard::get() const noexcept +{ + return m_ref; +} + +inline ref_type DeepArrayRefDestroyGuard::release() noexcept +{ + ref_type ref = m_ref; + m_ref = 0; + return ref; +} + + +} // namespace _impl +} // namespace realm + +#endif // REALM_IMPL_DESTROY_GUARD_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/impl/input_stream.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/impl/input_stream.hpp new file mode 100644 index 0000000..bc50140 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/impl/input_stream.hpp @@ -0,0 +1,256 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_IMPL_INPUT_STREAM_HPP +#define REALM_IMPL_INPUT_STREAM_HPP + +#include + +#include +#include +#include +#include + + +namespace realm { +namespace _impl { + + +class InputStream { +public: + /// Read bytes from this input stream and place them in the specified + /// buffer. The returned value is the actual number of bytes that were read, + /// and this is some number `n` such that `n <= min(size, m)` where `m` is + /// the number of bytes that could have been read from this stream before + /// reaching its end. Also, `n` cannot be zero unless `m` or `size` is + /// zero. The intention is that `size` should be non-zero, a the return + /// value used as the end-of-input indicator. + /// + /// Implementations are only allowed to block (put the calling thread to + /// sleep) up until the point in time where the first byte can be made + /// availble. + virtual size_t read(char* buffer, size_t size) = 0; + + virtual ~InputStream() noexcept + { + } +}; + + +class SimpleInputStream : public InputStream { +public: + SimpleInputStream(const char* data, size_t size) noexcept + : m_ptr(data) + , m_end(data + size) + { + } + size_t read(char* buffer, size_t size) override + { + size_t n = std::min(size, size_t(m_end - m_ptr)); + const char* begin = m_ptr; + m_ptr += n; + realm::safe_copy_n(begin, n, buffer); + return n; + } + +private: + const char* m_ptr; + const char* const m_end; +}; + + +class NoCopyInputStream { +public: + /// \return if any bytes was read. + /// A value of false indicates end-of-input. + /// If return value is true, \a begin and \a end are + /// updated to reflect the start and limit of a + /// contiguous memory chunk. + virtual bool next_block(const char*& begin, const char*& end) = 0; + + virtual ~NoCopyInputStream() noexcept + { + } +}; + + +class NoCopyInputStreamAdaptor : public NoCopyInputStream { +public: + NoCopyInputStreamAdaptor(InputStream& in, char* buffer, size_t buffer_size) noexcept + : m_in(in) + , m_buffer(buffer) + , m_buffer_size(buffer_size) + { + } + bool next_block(const char*& begin, const char*& end) override + { + size_t n = m_in.read(m_buffer, m_buffer_size); + begin = m_buffer; + end = m_buffer + n; + return n; + } + +private: + InputStream& m_in; + char* m_buffer; + size_t m_buffer_size; +}; + + +class SimpleNoCopyInputStream : public NoCopyInputStream { +public: + SimpleNoCopyInputStream(const char* data, size_t size) + : m_data(data) + , m_size(size) + { + } + + bool next_block(const char*& begin, const char*& end) override + { + if (m_size == 0) + return 0; + size_t size = m_size; + begin = m_data; + end = m_data + size; + m_size = 0; + return size; + } + +private: + const char* m_data; + size_t m_size; +}; + +class MultiLogNoCopyInputStream : public NoCopyInputStream { +public: + MultiLogNoCopyInputStream(const BinaryData* logs_begin, const BinaryData* logs_end) + : m_logs_begin(logs_begin) + , m_logs_end(logs_end) + { + if (m_logs_begin != m_logs_end) + m_curr_buf_remaining_size = m_logs_begin->size(); + } + + size_t read(char* buffer, size_t size) + { + if (m_logs_begin == m_logs_end) + return 0; + for (;;) { + if (m_curr_buf_remaining_size > 0) { + size_t offset = m_logs_begin->size() - m_curr_buf_remaining_size; + const char* data = m_logs_begin->data() + offset; + size_t size_2 = std::min(m_curr_buf_remaining_size, size); + m_curr_buf_remaining_size -= size_2; + // FIXME: Eliminate the need for copying by changing the API of + // Replication::InputStream such that blocks can be handed over + // without copying. This is a straight forward change, but the + // result is going to be more complicated and less conventional. + realm::safe_copy_n(data, size_2, buffer); + return size_2; + } + + ++m_logs_begin; + if (m_logs_begin == m_logs_end) + return 0; + m_curr_buf_remaining_size = m_logs_begin->size(); + } + } + + bool next_block(const char*& begin, const char*& end) override + { + while (m_logs_begin < m_logs_end) { + size_t result = m_logs_begin->size(); + const char* data = m_logs_begin->data(); + m_logs_begin++; + if (result == 0) + continue; // skip empty blocks + begin = data; + end = data + result; + return result; + } + return 0; + } + +private: + const BinaryData* m_logs_begin; + const BinaryData* m_logs_end; + size_t m_curr_buf_remaining_size; +}; + + +class ChangesetInputStream : public NoCopyInputStream { +public: + using version_type = History::version_type; + static constexpr unsigned NB_BUFFERS = 8; + + ChangesetInputStream(History& hist, version_type begin_version, version_type end_version) + : m_history(hist) + , m_begin_version(begin_version) + , m_end_version(end_version) + { + get_changeset(); + } + + bool next_block(const char*& begin, const char*& end) override + { + while (m_valid) { + BinaryData actual = m_changesets_begin->get_next(); + + if (actual.size() > 0) { + begin = actual.data(); + end = actual.data() + actual.size(); + return true; + } + + m_changesets_begin++; + + if (REALM_UNLIKELY(m_changesets_begin == m_changesets_end)) { + get_changeset(); + } + } + return false; // End of input + } + +private: + History& m_history; + version_type m_begin_version, m_end_version; + BinaryIterator m_changesets[NB_BUFFERS]; // Buffer + BinaryIterator* m_changesets_begin = nullptr; + BinaryIterator* m_changesets_end = nullptr; + bool m_valid; + + void get_changeset() + { + auto versions_to_get = m_end_version - m_begin_version; + m_valid = versions_to_get > 0; + if (m_valid) { + if (versions_to_get > NB_BUFFERS) + versions_to_get = NB_BUFFERS; + version_type end_version = m_begin_version + versions_to_get; + m_history.get_changesets(m_begin_version, end_version, m_changesets); + m_begin_version = end_version; + m_changesets_begin = m_changesets; + m_changesets_end = m_changesets_begin + versions_to_get; + } + } +}; + +} // namespace _impl +} // namespace realm + +#endif // REALM_IMPL_INPUT_STREAM_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/impl/output_stream.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/impl/output_stream.hpp new file mode 100644 index 0000000..1d022cd --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/impl/output_stream.hpp @@ -0,0 +1,75 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_IMPL_OUTPUT_STREAM_HPP +#define REALM_IMPL_OUTPUT_STREAM_HPP + +#include +#include + +#include + +#include + +#include + +namespace realm { +namespace _impl { + + +class OutputStream : public ArrayWriterBase { +public: + OutputStream(std::ostream&); + ~OutputStream() noexcept; + + ref_type get_ref_of_next_array() const noexcept; + + void write(const char* data, size_t size); + + ref_type write_array(const char* data, size_t size, uint32_t checksum) override; + +private: + ref_type m_next_ref; + std::ostream& m_out; + + void do_write(const char* data, size_t size); +}; + + +// Implementation: + +inline OutputStream::OutputStream(std::ostream& out) + : m_next_ref(0) + , m_out(out) +{ +} + +inline OutputStream::~OutputStream() noexcept +{ +} + +inline size_t OutputStream::get_ref_of_next_array() const noexcept +{ + return m_next_ref; +} + + +} // namespace _impl +} // namespace realm + +#endif // REALM_IMPL_OUTPUT_STREAM_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/impl/simulated_failure.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/impl/simulated_failure.hpp new file mode 100644 index 0000000..4958151 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/impl/simulated_failure.hpp @@ -0,0 +1,228 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_IMPL_SIMULATED_FAILURE_HPP +#define REALM_IMPL_SIMULATED_FAILURE_HPP + +#include +#include + +#include + +#ifdef REALM_DEBUG +#define REALM_ENABLE_SIMULATED_FAILURE +#endif + +namespace realm { +namespace _impl { + +class SimulatedFailure : public std::system_error { +public: + enum FailureType { + generic, + slab_alloc__reset_free_space_tracking, + slab_alloc__remap, + shared_group__grow_reader_mapping, + sync_client__read_head, + sync_server__read_head, + _num_failure_types + }; + + class OneShotPrimeGuard; + class RandomPrimeGuard; + + /// Prime the specified failure type on the calling thread for triggering + /// once. + static void prime_one_shot(FailureType); + + /// Prime the specified failure type on the calling thread for triggering + /// randomly \a n out of \a m times. + static void prime_random(FailureType, int n, int m, uint_fast64_t seed = 0); + + /// Unprime the specified failure type on the calling thread. + static void unprime(FailureType) noexcept; + + /// Returns true according to the mode of priming of the specified failure + /// type on the calling thread, but only if REALM_ENABLE_SIMULATED_FAILURE + /// was defined during compilation. If REALM_ENABLE_SIMULATED_FAILURE was + /// not defined, this function always return false. + static bool check_trigger(FailureType) noexcept; + + /// The specified error code is set to `make_error_code(failure_type)` if + /// check_trigger() returns true. Otherwise it is set to + /// `std::error_code()`. Returns a copy of the updated error code. + static std::error_code trigger(FailureType failure_type, std::error_code&) noexcept; + + /// Throws SimulatedFailure if check_trigger() returns true. The exception + /// will be constructed with an error code equal to + /// `make_error_code(failure_type)`. + static void trigger(FailureType failure_type); + + /// Returns true when, and only when REALM_ENABLE_SIMULATED_FAILURE was + /// defined during compilation. + static constexpr bool is_enabled(); + + SimulatedFailure(std::error_code); + +private: +#ifdef REALM_ENABLE_SIMULATED_FAILURE + static void do_prime_one_shot(FailureType); + static void do_prime_random(FailureType, int n, int m, uint_fast64_t seed); + static void do_unprime(FailureType) noexcept; + static bool do_check_trigger(FailureType) noexcept; +#endif +}; + +std::error_code make_error_code(SimulatedFailure::FailureType) noexcept; + +class SimulatedFailure::OneShotPrimeGuard { +public: + OneShotPrimeGuard(FailureType); + ~OneShotPrimeGuard() noexcept; + +private: + const FailureType m_type; +}; + + +class SimulatedFailure::RandomPrimeGuard { +public: + RandomPrimeGuard(FailureType, int n, int m, uint_fast64_t seed = 0); + ~RandomPrimeGuard() noexcept; + +private: + const FailureType m_type; +}; + +std::error_code make_error_code(SimulatedFailure::FailureType) noexcept; + +} // namespace _impl +} // namespace realm + +namespace std { + +template<> struct is_error_code_enum { + static const bool value = true; +}; + +} // namespace std + +namespace realm { +namespace _impl { + + +// Implementation + +inline void SimulatedFailure::prime_one_shot(FailureType failure_type) +{ +#ifdef REALM_ENABLE_SIMULATED_FAILURE + do_prime_one_shot(failure_type); +#else + static_cast(failure_type); +#endif +} + +inline void SimulatedFailure::prime_random(FailureType failure_type, int n, int m, uint_fast64_t seed) +{ +#ifdef REALM_ENABLE_SIMULATED_FAILURE + do_prime_random(failure_type, n, m, seed); +#else + static_cast(failure_type); + static_cast(n); + static_cast(m); + static_cast(seed); +#endif +} + +inline void SimulatedFailure::unprime(FailureType failure_type) noexcept +{ +#ifdef REALM_ENABLE_SIMULATED_FAILURE + do_unprime(failure_type); +#else + static_cast(failure_type); +#endif +} + +inline bool SimulatedFailure::check_trigger(FailureType failure_type) noexcept +{ +#ifdef REALM_ENABLE_SIMULATED_FAILURE + return do_check_trigger(failure_type); +#else + static_cast(failure_type); + return false; +#endif +} + +inline std::error_code SimulatedFailure::trigger(FailureType failure_type, std::error_code& ec) noexcept +{ + if (check_trigger(failure_type)) { + ec = make_error_code(failure_type); + } + else { + ec = std::error_code(); + } + return ec; +} + +inline void SimulatedFailure::trigger(FailureType failure_type) +{ + if (check_trigger(failure_type)) + throw SimulatedFailure(make_error_code(failure_type)); +} + +inline constexpr bool SimulatedFailure::is_enabled() +{ +#ifdef REALM_ENABLE_SIMULATED_FAILURE + return true; +#else + return false; +#endif +} + +inline SimulatedFailure::SimulatedFailure(std::error_code ec) + : std::system_error(ec) +{ +} + +inline SimulatedFailure::OneShotPrimeGuard::OneShotPrimeGuard(FailureType failure_type) + : m_type(failure_type) +{ + prime_one_shot(m_type); +} + +inline SimulatedFailure::OneShotPrimeGuard::~OneShotPrimeGuard() noexcept +{ + unprime(m_type); +} + +inline SimulatedFailure::RandomPrimeGuard::RandomPrimeGuard(FailureType failure_type, int n, int m, + uint_fast64_t seed) + : m_type(failure_type) +{ + prime_random(m_type, n, m, seed); +} + +inline SimulatedFailure::RandomPrimeGuard::~RandomPrimeGuard() noexcept +{ + unprime(m_type); +} + +} // namespace _impl +} // namespace realm + +#endif // REALM_IMPL_SIMULATED_FAILURE_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/impl/transact_log.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/impl/transact_log.hpp new file mode 100644 index 0000000..9415115 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/impl/transact_log.hpp @@ -0,0 +1,1524 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_IMPL_TRANSACT_LOG_HPP +#define REALM_IMPL_TRANSACT_LOG_HPP + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace realm { + +struct GlobalKey; + +namespace _impl { + +/// Transaction log instruction encoding +/// NOTE: Any change to this enum is a file-format breaking change. +enum Instruction { + instr_InsertGroupLevelTable = 1, + instr_EraseGroupLevelTable = 2, // Remove columnless table from group + instr_RenameGroupLevelTable = 3, + + instr_SelectTable = 10, + instr_CreateObject = 11, + instr_RemoveObject = 12, + instr_Set = 13, + instr_SetDefault = 14, + // instr_ClearTable = 15, Remove all rows in selected table (unused from file format 11) + + instr_InsertColumn = 20, // Insert new column into to selected descriptor + instr_EraseColumn = 21, // Remove column from selected descriptor + instr_RenameColumn = 22, // Rename column in selected descriptor + // instr_SetLinkType = 23, Strong/weak (unused from file format 11) + + instr_SelectList = 30, + instr_ListInsert = 31, // Insert list entry + instr_ListSet = 32, // Assign to list entry + instr_ListMove = 33, // Move an entry within a link list + // instr_ListSwap = 34, Swap two entries within a list (unused from file format 11) + instr_ListErase = 35, // Remove an entry from a list + instr_ListClear = 36, // Remove all entries from a list +}; + +class TransactLogStream { +public: + virtual ~TransactLogStream() + { + } + + /// Ensure contiguous free space in the transaction log + /// buffer. This method must update `out_free_begin` + /// and `out_free_end` such that they refer to a chunk + /// of free space whose size is at least \a n. + /// + /// \param size The required amount of contiguous free space. Must be + /// small (probably not greater than 1024) + /// \param out_free_begin must point to current write position which must be inside earlier + /// allocated area. Will be updated to point to new writing position. + /// \param out_free_end Will be updated to point to end of allocated area. + virtual void transact_log_reserve(size_t size, char** out_free_begin, char** out_free_end) = 0; + + /// Copy the specified data into the transaction log buffer. This + /// function should be called only when the specified data does + /// not fit inside the chunk of free space currently referred to + /// by `out_free_begin` and `out_free_end`. + /// + /// This method must update `out_begin` and + /// `out_end` such that, upon return, they still + /// refer to a (possibly empty) chunk of free space. + virtual void transact_log_append(const char* data, size_t size, char** out_free_begin, char** out_free_end) = 0; +}; + +class TransactLogBufferStream : public TransactLogStream { +public: + void transact_log_reserve(size_t size, char** out_free_begin, char** out_free_end) override; + void transact_log_append(const char* data, size_t size, char** out_free_begin, char** out_free_end) override; + + const char* get_data() const; + char* get_data(); + size_t get_size(); + +private: + util::Buffer m_buffer; +}; + + +// LCOV_EXCL_START (because the NullInstructionObserver is trivial) +class NullInstructionObserver { +public: + /// The following methods are also those that TransactLogParser expects + /// to find on the `InstructionHandler`. + + // No selection needed: + bool select_table(TableKey) + { + return true; + } + bool select_list(ColKey, ObjKey) + { + return true; + } + bool select_link_list(ColKey, ObjKey) + { + return true; + } + bool insert_group_level_table(TableKey) + { + return true; + } + bool erase_group_level_table(TableKey) + { + return true; + } + bool rename_group_level_table(TableKey) + { + return true; + } + + // Must have table selected: + bool create_object(ObjKey) + { + return true; + } + bool remove_object(ObjKey) + { + return true; + } + bool modify_object(ColKey, ObjKey) + { + return true; + } + bool list_set(size_t) + { + return true; + } + bool list_insert(size_t) + { + return true; + } + + // Must have descriptor selected: + bool insert_column(ColKey) + { + return true; + } + bool erase_column(ColKey) + { + return true; + } + bool rename_column(ColKey) + { + return true; + } + bool set_link_type(ColKey) + { + return true; + } + + // Must have linklist selected: + bool list_move(size_t, size_t) + { + return true; + } + bool list_erase(size_t) + { + return true; + } + bool list_clear(size_t) + { + return true; + } + + void parse_complete() + { + } +}; +// LCOV_EXCL_STOP (NullInstructionObserver) + + +/// See TransactLogConvenientEncoder for information about the meaning of the +/// arguments of each of the functions in this class. +class TransactLogEncoder { +public: + /// The following methods are also those that TransactLogParser expects + /// to find on the `InstructionHandler`. + + // No selection needed: + bool select_table(TableKey key); + bool insert_group_level_table(TableKey table_key); + bool erase_group_level_table(TableKey table_key); + bool rename_group_level_table(TableKey table_key); + + /// Must have table selected. + bool create_object(ObjKey key) + { + append_simple_instr(instr_CreateObject, key); // Throws + return true; + } + + bool remove_object(ObjKey key) + { + append_simple_instr(instr_RemoveObject, key); // Throws + return true; + } + bool modify_object(ColKey col_key, ObjKey key); + + // Must have descriptor selected: + bool insert_column(ColKey col_key); + bool erase_column(ColKey col_key); + bool rename_column(ColKey col_key); + bool set_link_type(ColKey col_key); + + // Must have linklist selected: + bool select_list(ColKey col_key, ObjKey key); + bool list_set(size_t list_ndx); + bool list_insert(size_t ndx); + bool list_move(size_t from_link_ndx, size_t to_link_ndx); + bool list_erase(size_t list_ndx); + bool list_clear(size_t old_list_size); + + /// End of methods expected by parser. + + + TransactLogEncoder(TransactLogStream& out_stream); + void set_buffer(char* new_free_begin, char* new_free_end); + char* write_position() const + { + return m_transact_log_free_begin; + } + +private: + // Make sure this is in agreement with the actual integer encoding + // scheme (see encode_int()). + static constexpr int max_enc_bytes_per_int = 10; +// Space is reserved in chunks to avoid excessive over allocation. +#ifdef REALM_DEBUG + static constexpr int max_numbers_per_chunk = 2; // Increase the chance of chunking in debug mode +#else + static constexpr int max_numbers_per_chunk = 8; +#endif + + TransactLogStream& m_stream; + + // These two delimit a contiguous region of free space in a + // transaction log buffer following the last written data. It may + // be empty. + char* m_transact_log_free_begin = nullptr; + char* m_transact_log_free_end = nullptr; + + char* reserve(size_t size); + /// \param ptr Must be in the range [m_transact_log_free_begin, m_transact_log_free_end] + void advance(char* ptr) noexcept; + + template + size_t max_size(T); + + size_t max_size_list() + { + return 0; + } + + template + size_t max_size_list(T val, Args... args) + { + return max_size(val) + max_size_list(args...); + } + + template + char* encode(char* ptr, T value); + + char* encode_list(char* ptr) + { + advance(ptr); + return ptr; + } + + template + char* encode_list(char* ptr, T value, Args... args) + { + return encode_list(encode(ptr, value), args...); + } + + template + void append_simple_instr(L... numbers); + + template + static char* encode_int(char*, T value); + friend class TransactLogParser; +}; + +class TransactLogConvenientEncoder { +public: + virtual ~TransactLogConvenientEncoder(); + virtual void add_class(TableKey table_key, StringData table_name, bool is_embedded); + virtual void add_class_with_primary_key(TableKey, StringData table_name, DataType pk_type, StringData pk_field, + bool nullable); + virtual void erase_group_level_table(TableKey table_key, size_t num_tables); + virtual void rename_group_level_table(TableKey table_key, StringData new_name); + virtual void insert_column(const Table*, ColKey col_key, DataType type, StringData name, Table* target_table); + virtual void erase_column(const Table*, ColKey col_key); + virtual void rename_column(const Table*, ColKey col_key, StringData name); + + virtual void set_int(const Table*, ColKey col_key, ObjKey key, int_fast64_t value, + Instruction variant = instr_Set); + virtual void add_int(const Table*, ColKey col_key, ObjKey key, int_fast64_t value); + virtual void set_bool(const Table*, ColKey col_key, ObjKey key, bool value, Instruction variant = instr_Set); + virtual void set_float(const Table*, ColKey col_key, ObjKey key, float value, Instruction variant = instr_Set); + virtual void set_double(const Table*, ColKey col_key, ObjKey key, double value, Instruction variant = instr_Set); + virtual void set_string(const Table*, ColKey col_key, ObjKey key, StringData value, + Instruction variant = instr_Set); + virtual void set_binary(const Table*, ColKey col_key, ObjKey key, BinaryData value, + Instruction variant = instr_Set); + virtual void set_timestamp(const Table*, ColKey col_key, ObjKey key, Timestamp value, + Instruction variant = instr_Set); + virtual void set_object_id(const Table*, ColKey col_key, ObjKey key, ObjectId value, + Instruction variant = instr_Set); + virtual void set_decimal(const Table*, ColKey col_key, ObjKey key, Decimal128 value, + Instruction variant = instr_Set); + virtual void set_link(const Table*, ColKey col_key, ObjKey key, ObjKey value, Instruction variant = instr_Set); + virtual void set_null(const Table*, ColKey col_key, ObjKey key, Instruction variant = instr_Set); + virtual void insert_substring(const Table*, ColKey col_key, ObjKey key, size_t pos, StringData); + virtual void erase_substring(const Table*, ColKey col_key, ObjKey key, size_t pos, size_t size); + + virtual void list_set_int(const ConstLstBase& list, size_t list_ndx, int64_t value); + virtual void list_set_bool(const ConstLstBase& list, size_t list_ndx, bool value); + virtual void list_set_float(const ConstLstBase& list, size_t list_ndx, float value); + virtual void list_set_double(const ConstLstBase& list, size_t list_ndx, double value); + virtual void list_set_string(const Lst& list, size_t list_ndx, StringData value); + virtual void list_set_binary(const Lst& list, size_t list_ndx, BinaryData value); + virtual void list_set_timestamp(const Lst& list, size_t list_ndx, Timestamp value); + virtual void list_set_object_id(const ConstLstBase& list, size_t list_ndx, ObjectId value); + virtual void list_set_decimal(const Lst& list, size_t list_ndx, Decimal128 value); + + virtual void list_insert_int(const ConstLstBase& list, size_t list_ndx, int64_t value); + virtual void list_insert_bool(const ConstLstBase& list, size_t list_ndx, bool value); + virtual void list_insert_float(const ConstLstBase& list, size_t list_ndx, float value); + virtual void list_insert_double(const ConstLstBase& list, size_t list_ndx, double value); + virtual void list_insert_string(const Lst& list, size_t list_ndx, StringData value); + virtual void list_insert_binary(const Lst& list, size_t list_ndx, BinaryData value); + virtual void list_insert_timestamp(const Lst& list, size_t list_ndx, Timestamp value); + virtual void list_insert_object_id(const ConstLstBase& list, size_t list_ndx, ObjectId value); + virtual void list_insert_decimal(const Lst& list, size_t list_ndx, Decimal128 value); + + virtual void create_object(const Table*, GlobalKey); + virtual void create_object_with_primary_key(const Table*, GlobalKey, Mixed); + virtual void remove_object(const Table*, ObjKey); + + virtual void list_set_null(const ConstLstBase&, size_t ndx); + virtual void list_insert_null(const ConstLstBase&, size_t ndx); + virtual void list_set_link(const Lst&, size_t link_ndx, ObjKey value); + virtual void list_insert_link(const Lst&, size_t link_ndx, ObjKey value); + virtual void list_move(const ConstLstBase&, size_t from_link_ndx, size_t to_link_ndx); + virtual void list_erase(const ConstLstBase&, size_t link_ndx); + virtual void list_clear(const ConstLstBase&); + + //@{ + + /// Implicit nullifications due to removal of target row. This is redundant + /// information from the point of view of replication, as the removal of the + /// target row will reproduce the implicit nullifications in the target + /// Realm anyway. The purpose of this instruction is to allow observers + /// (reactor pattern) to be explicitly notified about the implicit + /// nullifications. + + virtual void nullify_link(const Table*, ColKey col_key, ObjKey key); + virtual void link_list_nullify(const Lst&, size_t link_ndx); + + //@} + +protected: + TransactLogConvenientEncoder(TransactLogStream& encoder); + + void reset_selection_caches() noexcept; + void set_buffer(char* new_free_begin, char* new_free_end) + { + m_encoder.set_buffer(new_free_begin, new_free_end); + } + char* write_position() const + { + return m_encoder.write_position(); + } + +private: + struct LinkListId { + TableKey table_key; + ObjKey object_key; + ColKey col_id; + + LinkListId() = default; + LinkListId(const ConstLstBase& list) + : table_key(list.get_table()->get_key()) + , object_key(list.get_key()) + , col_id(list.get_col_key()) + { + } + LinkListId(TableKey t, ObjKey k, ColKey c) + : table_key(t) + , object_key(k) + , col_id(c) + { + } + bool operator!=(const LinkListId& other) + { + return object_key != other.object_key || table_key != other.table_key || col_id != other.col_id; + } + }; + TransactLogEncoder m_encoder; + mutable const Table* m_selected_table = nullptr; + mutable LinkListId m_selected_list; + + void unselect_all() noexcept; + void select_table(const Table*); // unselects link list + void select_list(const ConstLstBase&); + + void do_select_table(const Table*); + void do_select_list(const ConstLstBase&); + + void do_set(const Table*, ColKey col_key, ObjKey key, Instruction variant = instr_Set); + + friend class TransactReverser; +}; + + +class TransactLogParser { +public: + class BadTransactLog; // Exception + + TransactLogParser(); + ~TransactLogParser() noexcept; + + /// See `TransactLogEncoder` for a list of methods that the `InstructionHandler` must define. + template + void parse(InputStream&, InstructionHandler&); + + template + void parse(NoCopyInputStream&, InstructionHandler&); + +private: + util::Buffer m_input_buffer; + + // The input stream is assumed to consist of chunks of memory organised such that + // every instruction resides in a single chunk only. + NoCopyInputStream* m_input; + // pointer into transaction log, each instruction is parsed from m_input_begin and onwards. + // Each instruction are assumed to be contiguous in memory. + const char* m_input_begin; + // pointer to one past current instruction log chunk. If m_input_begin reaches m_input_end, + // a call to next_input_buffer will move m_input_begin and m_input_end to a new chunk of + // memory. Setting m_input_end to 0 disables this check, and is used if it is already known + // that all of the instructions are in memory. + const char* m_input_end; + util::StringBuffer m_string_buffer; + + REALM_NORETURN void parser_error() const; + + template + void parse_one(InstructionHandler&); + bool has_next() noexcept; + + template + T read_int(); + + // Advance m_input_begin and m_input_end to reflect the next block of instructions + // Returns false if no more input was available + bool next_input_buffer(); + + // return true if input was available + bool read_char(char&); // throws +}; + + +class TransactLogParser::BadTransactLog : public std::exception { +public: + const char* what() const noexcept override + { + return "Bad transaction log"; + } +}; + + +/// Implementation: + +inline void TransactLogBufferStream::transact_log_reserve(size_t size, char** inout_new_begin, char** out_new_end) +{ + char* data = m_buffer.data(); + REALM_ASSERT(*inout_new_begin >= data); + REALM_ASSERT(*inout_new_begin <= (data + m_buffer.size())); + size_t used_size = *inout_new_begin - data; + m_buffer.reserve_extra(used_size, size); + data = m_buffer.data(); // May have changed + *inout_new_begin = data + used_size; + *out_new_end = data + m_buffer.size(); +} + +inline void TransactLogBufferStream::transact_log_append(const char* data, size_t size, char** out_new_begin, + char** out_new_end) +{ + transact_log_reserve(size, out_new_begin, out_new_end); + *out_new_begin = realm::safe_copy_n(data, size, *out_new_begin); +} + +inline const char* TransactLogBufferStream::get_data() const +{ + return m_buffer.data(); +} + +inline char* TransactLogBufferStream::get_data() +{ + return m_buffer.data(); +} + +inline size_t TransactLogBufferStream::get_size() +{ + return m_buffer.size(); +} + +inline TransactLogEncoder::TransactLogEncoder(TransactLogStream& stream) + : m_stream(stream) +{ +} + +inline void TransactLogEncoder::set_buffer(char* free_begin, char* free_end) +{ + REALM_ASSERT(free_begin <= free_end); + m_transact_log_free_begin = free_begin; + m_transact_log_free_end = free_end; +} + +inline void TransactLogConvenientEncoder::reset_selection_caches() noexcept +{ + unselect_all(); +} + +inline char* TransactLogEncoder::reserve(size_t n) +{ + if (size_t(m_transact_log_free_end - m_transact_log_free_begin) < n) { + m_stream.transact_log_reserve(n, &m_transact_log_free_begin, &m_transact_log_free_end); + } + return m_transact_log_free_begin; +} + +inline void TransactLogEncoder::advance(char* ptr) noexcept +{ + REALM_ASSERT_DEBUG(m_transact_log_free_begin <= ptr); + REALM_ASSERT_DEBUG(ptr <= m_transact_log_free_end); + m_transact_log_free_begin = ptr; +} + + +// The integer encoding is platform independent. Also, it does not +// depend on the type of the specified integer. Integers of any type +// can be encoded as long as the specified buffer is large enough (see +// below). The decoding does not have to use the same type. Decoding +// will fail if, and only if the encoded value falls outside the range +// of the requested destination type. +// +// The encoding uses one or more bytes. It never uses more than 8 bits +// per byte. The last byte in the sequence is the first one that has +// its 8th bit set to zero. +// +// Consider a particular non-negative value V. Let W be the number of +// bits needed to encode V using the trivial binary encoding of +// integers. The total number of bytes produced is then +// ceil((W+1)/7). The first byte holds the 7 least significant bits of +// V. The last byte holds at most 6 bits of V including the most +// significant one. The value of the first bit of the last byte is +// always 2**((N-1)*7) where N is the total number of bytes. +// +// A negative value W is encoded by setting the sign bit to one and +// then encoding the positive result of -(W+1) as described above. The +// advantage of this representation is that it converts small negative +// values to small positive values which require a small number of +// bytes. This would not have been true for 2's complements +// representation, for example. The sign bit is always stored as the +// 7th bit of the last byte. +// +// value bits value + sign max bytes +// -------------------------------------------------- +// int8_t 7 8 2 +// uint8_t 8 9 2 +// int16_t 15 16 3 +// uint16_t 16 17 3 +// int32_t 31 32 5 +// uint32_t 32 33 5 +// int64_t 63 64 10 +// uint64_t 64 65 10 +// +template +char* TransactLogEncoder::encode_int(char* ptr, T value) +{ + static_assert(std::numeric_limits::is_integer, "Integer required"); + bool negative = value < 0; + if (negative) { + // The following conversion is guaranteed by C++11 to never + // overflow (contrast this with "-value" which indeed could + // overflow). See C99+TC3 section 6.2.6.2 paragraph 2. + REALM_DIAG_PUSH(); + REALM_DIAG_IGNORE_UNSIGNED_MINUS(); + value = -(value + 1); + REALM_DIAG_POP(); + } + // At this point 'value' is always a positive number. Also, small + // negative numbers have been converted to small positive numbers. + REALM_ASSERT(value >= 0); + // One sign bit plus number of value bits + const int num_bits = 1 + std::numeric_limits::digits; + // Only the first 7 bits are available per byte. Had it not been + // for the fact that maximum guaranteed bit width of a char is 8, + // this value could have been increased to 15 (one less than the + // number of value bits in 'unsigned'). + const int bits_per_byte = 7; + const int max_bytes = (num_bits + (bits_per_byte - 1)) / bits_per_byte; + static_assert(max_bytes <= max_enc_bytes_per_int, "Bad max_enc_bytes_per_int"); + // An explicit constant maximum number of iterations is specified + // in the hope that it will help the optimizer (to do loop + // unrolling, for example). + typedef unsigned char uchar; + for (int i = 0; i < max_bytes; ++i) { + if (value >> (bits_per_byte - 1) == 0) + break; + *reinterpret_cast(ptr) = uchar((1U << bits_per_byte) | unsigned(value & ((1U << bits_per_byte) - 1))); + ++ptr; + value >>= bits_per_byte; + } + *reinterpret_cast(ptr) = uchar(negative ? (1U << (bits_per_byte - 1)) | unsigned(value) : value); + return ++ptr; +} + +template +inline char* TransactLogEncoder::encode(char* ptr, T inst) +{ + return encode_int(ptr, inst); +} + +template <> +inline char* TransactLogEncoder::encode(char* ptr, TableKey key) +{ + return encode_int(ptr, key.value); +} + +template <> +inline char* TransactLogEncoder::encode(char* ptr, ColKey key) +{ + return encode_int(ptr, key.value); +} + +template <> +inline char* TransactLogEncoder::encode(char* ptr, ObjKey key) +{ + return encode_int(ptr, key.value); +} + +template <> +inline char* TransactLogEncoder::encode(char* ptr, Instruction inst) +{ + return encode_int(ptr, inst); +} + +template +size_t TransactLogEncoder::max_size(T) +{ + return max_enc_bytes_per_int; +} + +template <> +inline size_t TransactLogEncoder::max_size(Instruction) +{ + return 1; +} + +template +void TransactLogEncoder::append_simple_instr(L... numbers) +{ + size_t max_required_bytes = max_size_list(numbers...); + char* ptr = reserve(max_required_bytes); // Throws + encode_list(ptr, numbers...); +} + +inline void TransactLogConvenientEncoder::unselect_all() noexcept +{ + m_selected_table = nullptr; + m_selected_list = LinkListId(); +} + +inline void TransactLogConvenientEncoder::select_table(const Table* table) +{ + if (table != m_selected_table) + do_select_table(table); // Throws + m_selected_list = LinkListId(); +} + +inline void TransactLogConvenientEncoder::select_list(const ConstLstBase& list) +{ + if (LinkListId(list) != m_selected_list) { + do_select_list(list); // Throws + } +} + +inline bool TransactLogEncoder::insert_group_level_table(TableKey table_key) +{ + append_simple_instr(instr_InsertGroupLevelTable, table_key); // Throws + return true; +} + +inline bool TransactLogEncoder::erase_group_level_table(TableKey table_key) +{ + append_simple_instr(instr_EraseGroupLevelTable, table_key); // Throws + return true; +} + +inline void TransactLogConvenientEncoder::erase_group_level_table(TableKey table_key, size_t) +{ + unselect_all(); + m_encoder.erase_group_level_table(table_key); // Throws +} + +inline bool TransactLogEncoder::rename_group_level_table(TableKey table_key) +{ + append_simple_instr(instr_RenameGroupLevelTable, table_key); // Throws + return true; +} + +inline void TransactLogConvenientEncoder::rename_group_level_table(TableKey table_key, StringData) +{ + unselect_all(); + m_encoder.rename_group_level_table(table_key); // Throws +} + +inline bool TransactLogEncoder::insert_column(ColKey col_key) +{ + append_simple_instr(instr_InsertColumn, col_key); // Throws + return true; +} + +inline void TransactLogConvenientEncoder::insert_column(const Table* t, ColKey col_key, DataType, StringData, Table*) +{ + select_table(t); // Throws + m_encoder.insert_column(col_key); // Throws +} + +inline bool TransactLogEncoder::erase_column(ColKey col_key) +{ + append_simple_instr(instr_EraseColumn, col_key); // Throws + return true; +} + +inline void TransactLogConvenientEncoder::erase_column(const Table* t, ColKey col_key) +{ + select_table(t); // Throws + m_encoder.erase_column(col_key); // Throws +} + +inline bool TransactLogEncoder::rename_column(ColKey col_key) +{ + append_simple_instr(instr_RenameColumn, col_key); // Throws + return true; +} + +inline void TransactLogConvenientEncoder::rename_column(const Table* t, ColKey col_key, StringData) +{ + select_table(t); // Throws + m_encoder.rename_column(col_key); // Throws +} + + +inline bool TransactLogEncoder::modify_object(ColKey col_key, ObjKey key) +{ + append_simple_instr(instr_Set, col_key, key); // Throws + return true; +} + + +inline void TransactLogConvenientEncoder::do_set(const Table* t, ColKey col_key, ObjKey key, Instruction variant) +{ + if (variant != Instruction::instr_SetDefault) { + select_table(t); // Throws + m_encoder.modify_object(col_key, key); // Throws + } +} + + +inline void TransactLogConvenientEncoder::set_int(const Table* t, ColKey col_key, ObjKey key, int_fast64_t, + Instruction variant) +{ + do_set(t, col_key, key, variant); // Throws +} + + +inline void TransactLogConvenientEncoder::add_int(const Table* t, ColKey col_key, ObjKey key, int_fast64_t) +{ + do_set(t, col_key, key); // Throws +} + +inline void TransactLogConvenientEncoder::set_bool(const Table* t, ColKey col_key, ObjKey key, bool, + Instruction variant) +{ + do_set(t, col_key, key, variant); // Throws +} + +inline void TransactLogConvenientEncoder::set_float(const Table* t, ColKey col_key, ObjKey key, float, + Instruction variant) +{ + do_set(t, col_key, key, variant); // Throws +} + +inline void TransactLogConvenientEncoder::set_double(const Table* t, ColKey col_key, ObjKey key, double, + Instruction variant) +{ + do_set(t, col_key, key, variant); // Throws +} + +inline void TransactLogConvenientEncoder::set_string(const Table* t, ColKey col_key, ObjKey key, StringData, + Instruction variant) +{ + do_set(t, col_key, key, variant); // Throws +} + +inline void TransactLogConvenientEncoder::set_binary(const Table* t, ColKey col_key, ObjKey key, BinaryData, + Instruction variant) +{ + do_set(t, col_key, key, variant); // Throws +} + +inline void TransactLogConvenientEncoder::set_timestamp(const Table* t, ColKey col_key, ObjKey key, Timestamp, + Instruction variant) +{ + do_set(t, col_key, key, variant); // Throws +} + +inline void TransactLogConvenientEncoder::set_object_id(const Table* t, ColKey col_key, ObjKey key, ObjectId, + Instruction variant) +{ + do_set(t, col_key, key, variant); // Throws +} + +inline void TransactLogConvenientEncoder::set_decimal(const Table* t, ColKey col_key, ObjKey key, Decimal128, + Instruction variant) +{ + do_set(t, col_key, key, variant); // Throws +} + +inline void TransactLogConvenientEncoder::set_link(const Table* t, ColKey col_key, ObjKey key, ObjKey, + Instruction variant) +{ + do_set(t, col_key, key, variant); // Throws +} + +inline void TransactLogConvenientEncoder::set_null(const Table* t, ColKey col_key, ObjKey key, Instruction variant) +{ + do_set(t, col_key, key, variant); // Throws +} + +inline void TransactLogConvenientEncoder::nullify_link(const Table* t, ColKey col_key, ObjKey key) +{ + select_table(t); // Throws + m_encoder.modify_object(col_key, key); // Throws +} + +inline void TransactLogConvenientEncoder::insert_substring(const Table* t, ColKey col_key, ObjKey key, size_t, + StringData value) +{ + if (value.size() > 0) { + do_set(t, col_key, key); // Throws + } +} + +inline void TransactLogConvenientEncoder::erase_substring(const Table* t, ColKey col_key, ObjKey key, size_t, + size_t size) +{ + if (size > 0) { + do_set(t, col_key, key); // Throws + } +} + +inline bool TransactLogEncoder::list_set(size_t list_ndx) +{ + append_simple_instr(instr_ListSet, list_ndx); // Throws + return true; +} + +inline void TransactLogConvenientEncoder::list_set_int(const ConstLstBase& list, size_t list_ndx, int64_t) +{ + select_list(list); // Throws + m_encoder.list_set(list_ndx); // Throws +} + +inline void TransactLogConvenientEncoder::list_set_bool(const ConstLstBase& list, size_t list_ndx, bool) +{ + select_list(list); // Throws + m_encoder.list_set(list_ndx); // Throws +} + +inline void TransactLogConvenientEncoder::list_set_float(const ConstLstBase& list, size_t list_ndx, float) +{ + select_list(list); // Throws + m_encoder.list_set(list_ndx); // Throws +} + +inline void TransactLogConvenientEncoder::list_set_double(const ConstLstBase& list, size_t list_ndx, double) +{ + select_list(list); // Throws + m_encoder.list_set(list_ndx); // Throws +} + +inline void TransactLogConvenientEncoder::list_set_string(const Lst& list, size_t list_ndx, StringData) +{ + select_list(list); // Throws + m_encoder.list_set(list_ndx); // Throws +} + +inline void TransactLogConvenientEncoder::list_set_binary(const Lst& list, size_t list_ndx, BinaryData) +{ + select_list(list); // Throws + m_encoder.list_set(list_ndx); // Throws +} + +inline void TransactLogConvenientEncoder::list_set_timestamp(const Lst& list, size_t list_ndx, Timestamp) +{ + select_list(list); // Throws + m_encoder.list_set(list_ndx); // Throws +} + +inline void TransactLogConvenientEncoder::list_set_object_id(const ConstLstBase& list, size_t list_ndx, ObjectId) +{ + select_list(list); // Throws + m_encoder.list_set(list_ndx); // Throws +} + +inline void TransactLogConvenientEncoder::list_set_decimal(const Lst& list, size_t list_ndx, Decimal128) +{ + select_list(list); // Throws + m_encoder.list_set(list_ndx); // Throws +} + +inline bool TransactLogEncoder::list_insert(size_t list_ndx) +{ + append_simple_instr(instr_ListInsert, list_ndx); // Throws + return true; +} + +inline void TransactLogConvenientEncoder::list_insert_int(const ConstLstBase& list, size_t list_ndx, int64_t) +{ + select_list(list); // Throws + m_encoder.list_insert(list_ndx); // Throws +} + +inline void TransactLogConvenientEncoder::list_insert_bool(const ConstLstBase& list, size_t list_ndx, bool) +{ + select_list(list); // Throws + m_encoder.list_insert(list_ndx); // Throws +} + +inline void TransactLogConvenientEncoder::list_insert_float(const ConstLstBase& list, size_t list_ndx, float) +{ + select_list(list); // Throws + m_encoder.list_insert(list_ndx); // Throws +} + +inline void TransactLogConvenientEncoder::list_insert_double(const ConstLstBase& list, size_t list_ndx, double) +{ + select_list(list); // Throws + m_encoder.list_insert(list_ndx); // Throws +} + +inline void TransactLogConvenientEncoder::list_insert_string(const Lst& list, size_t list_ndx, StringData) +{ + select_list(list); // Throws + m_encoder.list_insert(list_ndx); // Throws +} + +inline void TransactLogConvenientEncoder::list_insert_binary(const Lst& list, size_t list_ndx, BinaryData) +{ + select_list(list); // Throws + m_encoder.list_insert(list_ndx); // Throws +} + +inline void TransactLogConvenientEncoder::list_insert_object_id(const ConstLstBase& list, size_t list_ndx, ObjectId) +{ + select_list(list); // Throws + m_encoder.list_insert(list_ndx); // Throws +} + +inline void TransactLogConvenientEncoder::list_insert_timestamp(const Lst& list, size_t list_ndx, + Timestamp) +{ + select_list(list); // Throws + m_encoder.list_insert(list_ndx); // Throws +} + +inline void TransactLogConvenientEncoder::list_insert_decimal(const Lst& list, size_t list_ndx, + Decimal128) +{ + select_list(list); // Throws + m_encoder.list_insert(list_ndx); // Throws +} + +inline void TransactLogConvenientEncoder::remove_object(const Table* t, ObjKey key) +{ + select_table(t); // Throws + m_encoder.remove_object(key); // Throws +} + +inline void TransactLogConvenientEncoder::list_set_null(const ConstLstBase& list, size_t list_ndx) +{ + select_list(list); // Throws + m_encoder.list_set(list_ndx); // Throws +} + +inline void TransactLogConvenientEncoder::list_insert_null(const ConstLstBase& list, size_t list_ndx) +{ + select_list(list); // Throws + m_encoder.list_insert(list_ndx); // Throws +} + +inline void TransactLogConvenientEncoder::list_set_link(const Lst& list, size_t link_ndx, ObjKey) +{ + select_list(list); // Throws + m_encoder.list_set(link_ndx); // Throws +} + +inline void TransactLogConvenientEncoder::list_insert_link(const Lst& list, size_t link_ndx, ObjKey) +{ + select_list(list); // Throws + m_encoder.list_insert(link_ndx); // Throws +} + +inline void TransactLogConvenientEncoder::link_list_nullify(const Lst& list, size_t link_ndx) +{ + select_list(list); // Throws + m_encoder.list_erase(link_ndx); // Throws +} + +inline bool TransactLogEncoder::list_move(size_t from_link_ndx, size_t to_link_ndx) +{ + REALM_ASSERT(from_link_ndx != to_link_ndx); + append_simple_instr(instr_ListMove, from_link_ndx, to_link_ndx); // Throws + return true; +} + +inline void TransactLogConvenientEncoder::list_move(const ConstLstBase& list, size_t from_link_ndx, + size_t to_link_ndx) +{ + select_list(list); // Throws + m_encoder.list_move(from_link_ndx, to_link_ndx); // Throws +} + +inline bool TransactLogEncoder::list_erase(size_t list_ndx) +{ + append_simple_instr(instr_ListErase, list_ndx); // Throws + return true; +} + +inline void TransactLogConvenientEncoder::list_erase(const ConstLstBase& list, size_t link_ndx) +{ + select_list(list); // Throws + m_encoder.list_erase(link_ndx); // Throws +} + +inline bool TransactLogEncoder::list_clear(size_t old_list_size) +{ + append_simple_instr(instr_ListClear, old_list_size); // Throws + return true; +} + +inline TransactLogParser::TransactLogParser() + : m_input_buffer(1024) // Throws +{ +} + + +inline TransactLogParser::~TransactLogParser() noexcept +{ +} + + +template +void TransactLogParser::parse(NoCopyInputStream& in, InstructionHandler& handler) +{ + m_input = ∈ + m_input_begin = m_input_end = nullptr; + + while (has_next()) + parse_one(handler); // Throws +} + +template +void TransactLogParser::parse(InputStream& in, InstructionHandler& handler) +{ + NoCopyInputStreamAdaptor in_2(in, m_input_buffer.data(), m_input_buffer.size()); + parse(in_2, handler); // Throws +} + +inline bool TransactLogParser::has_next() noexcept +{ + return m_input_begin != m_input_end || next_input_buffer(); +} + +template +void TransactLogParser::parse_one(InstructionHandler& handler) +{ + char instr_ch = 0; // silence a warning + if (!read_char(instr_ch)) + parser_error(); // Throws + Instruction instr = Instruction(instr_ch); + switch (instr) { + case instr_Set: { + ColKey col_key = ColKey(read_int()); // Throws + ObjKey key(read_int()); // Throws + if (!handler.modify_object(col_key, key)) // Throws + parser_error(); + return; + } + case instr_SetDefault: + // Should not appear in the transaction log + parser_error(); + case instr_ListSet: { + size_t list_ndx = read_int(); + if (!handler.list_set(list_ndx)) // Throws + parser_error(); + return; + } + case instr_CreateObject: { + ObjKey key(read_int()); // Throws + if (!handler.create_object(key)) // Throws + parser_error(); + return; + } + case instr_RemoveObject: { + ObjKey key(read_int()); // Throws + if (!handler.remove_object(key)) // Throws + parser_error(); + return; + } + case instr_SelectTable: { + int levels = read_int(); // Throws + REALM_ASSERT(levels == 0); + TableKey key = TableKey(read_int()); + if (!handler.select_table(key)) // Throws + parser_error(); + return; + } + case instr_ListInsert: { + size_t list_ndx = read_int(); + if (!handler.list_insert(list_ndx)) // Throws + parser_error(); + return; + } + case instr_ListMove: { + size_t from_link_ndx = read_int(); // Throws + size_t to_link_ndx = read_int(); // Throws + if (!handler.list_move(from_link_ndx, to_link_ndx)) // Throws + parser_error(); + return; + } + case instr_ListErase: { + size_t link_ndx = read_int(); // Throws + if (!handler.list_erase(link_ndx)) // Throws + parser_error(); + return; + } + case instr_ListClear: { + size_t old_list_size = read_int(); // Throws + if (!handler.list_clear(old_list_size)) // Throws + parser_error(); + return; + } + case instr_SelectList: { + ColKey col_key = ColKey(read_int()); // Throws + ObjKey key = ObjKey(read_int()); // Throws + if (!handler.select_list(col_key, key)) // Throws + parser_error(); + return; + } + case instr_InsertColumn: { + ColKey col_key = ColKey(read_int()); // Throws + if (!handler.insert_column(col_key)) // Throws + parser_error(); + return; + } + case instr_EraseColumn: { + ColKey col_key = ColKey(read_int()); // Throws + if (!handler.erase_column(col_key)) // Throws + parser_error(); + return; + } + case instr_RenameColumn: { + ColKey col_key = ColKey(read_int()); // Throws + if (!handler.rename_column(col_key)) // Throws + parser_error(); + return; + } + case instr_InsertGroupLevelTable: { + TableKey table_key = TableKey(read_int()); // Throws + if (!handler.insert_group_level_table(table_key)) // Throws + parser_error(); + return; + } + case instr_EraseGroupLevelTable: { + TableKey table_key = TableKey(read_int()); // Throws + if (!handler.erase_group_level_table(table_key)) // Throws + parser_error(); + return; + } + case instr_RenameGroupLevelTable: { + TableKey table_key = TableKey(read_int()); // Throws + if (!handler.rename_group_level_table(table_key)) // Throws + parser_error(); + return; + } + } + + throw BadTransactLog(); +} + + +template +T TransactLogParser::read_int() +{ + T value = 0; + int part = 0; + const int max_bytes = (std::numeric_limits::digits + 1 + 6) / 7; + for (int i = 0; i != max_bytes; ++i) { + char c; + if (!read_char(c)) + goto bad_transact_log; + part = static_cast(c); + if (0xFF < part) + goto bad_transact_log; // Only the first 8 bits may be used in each byte + if ((part & 0x80) == 0) { + T p = part & 0x3F; + if (util::int_shift_left_with_overflow_detect(p, i * 7)) + goto bad_transact_log; + value |= p; + break; + } + if (i == max_bytes - 1) + goto bad_transact_log; // Too many bytes + value |= T(part & 0x7F) << (i * 7); + } + if (part & 0x40) { + // The real value is negative. Because 'value' is positive at + // this point, the following negation is guaranteed by C++11 + // to never overflow. See C99+TC3 section 6.2.6.2 paragraph 2. + REALM_DIAG_PUSH(); + REALM_DIAG_IGNORE_UNSIGNED_MINUS(); + value = -value; + REALM_DIAG_POP(); + if (util::int_subtract_with_overflow_detect(value, 1)) + goto bad_transact_log; + } + return value; + +bad_transact_log: + throw BadTransactLog(); +} + +inline bool TransactLogParser::next_input_buffer() +{ + return m_input->next_block(m_input_begin, m_input_end); +} + + +inline bool TransactLogParser::read_char(char& c) +{ + if (m_input_begin == m_input_end && !next_input_buffer()) + return false; + c = *m_input_begin++; + return true; +} + + +class TransactReverser { +public: + bool select_table(TableKey key) + { + sync_table(); + m_encoder.select_table(key); + m_pending_ts_instr = get_inst(); + return true; + } + + bool insert_group_level_table(TableKey table_key) + { + sync_table(); + m_encoder.erase_group_level_table(table_key); + append_instruction(); + return true; + } + + bool erase_group_level_table(TableKey table_key) + { + sync_table(); + m_encoder.insert_group_level_table(table_key); + append_instruction(); + return true; + } + + bool rename_group_level_table(TableKey) + { + sync_table(); + return true; + } + + bool create_object(ObjKey key) + { + m_encoder.remove_object(key); // Throws + append_instruction(); + return true; + } + + bool remove_object(ObjKey key) + { + m_encoder.create_object(key); // Throws + append_instruction(); + return true; + } + + bool modify_object(ColKey col_key, ObjKey key) + { + m_encoder.modify_object(col_key, key); + append_instruction(); + return true; + } + + bool list_set(size_t ndx) + { + m_encoder.list_set(ndx); + append_instruction(); + return true; + } + + bool list_insert(size_t ndx) + { + m_encoder.list_erase(ndx); + append_instruction(); + return true; + } + + bool clear_table(size_t old_size) + { + while (old_size--) { + m_encoder.create_object(null_key); + append_instruction(); + } + return true; + } + + bool set_link_type(ColKey key) + { + m_encoder.set_link_type(key); + return true; + } + + bool insert_column(ColKey col_key) + { + m_encoder.erase_column(col_key); + append_instruction(); + return true; + } + + bool erase_column(ColKey col_key) + { + m_encoder.insert_column(col_key); + append_instruction(); + return true; + } + + bool rename_column(ColKey col_key) + { + m_encoder.rename_column(col_key); + return true; + } + + bool select_list(ColKey col_key, ObjKey key) + { + sync_list(); + m_encoder.select_list(col_key, key); + m_pending_ls_instr = get_inst(); + return true; + } + + bool list_move(size_t from_link_ndx, size_t to_link_ndx) + { + m_encoder.list_move(from_link_ndx, to_link_ndx); + append_instruction(); + return true; + } + + bool list_erase(size_t list_ndx) + { + m_encoder.list_insert(list_ndx); + append_instruction(); + return true; + } + + bool list_clear(size_t old_list_size) + { + // Append in reverse order because the reversed log is itself applied + // in reverse, and this way it generates all back-insertions rather than + // all front-insertions + for (size_t i = old_list_size; i > 0; --i) { + m_encoder.list_insert(i - 1); + append_instruction(); + } + return true; + } + +private: + _impl::TransactLogBufferStream m_buffer; + _impl::TransactLogEncoder m_encoder{m_buffer}; + struct Instr { + size_t begin; + size_t end; + }; + std::vector m_instructions; + size_t current_instr_start = 0; + Instr m_pending_ts_instr{0, 0}; + Instr m_pending_ls_instr{0, 0}; + + Instr get_inst() + { + Instr instr; + instr.begin = current_instr_start; + current_instr_start = transact_log_size(); + instr.end = current_instr_start; + return instr; + } + + size_t transact_log_size() const + { + REALM_ASSERT_3(m_encoder.write_position(), >=, m_buffer.get_data()); + return m_encoder.write_position() - m_buffer.get_data(); + } + + void append_instruction() + { + m_instructions.push_back(get_inst()); + } + + void append_instruction(Instr instr) + { + m_instructions.push_back(instr); + } + + void sync_select(Instr& pending_instr) + { + if (pending_instr.begin != pending_instr.end) { + append_instruction(pending_instr); + pending_instr = {0, 0}; + } + } + + void sync_list() + { + sync_select(m_pending_ls_instr); + } + + void sync_table() + { + sync_list(); + sync_select(m_pending_ts_instr); + } + + friend class ReversedNoCopyInputStream; +}; + + +class ReversedNoCopyInputStream : public NoCopyInputStream { +public: + ReversedNoCopyInputStream(TransactReverser& reverser) + : m_instr_order(reverser.m_instructions) + { + // push any pending select_table into the buffer + reverser.sync_table(); + + m_buffer = reverser.m_buffer.get_data(); + m_current = m_instr_order.size(); + } + + bool next_block(const char*& begin, const char*& end) override + { + if (m_current != 0) { + m_current--; + begin = m_buffer + m_instr_order[m_current].begin; + end = m_buffer + m_instr_order[m_current].end; + return (end > begin); + } + return false; + } + +private: + const char* m_buffer; + std::vector& m_instr_order; + size_t m_current; +}; + +} // namespace _impl +} // namespace realm + +#endif // REALM_IMPL_TRANSACT_LOG_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/index_string.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/index_string.hpp new file mode 100644 index 0000000..e0327a2 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/index_string.hpp @@ -0,0 +1,626 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_INDEX_STRING_HPP +#define REALM_INDEX_STRING_HPP + +#include +#include +#include + +#include +#include + +/* +The StringIndex class is used for both type_String and all integral types, such as type_Bool, type_Timestamp and +type_Int. When used for integral types, the 64-bit integer is simply casted to a string of 8 bytes through a +pretty simple "wrapper layer" in all public methods. + +The StringIndex data structure is like an "inversed" B+ tree where the leafs contain row indexes and the non-leafs +contain 4-byte chunks of payload. Imagine a table with following strings: + + hello, kitty, kitten, foobar, kitty, foobar + +The topmost level of the index tree contains prefixes of the payload strings of length <= 4. The next level contains +prefixes of the remaining parts of the strings. Unnecessary levels of the tree are optimized away; the prefix "foob" +is shared only by rows that are identical ("foobar"), so "ar" is not needed to be stored in the tree. + + hell kitt foob + | /\ | + 0 en y {3, 5} + | \ + {1, 4} 2 + +Each non-leafs consists of two integer arrays of the same length, one containing payload and the other containing +references to the sublevel nodes. + +The leafs can be either a single value or a Column. If the reference in its parent node has its least significant +bit set, then the remaining upper bits specify the row index at which the string is stored. If the bit is clear, +it must be interpreted as a reference to a Column that stores the row indexes at which the string is stored. + +If a Column is used, then all row indexes are guaranteed to be sorted increasingly, which means you an search in it +using our binary search functions such as upper_bound() and lower_bound(). Each duplicate value will be stored in +the same Column, but Columns may contain more than just duplicates if the depth of the tree exceeds the value +`s_max_offset` This is to avoid stack overflow problems with many of our recursive functions if we have two very +long strings that have a long common prefix but differ in the last couple bytes. If a Column stores more than just +duplicates, then the list is kept sorted in ascending order by string value and within the groups of common +strings, the rows are sorted in ascending order. +*/ + +namespace realm { + +class Spec; +class Timestamp; +class ClusterColumn; + +template +class BPlusTree; + +/// Each StringIndex node contains an array of this type +class IndexArray : public Array { +public: + IndexArray(Allocator& allocator) + : Array(allocator) + { + } + + ObjKey index_string_find_first(StringData value, const ClusterColumn& column) const; + void index_string_find_all(std::vector& result, StringData value, const ClusterColumn& column, + bool case_insensitive = false) const; + FindRes index_string_find_all_no_copy(StringData value, const ClusterColumn& column, + InternalFindResult& result) const; + size_t index_string_count(StringData value, const ClusterColumn& column) const; + +private: + template + int64_t from_list(StringData value, InternalFindResult& result_ref, const IntegerColumn& key_values, + const ClusterColumn& column) const; + + void from_list_all(StringData value, std::vector& result, const IntegerColumn& rows, + const ClusterColumn& column) const; + + void from_list_all_ins(StringData value, std::vector& result, const IntegerColumn& rows, + const ClusterColumn& column) const; + + template + int64_t index_string(StringData value, InternalFindResult& result_ref, const ClusterColumn& column) const; + + void index_string_all(StringData value, std::vector& result, const ClusterColumn& column) const; + + void index_string_all_ins(StringData value, std::vector& result, const ClusterColumn& column) const; +}; + +// 12 is the biggest element size of any non-string/binary Realm type +constexpr size_t string_conversion_buffer_size = 12; +using StringConversionBuffer = std::array; + +// The purpose of this class is to get easy access to fields in a specific column in the +// cluster. When you have an object like this, you can get a string version of the relevant +// field based on the key for the object. +class ClusterColumn { +public: + ClusterColumn(const ClusterTree* cluster_tree, ColKey column_key) + : m_cluster_tree(cluster_tree) + , m_column_key(column_key) + { + } + size_t size() const + { + return m_cluster_tree->size(); + } + ClusterTree::ConstIterator begin() const + { + return ClusterTree::ConstIterator(*m_cluster_tree, 0); + } + + ClusterTree::ConstIterator end() const + { + return ClusterTree::ConstIterator(*m_cluster_tree, size()); + } + + + DataType get_data_type() const; + ColKey get_column_key() const + { + return m_column_key; + } + bool is_nullable() const; + StringData get_index_data(ObjKey key, StringConversionBuffer& buffer) const; + +private: + const ClusterTree* m_cluster_tree; + ColKey m_column_key; +}; + +class StringIndex { +public: + StringIndex(const ClusterColumn& target_column, Allocator&); + StringIndex(ref_type, ArrayParent*, size_t ndx_in_parent, const ClusterColumn& target_column, Allocator&); + ~StringIndex() noexcept + { + } + + ColKey get_column_key() const + { + return m_target_column.get_column_key(); + } + + static bool type_supported(realm::DataType type) + { + return (type == type_Int || type == type_String || type == type_Bool || type == type_Timestamp || + type == type_ObjectId); + } + + static ref_type create_empty(Allocator& alloc); + + void set_target(const ClusterColumn& target_column) noexcept; + + // Accessor concept: + Allocator& get_alloc() const noexcept; + void destroy() noexcept; + void detach(); + bool is_attached() const noexcept; + void set_parent(ArrayParent* parent, size_t ndx_in_parent) noexcept; + size_t get_ndx_in_parent() const noexcept; + void set_ndx_in_parent(size_t ndx_in_parent) noexcept; + void update_from_parent(size_t old_baseline) noexcept; + void refresh_accessor_tree(const ClusterColumn& target_column); + ref_type get_ref() const noexcept; + + // StringIndex interface: + + bool is_empty() const; + + template + void insert(ObjKey key, T value); + template + void insert(ObjKey key, util::Optional value); + + template + void set(ObjKey key, T new_value); + template + void set(ObjKey key, util::Optional new_value); + + void erase(ObjKey key); + + template + ObjKey find_first(T value) const; + template + void find_all(std::vector& result, T value, bool case_insensitive = false) const; + template + FindRes find_all_no_copy(T value, InternalFindResult& result) const; + template + size_t count(T value) const; + template + void update_ref(T value, size_t old_row_ndx, size_t new_row_ndx); + + void clear(); + + bool has_duplicate_values() const noexcept; + + void verify() const; +#ifdef REALM_DEBUG + template + void verify_entries(const ClusterColumn& column) const; + void do_dump_node_structure(std::ostream&, int) const; +#endif + + typedef int32_t key_type; + + // s_max_offset specifies the number of levels of recursive string indexes + // allowed before storing everything in lists. This is to avoid nesting + // to too deep of a level. Since every SubStringIndex stores 4 bytes, this + // means that a StringIndex is helpful for strings of a common prefix up to + // 4 times this limit (200 bytes shared). Lists are stored in sorted order, + // so strings sharing a common prefix of more than this limit will use a + // binary search of approximate complexity log2(n) from `std::lower_bound`. + static const size_t s_max_offset = 200; // max depth * s_index_key_length + static const size_t s_index_key_length = 4; + static key_type create_key(StringData) noexcept; + static key_type create_key(StringData, size_t) noexcept; + +private: + // m_array is a compact representation for storing the children of this StringIndex. + // Children can be: + // 1) a row number + // 2) a reference to a list which stores row numbers (for duplicate strings). + // 3) a reference to a sub-index + // m_array[0] is always a reference to a values array which stores the 4 byte chunk + // of payload data for quick string chunk comparisons. The array stored + // at m_array[0] lines up with the indices of values in m_array[1] so for example + // starting with an empty StringIndex: + // StringColumn::insert(target_row_ndx=42, value="test_string") would result with + // get_array_from_ref(m_array[0])[0] == create_key("test") and + // m_array[1] == 42 + // In this way, m_array which stores one child has a size of two. + // Children are type 1 (row number) if the LSB of the value is set. + // To get the actual row value, shift value down by one. + // If the LSB of the value is 0 then the value is a reference and can be either + // type 2, or type 3 (no shifting in either case). + // References point to a list if the context header flag is NOT set. + // If the header flag is set, references point to a sub-StringIndex (nesting). + std::unique_ptr m_array; + ClusterColumn m_target_column; + + struct inner_node_tag { + }; + StringIndex(inner_node_tag, Allocator&); + + static IndexArray* create_node(Allocator&, bool is_leaf); + + void insert_with_offset(ObjKey key, StringData value, size_t offset); + void insert_row_list(size_t ref, size_t offset, StringData value); + void insert_to_existing_list(ObjKey key, StringData value, IntegerColumn& list); + void insert_to_existing_list_at_lower(ObjKey key, StringData value, IntegerColumn& list, + const IntegerColumnIterator& lower); + key_type get_last_key() const; + + struct NodeChange { + size_t ref1; + size_t ref2; + enum ChangeType { change_None, change_InsertBefore, change_InsertAfter, change_Split } type; + NodeChange(ChangeType t, size_t r1 = 0, size_t r2 = 0) + : ref1(r1) + , ref2(r2) + , type(t) + { + } + NodeChange() + : ref1(0) + , ref2(0) + , type(change_None) + { + } + }; + + // B-Tree functions + void TreeInsert(ObjKey obj_key, key_type, size_t offset, StringData value); + NodeChange do_insert(ObjKey, key_type, size_t offset, StringData value); + /// Returns true if there is room or it can join existing entries + bool leaf_insert(ObjKey obj_key, key_type, size_t offset, StringData value, bool noextend = false); + void node_insert_split(size_t ndx, size_t new_ref); + void node_insert(size_t ndx, size_t ref); + void do_delete(ObjKey key, StringData, size_t offset); + + StringData get(ObjKey key, StringConversionBuffer& buffer) const; + + void node_add_key(ref_type ref); + +#ifdef REALM_DEBUG + static void dump_node_structure(const Array& node, std::ostream&, int level); +#endif +}; + +class SortedListComparator { +public: + SortedListComparator(const ClusterTree* cluster_tree, ColKey column_key) + : m_column(cluster_tree, column_key) + { + } + SortedListComparator(const ClusterColumn& column) + : m_column(column) + { + } + + bool operator()(int64_t key_value, StringData needle); + bool operator()(StringData needle, int64_t key_value); + +private: + const ClusterColumn m_column; +}; + + +// Implementation: + +template +struct GetIndexData { + static StringData get_index_data(Mixed, StringConversionBuffer&) + { + REALM_ASSERT_RELEASE(false); // LCOV_EXCL_LINE; Index not supported + return {}; + } +}; + +template <> +struct GetIndexData { + static StringData get_index_data(const Timestamp& dt, StringConversionBuffer& buffer); +}; + +template <> +struct GetIndexData { + static StringData get_index_data(const int64_t& value, StringConversionBuffer& buffer) + { + const char* c = reinterpret_cast(&value); + realm::safe_copy_n(c, sizeof(int64_t), buffer.data()); + return StringData{buffer.data(), sizeof(int64_t)}; + } +}; + +template <> +struct GetIndexData { + static StringData get_index_data(const bool& value, StringConversionBuffer& buffer) + { + int64_t value2 = value ? 1 : 0; + const char* c = reinterpret_cast(&value2); + realm::safe_copy_n(c, sizeof(int64_t), buffer.data()); + return StringData{buffer.data(), sizeof(int64_t)}; + } +}; + +template <> +struct GetIndexData { + static StringData get_index_data(StringData data, StringConversionBuffer&) + { + return data; + } +}; + +template <> +struct GetIndexData { + static StringData get_index_data(null, StringConversionBuffer&) + { + return null{}; + } +}; + +template +struct GetIndexData> { + static StringData get_index_data(const util::Optional& value, StringConversionBuffer& buffer) + { + if (value) + return GetIndexData::get_index_data(*value, buffer); + return null{}; + } +}; + +template <> +struct GetIndexData { + static StringData get_index_data(ObjectId value, StringConversionBuffer& buffer) + { + memcpy(&buffer, &value, sizeof(ObjectId)); + return StringData{buffer.data(), sizeof(ObjectId)}; + } +}; + +template <> +struct GetIndexData : GetIndexData { +}; + +// to_str() is used by the integer index. The existing StringIndex is re-used for this +// by making IntegerColumn convert its integers to strings by calling to_str(). + +template +inline StringData to_str(T&& value, StringConversionBuffer& buffer) +{ + return GetIndexData::type>::get_index_data(value, buffer); +} + + +inline StringIndex::StringIndex(const ClusterColumn& target_column, Allocator& alloc) + : m_array(create_node(alloc, true)) // Throws + , m_target_column(target_column) +{ +} + +inline StringIndex::StringIndex(ref_type ref, ArrayParent* parent, size_t ndx_in_parent, + const ClusterColumn& target_column, Allocator& alloc) + : m_array(new IndexArray(alloc)) + , m_target_column(target_column) +{ + REALM_ASSERT_EX(Array::get_context_flag_from_header(alloc.translate(ref)), ref, size_t(alloc.translate(ref))); + m_array->init_from_ref(ref); + set_parent(parent, ndx_in_parent); +} + +inline StringIndex::StringIndex(inner_node_tag, Allocator& alloc) + : m_array(create_node(alloc, false)) // Throws + , m_target_column(ClusterColumn(nullptr, {})) +{ +} + +// Byte order of the key is *reversed*, so that for the integer index, the least significant +// byte comes first, so that it fits little-endian machines. That way we can perform fast +// range-lookups and iterate in order, etc, as future features. This, however, makes the same +// features slower for string indexes. Todo, we should reverse the order conditionally, depending +// on the column type. +inline StringIndex::key_type StringIndex::create_key(StringData str) noexcept +{ + key_type key = 0; + + if (str.size() >= 4) + goto four; + if (str.size() < 2) { + if (str.size() == 0) + goto none; + goto one; + } + if (str.size() == 2) + goto two; + goto three; + +// Create 4 byte index key +// (encoded like this to allow literal comparisons +// independently of endianness) +four: + key |= (key_type(static_cast(str[3])) << 0); +three: + key |= (key_type(static_cast(str[2])) << 8); +two: + key |= (key_type(static_cast(str[1])) << 16); +one: + key |= (key_type(static_cast(str[0])) << 24); +none: + return key; +} + +// Index works as follows: All non-NULL values are stored as if they had appended an 'X' character at the end. So +// "foo" is stored as if it was "fooX", and "" (empty string) is stored as "X". And NULLs are stored as empty strings. +inline StringIndex::key_type StringIndex::create_key(StringData str, size_t offset) noexcept +{ + if (str.is_null()) + return 0; + + if (offset > str.size()) + return 0; + + // for very short strings + size_t tail = str.size() - offset; + if (tail <= sizeof(key_type) - 1) { + char buf[sizeof(key_type)]; + memset(buf, 0, sizeof(key_type)); + buf[tail] = 'X'; + memcpy(buf, str.data() + offset, tail); + return create_key(StringData(buf, tail + 1)); + } + // else fallback + return create_key(str.substr(offset)); +} + +template +void StringIndex::insert(ObjKey key, T value) +{ + StringConversionBuffer buffer; + size_t offset = 0; // First key from beginning of string + insert_with_offset(key, to_str(value, buffer), offset); // Throws +} + +template +void StringIndex::insert(ObjKey key, util::Optional value) +{ + if (value) { + insert(key, *value); + } + else { + insert(key, null{}); + } +} + +template +void StringIndex::set(ObjKey key, T new_value) +{ + StringConversionBuffer buffer; + StringConversionBuffer buffer2; + StringData old_value = get(key, buffer); + StringData new_value2 = to_str(new_value, buffer2); + + // Note that insert_with_offset() throws UniqueConstraintViolation. + + if (REALM_LIKELY(new_value2 != old_value)) { + // We must erase this row first because erase uses find_first which + // might find the duplicate if we insert before erasing. + erase(key); // Throws + + size_t offset = 0; // First key from beginning of string + insert_with_offset(key, new_value2, offset); // Throws + } +} + +template +void StringIndex::set(ObjKey key, util::Optional new_value) +{ + if (new_value) { + set(key, *new_value); + } + else { + set(key, null{}); + } +} + +template +ObjKey StringIndex::find_first(T value) const +{ + // Use direct access method + StringConversionBuffer buffer; + return m_array->index_string_find_first(to_str(value, buffer), m_target_column); +} + +template +void StringIndex::find_all(std::vector& result, T value, bool case_insensitive) const +{ + // Use direct access method + StringConversionBuffer buffer; + return m_array->index_string_find_all(result, to_str(value, buffer), m_target_column, case_insensitive); +} + +template +FindRes StringIndex::find_all_no_copy(T value, InternalFindResult& result) const +{ + // Use direct access method + StringConversionBuffer buffer; + return m_array->index_string_find_all_no_copy(to_str(value, buffer), m_target_column, result); +} + +template +size_t StringIndex::count(T value) const +{ + // Use direct access method + StringConversionBuffer buffer; + return m_array->index_string_count(to_str(value, buffer), m_target_column); +} + +template +void StringIndex::update_ref(T value, size_t old_row_ndx, size_t new_row_ndx) +{ + StringConversionBuffer buffer; + do_update_ref(to_str(value, buffer), old_row_ndx, new_row_ndx, 0); +} + +inline void StringIndex::destroy() noexcept +{ + return m_array->destroy_deep(); +} + +inline bool StringIndex::is_attached() const noexcept +{ + return m_array->is_attached(); +} + +inline void StringIndex::refresh_accessor_tree(const ClusterColumn& target_column) +{ + m_array->init_from_parent(); + m_target_column = target_column; +} + +inline ref_type StringIndex::get_ref() const noexcept +{ + return m_array->get_ref(); +} + +inline void StringIndex::set_parent(ArrayParent* parent, size_t ndx_in_parent) noexcept +{ + m_array->set_parent(parent, ndx_in_parent); +} + +inline size_t StringIndex::get_ndx_in_parent() const noexcept +{ + return m_array->get_ndx_in_parent(); +} + +inline void StringIndex::set_ndx_in_parent(size_t ndx_in_parent) noexcept +{ + m_array->set_ndx_in_parent(ndx_in_parent); +} + +inline void StringIndex::update_from_parent(size_t old_baseline) noexcept +{ + m_array->update_from_parent(old_baseline); +} + +} // namespace realm + +#endif // REALM_INDEX_STRING_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/keys.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/keys.hpp new file mode 100644 index 0000000..3d8e92d --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/keys.hpp @@ -0,0 +1,276 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_KEYS_HPP +#define REALM_KEYS_HPP + +#include +#include +#include +#include + +namespace realm { + +struct TableKey { + static constexpr uint32_t null_value = uint32_t(-1) >> 1; // free top bit + + constexpr TableKey() noexcept + : value(null_value) + { + } + explicit TableKey(uint32_t val) noexcept + : value(val) + { + } + TableKey& operator=(uint32_t val) noexcept + { + value = val; + return *this; + } + bool operator==(const TableKey& rhs) const noexcept + { + return value == rhs.value; + } + bool operator!=(const TableKey& rhs) const noexcept + { + return value != rhs.value; + } + bool operator<(const TableKey& rhs) const noexcept + { + return value < rhs.value; + } + explicit operator bool() const noexcept + { + return value != null_value; + } + uint32_t value; +}; + + +inline std::ostream& operator<<(std::ostream& os, TableKey tk) +{ + os << "TableKey(" << tk.value << ")"; + return os; +} + +namespace util { + +inline std::string to_string(TableKey tk) +{ + return to_string(tk.value); +} +} + +class TableVersions : public std::vector> { +public: + TableVersions() + { + } + TableVersions(TableKey key, uint64_t version) + { + emplace_back(key, version); + } + bool operator==(const TableVersions& other) const; +}; + +struct ColKey { + static constexpr int64_t null_value = int64_t(uint64_t(-1) >> 1); // free top bit + + struct Idx { + unsigned val; + }; + + constexpr ColKey() noexcept + : value(null_value) + { + } + constexpr explicit ColKey(int64_t val) noexcept + : value(val) + { + } + explicit ColKey(Idx index, ColumnType type, ColumnAttrMask attrs, unsigned tag) noexcept + : ColKey((index.val & 0xFFFFUL) | ((type & 0x3FUL) << 16) | ((attrs.m_value & 0xFFUL) << 22) | + ((tag & 0xFFFFFFFFUL) << 30)) + { + } + bool is_nullable() + { + return get_attrs().test(col_attr_Nullable); + } + bool is_list() + { + return get_attrs().test(col_attr_List); + } + ColKey& operator=(int64_t val) noexcept + { + value = val; + return *this; + } + bool operator==(const ColKey& rhs) const noexcept + { + return value == rhs.value; + } + bool operator!=(const ColKey& rhs) const noexcept + { + return value != rhs.value; + } + bool operator<(const ColKey& rhs) const noexcept + { + return value < rhs.value; + } + bool operator>(const ColKey& rhs) const noexcept + { + return value > rhs.value; + } + explicit operator bool() const noexcept + { + return value != null_value; + } + Idx get_index() const noexcept + { + return Idx{static_cast(value) & 0xFFFFU}; + } + ColumnType get_type() const noexcept + { + return ColumnType((static_cast(value) >> 16) & 0x3F); + } + ColumnAttrMask get_attrs() const noexcept + { + return ColumnAttrMask((static_cast(value) >> 22) & 0xFF); + } + unsigned get_tag() const noexcept + { + return (value >> 30) & 0xFFFFFFFFUL; + } + int64_t value; +}; + +static_assert(ColKey::null_value == 0x7fffffffffffffff, "Fix this"); + +inline std::ostream& operator<<(std::ostream& os, ColKey ck) +{ + os << "ColKey(" << ck.value << ")"; + return os; +} + +struct ObjKey { + constexpr ObjKey() noexcept + : value(-1) + { + } + explicit constexpr ObjKey(int64_t val) noexcept + : value(val) + { + } + bool is_unresolved() const + { + return value <= -2; + } + ObjKey get_unresolved() const + { + return ObjKey(-2 - value); + } + ObjKey& operator=(int64_t val) noexcept + { + value = val; + return *this; + } + bool operator==(const ObjKey& rhs) const noexcept + { + return value == rhs.value; + } + bool operator!=(const ObjKey& rhs) const noexcept + { + return value != rhs.value; + } + bool operator<(const ObjKey& rhs) const noexcept + { + return value < rhs.value; + } + bool operator<=(const ObjKey& rhs) const noexcept + { + return value <= rhs.value; + } + bool operator>(const ObjKey& rhs) const noexcept + { + return value > rhs.value; + } + bool operator>=(const ObjKey& rhs) const noexcept + { + return value >= rhs.value; + } + explicit operator bool() const noexcept + { + return value != -1; + } + int64_t value; + +private: + // operator bool will enable casting to integer. Prevent this. + operator int64_t() const = delete; +}; + +class ObjKeys : public std::vector { +public: + ObjKeys(const std::vector& init) + { + reserve(init.size()); + for (auto i : init) { + emplace_back(i); + } + } + ObjKeys() + { + } +}; + + +inline std::ostream& operator<<(std::ostream& ostr, ObjKey key) +{ + ostr << "ObjKey(" << key.value << ")"; + return ostr; +} + +constexpr ObjKey null_key; + +namespace util { + +inline std::string to_string(ColKey ck) +{ + return to_string(ck.value); +} + +} // namespace util + +} // namespace realm + + +namespace std { + +template <> +struct hash { + size_t operator()(realm::ObjKey key) const + { + return std::hash{}(key.value); + } +}; + +} // namespace std + + +#endif diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/list.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/list.hpp new file mode 100644 index 0000000..4cc1da5 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/list.hpp @@ -0,0 +1,1049 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_LIST_HPP +#define REALM_LIST_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(disable : 4250) // Suppress 'inherits ... via dominance' on MSVC +#endif + +namespace realm { + +class TableView; +class SortDescriptor; +class Group; + +// To be used in query for size. Adds nullability to size so that +// it can be put in a NullableVector +struct SizeOfList { + static constexpr size_t null_value = size_t(-1); + + SizeOfList(size_t s = null_value) + : sz(s) + { + } + bool is_null() + { + return sz == null_value; + } + void set_null() + { + sz = null_value; + } + size_t size() const + { + return sz; + } + size_t sz = null_value; +}; + +inline std::ostream& operator<<(std::ostream& ostr, SizeOfList size_of_list) +{ + if (size_of_list.is_null()) { + ostr << "null"; + } + else { + ostr << size_of_list.sz; + } + return ostr; +} + +class ConstLstBase : public ArrayParent { +public: + ConstLstBase(ConstLstBase&&) = delete; + virtual ~ConstLstBase(); + /* + * Operations that makes sense without knowing the specific type + * can be made virtual. + */ + virtual size_t size() const = 0; + virtual bool is_null(size_t ndx) const = 0; + virtual Mixed get_any(size_t ndx) const = 0; + + virtual Mixed min(size_t* return_ndx = nullptr) const = 0; + virtual Mixed max(size_t* return_ndx = nullptr) const = 0; + virtual Mixed sum(size_t* return_cnt = nullptr) const = 0; + virtual Mixed avg(size_t* return_cnt = nullptr) const = 0; + + // Modifies a vector of indices so that they refer to values sorted according + // to the specified sort order + virtual void sort(std::vector& indices, bool ascending = true) const = 0; + // Modifies a vector of indices so that they refer to distinct values. + // If 'sort_order' is supplied, the indices will refer to values in sort order, + // otherwise the indices will be in original order. + virtual void distinct(std::vector& indices, util::Optional sort_order = util::none) const = 0; + + bool is_empty() const + { + return size() == 0; + } + ObjKey get_key() const + { + return m_const_obj->get_key(); + } + bool is_attached() const + { + return m_const_obj->is_valid(); + } + bool has_changed() const + { + update_if_needed(); + if (m_last_content_version != m_content_version) { + m_last_content_version = m_content_version; + return true; + } + return false; + } + ConstTableRef get_table() const + { + return m_const_obj->get_table(); + } + ColKey get_col_key() const + { + return m_col_key; + } + + bool operator==(const ConstLstBase& other) const + { + return get_key() == other.get_key() && get_col_key() == other.get_col_key(); + } + +protected: + template + friend class LstIterator; + friend class Transaction; + + + ConstObj* m_const_obj; + ColKey m_col_key; + bool m_nullable = false; + + mutable std::vector m_deleted; + mutable uint_fast64_t m_content_version = 0; + mutable uint_fast64_t m_last_content_version = 0; + + ConstLstBase(ColKey col_key, ConstObj* obj); + virtual bool init_from_parent() const = 0; + + ref_type get_child_ref(size_t) const noexcept override; + + void update_if_needed() const + { + auto content_version = m_const_obj->get_alloc().get_content_version(); + if (m_const_obj->update_if_needed() || content_version != m_content_version) { + init_from_parent(); + } + } + void update_content_version() const + { + m_content_version = m_const_obj->get_alloc().get_content_version(); + } + // Increase index by one. I we land on and index that is deleted, keep + // increasing until we get to a valid entry. + size_t incr(size_t ndx) const + { + ndx++; + if (!m_deleted.empty()) { + auto it = m_deleted.begin(); + auto end = m_deleted.end(); + while (it != end && *it < ndx) { + ++it; + } + // If entry is deleted, increase further + while (it != end && *it == ndx) { + ++it; + ++ndx; + } + } + return ndx; + } + // Convert from virtual to real index + size_t adjust(size_t ndx) const + { + if (!m_deleted.empty()) { + // Optimized for the case where the iterator is past that last deleted entry + auto it = m_deleted.rbegin(); + auto end = m_deleted.rend(); + while (it != end && *it >= ndx) { + if (*it == ndx) { + throw std::out_of_range("Element was deleted"); + } + ++it; + } + auto diff = end - it; + ndx -= diff; + } + return ndx; + } + void adj_remove(size_t ndx) + { + auto it = m_deleted.begin(); + auto end = m_deleted.end(); + while (it != end && *it <= ndx) { + ++ndx; + ++it; + } + m_deleted.insert(it, ndx); + } + void erase_repl(Replication* repl, size_t ndx) const; + void move_repl(Replication* repl, size_t from, size_t to) const; + void swap_repl(Replication* repl, size_t ndx1, size_t ndx2) const; + void clear_repl(Replication* repl) const; +}; + +/* + * This class implements a forward iterator over the elements in a Lst. + * + * The iterator is stable against deletions in the list. If you try to + * dereference an iterator that points to an element, that is deleted, the + * call will throw. + * + * Values are read into a member variable (m_val). This is the only way to + * implement operator-> and operator* returning a pointer and a reference resp. + * There is no overhead compared to the alternative where operator* would have + * to return T by value. + */ +template +class LstIterator { +public: + typedef std::forward_iterator_tag iterator_category; + typedef const T value_type; + typedef ptrdiff_t difference_type; + typedef const T* pointer; + typedef const T& reference; + + LstIterator(const ConstLstIf* l, size_t ndx) + : m_list(l) + , m_ndx(ndx) + { + } + pointer operator->() + { + m_val = m_list->get(m_list->adjust(m_ndx)); + return &m_val; + } + reference operator*() + { + return *operator->(); + } + LstIterator& operator++() + { + m_ndx = m_list->incr(m_ndx); + return *this; + } + LstIterator operator++(int) + { + LstIterator tmp(*this); + operator++(); + return tmp; + } + + bool operator!=(const LstIterator& rhs) + { + return m_ndx != rhs.m_ndx; + } + + bool operator==(const LstIterator& rhs) + { + return m_ndx == rhs.m_ndx; + } + +private: + friend class Lst; + T m_val; + const ConstLstIf* m_list; + size_t m_ndx; +}; + +template +inline void check_column_type(ColKey col) +{ + if (col && col.get_type() != ColumnTypeTraits::column_id) { + throw LogicError(LogicError::list_type_mismatch); + } +} + +template <> +inline void check_column_type(ColKey col) +{ + if (col && (col.get_type() != col_type_Int || col.get_attrs().test(col_attr_Nullable))) { + throw LogicError(LogicError::list_type_mismatch); + } +} + +template <> +inline void check_column_type>(ColKey col) +{ + if (col && (col.get_type() != col_type_Int || !col.get_attrs().test(col_attr_Nullable))) { + throw LogicError(LogicError::list_type_mismatch); + } +} + +template <> +inline void check_column_type(ColKey col) +{ + if (col && col.get_type() != col_type_LinkList) { + throw LogicError(LogicError::list_type_mismatch); + } +} + +/// This class defines the interface to ConstList, except for the constructor +/// The ConstList class has the ConstObj member m_obj, which should not be +/// inherited from Lst. +template +class ConstLstIf : public virtual ConstLstBase { +public: + /** + * Only member functions not referring to an index in the list will check if + * the object is up-to-date. The logic is that the user must always check the + * size before referring to a particular index, and size() will check for update. + */ + size_t size() const override + { + if (!is_attached()) + return 0; + update_if_needed(); + if (!m_valid) + return 0; + + return m_tree->size(); + } + bool is_null(size_t ndx) const final + { + return m_nullable && get(ndx) == BPlusTree::default_value(true); + } + Mixed get_any(size_t ndx) const final + { + return Mixed(get(ndx)); + } + + Mixed min(size_t* return_ndx = nullptr) const final; + Mixed max(size_t* return_ndx = nullptr) const final; + Mixed sum(size_t* return_cnt = nullptr) const final; + Mixed avg(size_t* return_cnt = nullptr) const final; + + void sort(std::vector& indices, bool ascending = true) const final; + void distinct(std::vector& indices, util::Optional sort_order = util::none) const final; + + T get(size_t ndx) const + { + if (ndx >= ConstLstIf::size()) { + throw std::out_of_range("Index out of range"); + } + return m_tree->get(ndx); + } + T operator[](size_t ndx) const + { + return get(ndx); + } + LstIterator begin() const + { + return LstIterator(this, 0); + } + LstIterator end() const + { + return LstIterator(this, ConstLstIf::size() + m_deleted.size()); + } + size_t find_first(T value) const + { + if (!m_valid && !init_from_parent()) + return not_found; + update_if_needed(); + return m_tree->find_first(value); + } + template + void find_all(T value, Func&& func) const + { + if (m_valid && init_from_parent()) + m_tree->find_all(value, std::forward(func)); + } + const BPlusTree& get_tree() const + { + return *m_tree; + } + +protected: + mutable std::unique_ptr> m_tree; + mutable bool m_valid = false; + + ConstLstIf() + : ConstLstBase(ColKey{}, nullptr) + { + } + + ConstLstIf(Allocator& alloc) + : ConstLstBase(ColKey{}, nullptr) + , m_tree(new BPlusTree(alloc)) + { + check_column_type(m_col_key); + + m_tree->set_parent(this, 0); // ndx not used, implicit in m_owner + } + + ConstLstIf(const ConstLstIf& other) + : ConstLstBase(other.m_col_key, nullptr) + , m_valid(other.m_valid) + { + if (other.m_tree) { + Allocator& alloc = other.m_tree->get_alloc(); + m_tree = std::make_unique>(alloc); + m_tree->set_parent(this, 0); + if (m_valid) + m_tree->init_from_ref(other.m_tree->get_ref()); + } + } + + ConstLstIf(ConstLstIf&& other) noexcept + : ConstLstBase(ColKey{}, nullptr) + , m_tree(std::move(other.m_tree)) + , m_valid(other.m_valid) + { + m_tree->set_parent(this, 0); + } + + ConstLstIf& operator=(const ConstLstIf& other) + { + if (this != &other) { + *this->m_const_obj = *other.m_const_obj; + m_valid = other.m_valid; + m_col_key = other.m_col_key; + m_deleted.clear(); + m_tree = nullptr; + + if (other.m_tree) { + Allocator& alloc = other.m_tree->get_alloc(); + m_tree = std::make_unique>(alloc); + m_tree->set_parent(this, 0); + if (m_valid) + m_tree->init_from_ref(other.m_tree->get_ref()); + } + } + return *this; + } + + bool init_from_parent() const override + { + m_valid = m_tree->init_from_parent(); + update_content_version(); + return m_valid; + } +}; + +template +class ConstLst : public ConstLstIf { +public: + ConstLst(const ConstObj& owner, ColKey col_key); + ConstLst(ConstLst&& other) noexcept + : ConstLstBase(other.m_col_key, &m_obj) + , ConstLstIf(std::move(other)) + , m_obj(std::move(other.m_obj)) + { + ConstLstBase::m_nullable = other.ConstLstBase::m_nullable; + } + +private: + ConstObj m_obj; + void update_child_ref(size_t, ref_type) override + { + } +}; +/* + * This class defines a virtual interface to a writable list + */ +class LstBase : public virtual ConstLstBase { +public: + LstBase() + : ConstLstBase(ColKey{}, nullptr) + { + } + virtual ~LstBase() + { + } + auto clone() const + { + return static_cast(m_const_obj)->get_listbase_ptr(m_col_key); + } + virtual void set_null(size_t ndx) = 0; + virtual void insert_null(size_t ndx) = 0; + virtual void insert_any(size_t ndx, Mixed val) = 0; + virtual void resize(size_t new_size) = 0; + virtual void remove(size_t from, size_t to) = 0; + virtual void move(size_t from, size_t to) = 0; + virtual void swap(size_t ndx1, size_t ndx2) = 0; + virtual void clear() = 0; +}; + +template +class Lst : public ConstLstIf, public LstBase { +public: + using ConstLstIf::m_tree; + using ConstLstIf::get; + + Lst() + : ConstLstBase({}, &m_obj) + { + } + Lst(const Obj& owner, ColKey col_key); + Lst(const Lst& other); + Lst(Lst&& other) noexcept; + + Lst& operator=(const Lst& other); + Lst& operator=(const BPlusTree& other); + + void update_child_ref(size_t, ref_type new_ref) override + { + m_obj.set_int(ConstLstBase::m_col_key, from_ref(new_ref)); + } + + void create() + { + m_tree->create(); + ConstLstIf::m_valid = true; + } + + void set_null(size_t ndx) override + { + set(ndx, BPlusTree::default_value(m_nullable)); + } + + void insert_null(size_t ndx) override + { + insert(ndx, BPlusTree::default_value(m_nullable)); + } + + void insert_any(size_t ndx, Mixed val) override + { + if (val.is_null()) { + insert_null(ndx); + } + else { + insert(ndx, val.get::type>()); + } + } + + void resize(size_t new_size) override + { + update_if_needed(); + size_t current_size = m_tree->size(); + while (new_size > current_size) { + insert_null(current_size++); + } + remove(new_size, current_size); + m_obj.bump_both_versions(); + } + + void add(T value) + { + insert(size(), value); + } + + T set(size_t ndx, T value) + { + REALM_ASSERT_DEBUG(!update_if_needed()); + + if (value_is_null(value) && !m_nullable) + throw LogicError(LogicError::column_not_nullable); + + // get will check for ndx out of bounds + T old = get(ndx); + if (old != value) { + ensure_writeable(); + do_set(ndx, value); + m_obj.bump_content_version(); + } + if (Replication* repl = this->m_const_obj->get_replication()) { + set_repl(repl, ndx, value); + } + return old; + } + + void insert(size_t ndx, T value) + { + REALM_ASSERT_DEBUG(!update_if_needed()); + + if (value_is_null(value) && !m_nullable) + throw LogicError(LogicError::column_not_nullable); + + ensure_created(); + if (ndx > m_tree->size()) { + throw std::out_of_range("Index out of range"); + } + ensure_writeable(); + if (Replication* repl = this->m_const_obj->get_replication()) { + insert_repl(repl, ndx, value); + } + do_insert(ndx, value); + m_obj.bump_content_version(); + } + + T remove(LstIterator& it) + { + return remove(ConstLstBase::adjust(it.m_ndx)); + } + + T remove(size_t ndx) + { + REALM_ASSERT_DEBUG(!update_if_needed()); + ensure_writeable(); + if (Replication* repl = this->m_const_obj->get_replication()) { + ConstLstBase::erase_repl(repl, ndx); + } + T old = get(ndx); + do_remove(ndx); + ConstLstBase::adj_remove(ndx); + m_obj.bump_content_version(); + + return old; + } + + void remove(size_t from, size_t to) override + { + while (from < to) { + remove(--to); + } + } + + void move(size_t from, size_t to) override + { + REALM_ASSERT_DEBUG(!update_if_needed()); + if (from != to) { + ensure_writeable(); + if (Replication* repl = this->m_const_obj->get_replication()) { + ConstLstBase::move_repl(repl, from, to); + } + if (to > from) { + to++; + } + else { + from++; + } + // We use swap here as it handles the special case for StringData where + // 'to' and 'from' points into the same array. In this case you cannot + // set an entry with the result of a get from another entry in the same + // leaf. + m_tree->insert(to, BPlusTree::default_value(m_nullable)); + m_tree->swap(from, to); + m_tree->erase(from); + + m_obj.bump_content_version(); + } + } + + void swap(size_t ndx1, size_t ndx2) override + { + REALM_ASSERT_DEBUG(!update_if_needed()); + if (ndx1 != ndx2) { + if (Replication* repl = this->m_const_obj->get_replication()) { + ConstLstBase::swap_repl(repl, ndx1, ndx2); + } + m_tree->swap(ndx1, ndx2); + m_obj.bump_content_version(); + } + } + + void clear() override + { + ensure_created(); + update_if_needed(); + ensure_writeable(); + if (size() > 0) { + if (Replication* repl = this->m_const_obj->get_replication()) { + ConstLstBase::clear_repl(repl); + } + m_tree->clear(); + m_obj.bump_content_version(); + } + } + +protected: + Obj m_obj; + bool update_if_needed() + { + if (m_obj.update_if_needed()) { + return init_from_parent(); + } + return false; + } + void ensure_created() + { + if (!ConstLstIf::m_valid && m_obj.is_valid()) { + create(); + } + } + void ensure_writeable() + { + if (m_obj.ensure_writeable()) { + init_from_parent(); + } + } + void do_set(size_t ndx, T value) + { + m_tree->set(ndx, value); + } + void do_insert(size_t ndx, T value) + { + m_tree->insert(ndx, value); + } + void do_remove(size_t ndx) + { + m_tree->erase(ndx); + } + void set_repl(Replication* repl, size_t ndx, T value); + void insert_repl(Replication* repl, size_t ndx, T value); +}; + +template +Lst::Lst(const Lst& other) + : ConstLstBase(other.m_col_key, &m_obj) + , ConstLstIf(other) + , m_obj(other.m_obj) +{ + m_nullable = other.m_nullable; +} + +template +Lst::Lst(Lst&& other) noexcept + : ConstLstBase(other.m_col_key, &m_obj) + , ConstLstIf(std::move(other)) + , m_obj(std::move(other.m_obj)) +{ + m_nullable = other.m_nullable; +} + +template +Lst& Lst::operator=(const Lst& other) +{ + ConstLstIf::operator=(other); + m_obj = other.m_obj; + m_nullable = other.m_nullable; + return *this; +} + +template +Lst& Lst::operator=(const BPlusTree& other) +{ + *m_tree = other; + return *this; +} + + +template <> +void Lst::do_set(size_t ndx, ObjKey target_key); + +template <> +void Lst::do_insert(size_t ndx, ObjKey target_key); + +template <> +void Lst::do_remove(size_t ndx); + +template <> +void Lst::clear(); + +// Translate from userfacing index to internal index. +size_t virtual2real(const std::vector& vec, size_t ndx); +// Scan through the list to find unresolved links +void update_unresolved(std::vector& vec, const BPlusTree& tree); + +class ConstLnkLst : public ConstLstIf { +public: + ConstLnkLst() + : ConstLstBase({}, &m_obj) + { + } + + ConstLnkLst(const ConstObj& obj, ColKey col_key) + : ConstLstBase(col_key, &m_obj) + , ConstLstIf(obj.get_alloc()) + , m_obj(obj) + { + this->init_from_parent(); + } + ConstLnkLst(ConstLnkLst&& other) noexcept + : ConstLstBase(other.m_col_key, &m_obj) + , ConstLstIf(std::move(other)) + , m_obj(std::move(other.m_obj)) + , m_unresolved(std::move(other.m_unresolved)) + { + } + + ConstLnkLst& operator=(const ConstLnkLst& other) + { + ConstLstIf::operator=(other); + m_unresolved = other.m_unresolved; + return *this; + } + + size_t size() const override + { + auto full_sz = ConstLstIf::size(); + return full_sz - m_unresolved.size(); + } + + // Getting links + ObjKey get(size_t ndx) const + { + return ConstLstIf::get(virtual2real(m_unresolved, ndx)); + } + + ConstObj operator[](size_t link_ndx) const + { + return get_object(link_ndx); + } + ConstObj get_object(size_t link_ndx) const; + + void update_child_ref(size_t, ref_type) override + { + } + +private: + ConstObj m_obj; + // Sorted set of indices containing unresolved links. + mutable std::vector m_unresolved; + bool init_from_parent() const override; +}; + +class LnkLst : public Lst, public ObjList { +public: + LnkLst() + : ConstLstBase({}, &m_obj) + { + } + LnkLst(const Obj& owner, ColKey col_key); + LnkLst(const LnkLst& other) + : ConstLstBase(other.m_col_key, &m_obj) + , Lst(other) + , m_unresolved(other.m_unresolved) + { + } + LnkLst(LnkLst&& other) noexcept + : ConstLstBase(other.m_col_key, &m_obj) + , Lst(std::move(other)) + , m_unresolved(std::move(other.m_unresolved)) + { + } + LnkLst& operator=(const LnkLst& other) + { + Lst::operator=(other); + m_unresolved = other.m_unresolved; + return *this; + } + + LnkLstPtr clone() const + { + if (m_obj.is_valid()) { + return std::make_unique(m_obj, m_col_key); + } + else { + return std::make_unique(); + } + } + TableRef get_target_table() const override + { + return m_obj.get_target_table(m_col_key); + } + bool is_in_sync() const override + { + return true; + } + size_t size() const override + { + auto full_sz = Lst::size(); + return full_sz - m_unresolved.size(); + } + + bool has_unresolved() const noexcept + { + return !m_unresolved.empty(); + } + + bool is_obj_valid(size_t) const noexcept override + { + // A link list cannot contain null values + return true; + } + + Obj get_object(size_t ndx) const override; + + Obj operator[](size_t ndx) + { + return get_object(ndx); + } + + using Lst::find_first; + using Lst::find_all; + void add(ObjKey value) + { + insert(size(), value); + } + void set(size_t ndx, ObjKey value); + void insert(size_t ndx, ObjKey value); + ObjKey get(size_t ndx) const + { + return Lst::get(virtual2real(m_unresolved, ndx)); + } + ObjKey get_key(size_t ndx) const override + { + return get(ndx); + } + void remove(size_t ndx) + { + Lst::remove(virtual2real(m_unresolved, ndx)); + } + void remove(size_t from, size_t to) override + { + while (from < to) { + remove(--to); + } + } + void clear() override + { + Lst::clear(); + m_unresolved.clear(); + } + // Create a new object in insert a link to it + Obj create_and_insert_linked_object(size_t ndx); + // Create a new object and link it. If an embedded object + // is already set, it will be removed. TBD: If a non-embedded + // object is already set, we throw LogicError (to prevent + // dangling objects, since they do not delete automatically + // if they are not embedded...) + Obj create_and_set_linked_object(size_t ndx); + // to be implemented: + Obj clear_linked_object(size_t ndx); + + TableView get_sorted_view(SortDescriptor order) const; + TableView get_sorted_view(ColKey column_key, bool ascending = true) const; + void remove_target_row(size_t link_ndx); + void remove_all_target_rows(); + +private: + friend class DB; + friend class ConstTableView; + friend class Query; + + // Sorted set of indices containing unresolved links. + mutable std::vector m_unresolved; + + void get_dependencies(TableVersions&) const override; + void sync_if_needed() const override; + bool init_from_parent() const override; +}; + +template +ConstLst ConstObj::get_list(ColKey col_key) const +{ + return ConstLst(*this, col_key); +} + +template +ConstLstPtr ConstObj::get_list_ptr(ColKey col_key) const +{ + Obj obj(*this); + return std::const_pointer_cast>(obj.get_list_ptr(col_key)); +} + +template +Lst Obj::get_list(ColKey col_key) const +{ + return Lst(*this, col_key); +} + +template +LstPtr Obj::get_list_ptr(ColKey col_key) const +{ + return std::make_unique>(*this, col_key); +} + +template <> +inline LstPtr Obj::get_list_ptr(ColKey col_key) const +{ + return get_linklist_ptr(col_key); +} + +inline ConstLnkLst ConstObj::get_linklist(ColKey col_key) const +{ + return ConstLnkLst(*this, col_key); +} + +inline ConstLnkLst ConstObj::get_linklist(StringData col_name) const +{ + return get_linklist(get_column_key(col_name)); +} + +inline ConstLnkLstPtr ConstObj::get_linklist_ptr(ColKey col_key) const +{ + Obj obj(*this); + return obj.get_linklist_ptr(col_key); +} + +inline LnkLst Obj::get_linklist(ColKey col_key) const +{ + return LnkLst(*this, col_key); +} + +inline LnkLstPtr Obj::get_linklist_ptr(ColKey col_key) const +{ + return std::make_unique(*this, col_key); +} + +inline LnkLst Obj::get_linklist(StringData col_name) const +{ + return get_linklist(get_column_key(col_name)); +} + +template +inline ColumnSumType list_sum(const ConstLstIf& list, size_t* return_cnt = nullptr) +{ + return bptree_sum(list.get_tree(), return_cnt); +} + +template +inline ColumnMinMaxType list_maximum(const ConstLstIf& list, size_t* return_ndx = nullptr) +{ + return bptree_maximum(list.get_tree(), return_ndx); +} + +template +inline ColumnMinMaxType list_minimum(const ConstLstIf& list, size_t* return_ndx = nullptr) +{ + return bptree_minimum(list.get_tree(), return_ndx); +} + +template +inline ColumnAverageType list_average(const ConstLstIf& list, size_t* return_cnt = nullptr) +{ + return bptree_average(list.get_tree(), return_cnt); +} +} + +#endif /* REALM_LIST_HPP */ diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/metrics/metric_timer.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/metrics/metric_timer.hpp new file mode 100644 index 0000000..b80c6f5 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/metrics/metric_timer.hpp @@ -0,0 +1,100 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_METRIC_TIMER_HPP +#define REALM_METRIC_TIMER_HPP + +#include + +#include +#include +#include + +namespace realm { +namespace metrics { + +using nanosecond_storage_t = int64_t; + +class MetricTimerResult { +public: + MetricTimerResult(); + ~MetricTimerResult(); + nanosecond_storage_t get_elapsed_nanoseconds() const; + void report_nanoseconds(nanosecond_storage_t time); + +protected: + nanosecond_storage_t m_elapsed_nanoseconds; +}; + + +class MetricTimer { +public: + MetricTimer(std::shared_ptr destination = nullptr); + ~MetricTimer(); + + void reset(); + + /// Returns elapsed time in nanoseconds since last call to reset(). + nanosecond_storage_t get_elapsed_nanoseconds() const; + /// Same as get_elapsed_time(). + operator nanosecond_storage_t() const; + + /// Format the elapsed time on the form 0h00m, 00m00s, 00.00s, or + /// 000.0ms depending on magnitude. + static void format(nanosecond_storage_t nanoseconds, std::ostream&); + + static std::string format(nanosecond_storage_t nanoseconds); + +private: + using clock_type = std::chrono::high_resolution_clock; + using time_point = std::chrono::time_point; + time_point m_start; + time_point m_paused_at; + std::shared_ptr m_dest; + + time_point get_timer_ticks() const; + nanosecond_storage_t calc_elapsed_nanoseconds(time_point begin, time_point end) const; +}; + + +inline void MetricTimer::reset() +{ + m_start = get_timer_ticks(); +} + +inline nanosecond_storage_t MetricTimer::get_elapsed_nanoseconds() const +{ + return calc_elapsed_nanoseconds(m_start, get_timer_ticks()); +} + +inline MetricTimer::operator nanosecond_storage_t() const +{ + return get_elapsed_nanoseconds(); +} + +inline std::ostream& operator<<(std::ostream& out, const MetricTimer& timer) +{ + MetricTimer::format(timer, out); + return out; +} + + +} // namespace metrics +} // namespace realm + +#endif // REALM_METRIC_TIMER_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/metrics/metrics.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/metrics/metrics.hpp new file mode 100644 index 0000000..3e9ff00 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/metrics/metrics.hpp @@ -0,0 +1,76 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_METRICS_HPP +#define REALM_METRICS_HPP + +#include + +#include +#include +#include +#include "realm/util/fixed_size_buffer.hpp" + +namespace realm { + +class Group; + +namespace metrics { + +class Metrics { +public: + Metrics(size_t max_history_size); + ~Metrics() noexcept; + size_t num_query_metrics() const; + size_t num_transaction_metrics() const; + + void add_query(QueryInfo info); + void add_transaction(TransactionInfo info); + + void start_read_transaction(); + void start_write_transaction(); + void end_read_transaction(size_t total_size, size_t free_space, size_t num_objects, size_t num_versions, + size_t num_decrypted_pages); + void end_write_transaction(size_t total_size, size_t free_space, size_t num_objects, size_t num_versions, + size_t num_decrypted_pages); + static std::unique_ptr report_fsync_time(const Group& g); + static std::unique_ptr report_write_time(const Group& g); + + using QueryInfoList = util::FixedSizeBuffer; + using TransactionInfoList = util::FixedSizeBuffer; + + // Get the list of metric objects tracked since the last take + std::unique_ptr take_queries(); + std::unique_ptr take_transactions(); + +private: + std::unique_ptr m_query_info; + std::unique_ptr m_transaction_info; + + std::unique_ptr m_pending_read; + std::unique_ptr m_pending_write; + + size_t m_max_num_queries; + size_t m_max_num_transactions; +}; + +} // namespace metrics +} // namespace realm + + +#endif // REALM_METRICS_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/metrics/query_info.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/metrics/query_info.hpp new file mode 100644 index 0000000..7bc9795 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/metrics/query_info.hpp @@ -0,0 +1,70 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_QUERY_INFO_HPP +#define REALM_QUERY_INFO_HPP + +#include +#include +#include + +#include +#include +#include + +namespace realm { + +class Query; // forward declare in namespace realm + +namespace metrics { + +class QueryInfo { +public: + enum QueryType { + type_Find, + type_FindAll, + type_Count, + type_Sum, + type_Average, + type_Maximum, + type_Minimum, + type_Invalid + }; + + QueryInfo(const Query* query, QueryType type); + ~QueryInfo() noexcept; + + std::string get_description() const; + std::string get_table_name() const; + QueryType get_type() const; + nanosecond_storage_t get_query_time_nanoseconds() const; + + static std::unique_ptr track(const Query* query, QueryType type); + static QueryType type_from_action(Action action); + +private: + std::string m_description; + std::string m_table_name; + QueryType m_type; + std::shared_ptr m_query_time; +}; + +} // namespace metrics +} // namespace realm + +#endif // REALM_QUERY_INFO_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/metrics/transaction_info.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/metrics/transaction_info.hpp new file mode 100644 index 0000000..2706024 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/metrics/transaction_info.hpp @@ -0,0 +1,73 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_TRANSACTION_INFO_HPP +#define REALM_TRANSACTION_INFO_HPP + +#include +#include + +#include +#include + +namespace realm { +namespace metrics { + +class Metrics; + +class TransactionInfo { +public: + enum TransactionType { read_transaction, write_transaction }; + TransactionInfo(TransactionType type); + TransactionInfo(const TransactionInfo&) = default; + ~TransactionInfo() noexcept; + + TransactionType get_transaction_type() const; + // the transaction time is a total amount which includes fsync_time + write_time + user_time + nanosecond_storage_t get_transaction_time_nanoseconds() const; + nanosecond_storage_t get_fsync_time_nanoseconds() const; + nanosecond_storage_t get_write_time_nanoseconds() const; + size_t get_disk_size() const; + size_t get_free_space() const; + size_t get_total_objects() const; + size_t get_num_available_versions() const; + size_t get_num_decrypted_pages() const; + +private: + MetricTimerResult m_transaction_time; + std::shared_ptr m_fsync_time; + std::shared_ptr m_write_time; + MetricTimer m_transact_timer; + + size_t m_realm_disk_size; + size_t m_realm_free_space; + size_t m_total_objects; + TransactionType m_type; + size_t m_num_versions; + size_t m_num_decrypted_pages; + + friend class Metrics; + void update_stats(size_t disk_size, size_t free_space, size_t total_objects, size_t available_versions, + size_t num_decrypted_pages); + void finish_timer(); +}; + +} // namespace metrics +} // namespace realm + +#endif // REALM_TRANSACTION_INFO_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/mixed.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/mixed.hpp new file mode 100644 index 0000000..3cef8b8 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/mixed.hpp @@ -0,0 +1,464 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_MIXED_HPP +#define REALM_MIXED_HPP + +#include // int64_t - not part of C++03, not even required by C++11 (see C++11 section 18.4.1) + +#include // size_t +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace realm { + + +/// This class represents a polymorphic Realm value. +/// +/// At any particular moment an instance of this class stores a +/// definite value of a definite type. If, for instance, that is an +/// integer value, you may call get() to extract that value. You +/// may call get_type() to discover what type of value is currently +/// stored. Calling get() on an instance that does not store an +/// integer, has undefined behavior, and likewise for all the other +/// types that can be stored. +/// +/// It is crucial to understand that the act of extracting a value of +/// a particular type requires definite knowledge about the stored +/// type. Calling a getter method for any particular type, that is not +/// the same type as the stored value, has undefined behavior. +/// +/// While values of numeric types are contained directly in a Mixed +/// instance, character and binary data are merely referenced. A Mixed +/// instance never owns the referenced data, nor does it in any other +/// way attempt to manage its lifetime. +/// +/// For compatibility with C style strings, when a string (character +/// data) is stored in a Realm database, it is always followed by a +/// terminating null character. This is also true when strings are +/// stored in a mixed type column. This means that in the following +/// code, if the 'mixed' value of the 8th row stores a string, then \c +/// c_str will always point to a null-terminated string: +/// +/// \code{.cpp} +/// +/// const char* c_str = my_table[7].mixed.data(); // Always null-terminated +/// +/// \endcode +/// +/// Note that this assumption does not hold in general for strings in +/// instances of Mixed. Indeed there is nothing stopping you from +/// constructing a new Mixed instance that refers to a string without +/// a terminating null character. +/// +/// At the present time no soultion has been found that would allow +/// for a Mixed instance to directly store a reference to a table. The +/// problem is roughly as follows: From most points of view, the +/// desirable thing to do, would be to store the table reference in a +/// Mixed instance as a plain pointer without any ownership +/// semantics. This would have no negative impact on the performance +/// of copying and destroying Mixed instances, and it would serve just +/// fine for passing a table as argument when setting the value of an +/// entry in a mixed column. In that case a copy of the referenced +/// table would be inserted into the mixed column. +/// +/// On the other hand, when retrieving a table reference from a mixed +/// column, storing it as a plain pointer in a Mixed instance is no +/// longer an acceptable option. The complex rules for managing the +/// lifetime of a Table instance, that represents a subtable, +/// necessitates the use of a "smart pointer" such as +/// TableRef. Enhancing the Mixed class to be able to act as a +/// TableRef would be possible, but would also lead to several new +/// problems. One problem is the risk of a Mixed instance outliving a +/// stack allocated Table instance that it references. This would be a +/// fatal error. Another problem is the impact that the nontrivial +/// table reference has on the performance of copying and destroying +/// Mixed instances. +/// +/// \sa StringData +class Mixed { +public: + Mixed() noexcept + : m_type(0) + { + } + + Mixed(util::None) noexcept + : Mixed() + { + } + + Mixed(int i) noexcept + : Mixed(int64_t(i)) + { + } + Mixed(int64_t) noexcept; + Mixed(bool) noexcept; + Mixed(float) noexcept; + Mixed(double) noexcept; + Mixed(util::Optional) noexcept; + Mixed(util::Optional) noexcept; + Mixed(util::Optional) noexcept; + Mixed(util::Optional) noexcept; + Mixed(StringData) noexcept; + Mixed(BinaryData) noexcept; + Mixed(Timestamp) noexcept; + Mixed(Decimal128); + Mixed(ObjectId) noexcept; + Mixed(util::Optional) noexcept; + Mixed(ObjKey) noexcept; + + // These are shortcuts for Mixed(StringData(c_str)), and are + // needed to avoid unwanted implicit conversion of char* to bool. + Mixed(char* c_str) noexcept + : Mixed(StringData(c_str)) + { + } + Mixed(const char* c_str) noexcept + : Mixed(StringData(c_str)) + { + } + Mixed(const std::string& s) noexcept + : Mixed(StringData(s)) + { + } + + ~Mixed() noexcept + { + } + + DataType get_type() const noexcept + { + REALM_ASSERT(m_type); + return DataType(m_type - 1); + } + + template + T get() const noexcept; + + // These functions are kept to be backwards compatible + int64_t get_int() const; + bool get_bool() const; + float get_float() const; + double get_double() const; + StringData get_string() const; + BinaryData get_binary() const; + Timestamp get_timestamp() const; + + bool is_null() const; + int compare(const Mixed& b) const; + bool operator==(const Mixed& other) const + { + return compare(other) == 0; + } + bool operator!=(const Mixed& other) const + { + return compare(other) != 0; + } + bool operator<(const Mixed& other) const + { + return compare(other) < 0; + } + bool operator>(const Mixed& other) const + { + return compare(other) > 0; + } + +private: + friend std::ostream& operator<<(std::ostream& out, const Mixed& m); + + uint32_t m_type; + union { + int64_t int_val; + bool bool_val; + float float_val; + double double_val; + StringData string_val; + BinaryData binary_val; + Timestamp date_val; + ObjectId id_val; + Decimal128 decimal_val; + }; +}; + +// Implementation: + +inline Mixed::Mixed(int64_t v) noexcept +{ + m_type = type_Int + 1; + int_val = v; +} + +inline Mixed::Mixed(bool v) noexcept +{ + m_type = type_Bool + 1; + bool_val = v; +} + +inline Mixed::Mixed(float v) noexcept +{ + m_type = type_Float + 1; + float_val = v; +} + +inline Mixed::Mixed(double v) noexcept +{ + m_type = type_Double + 1; + double_val = v; +} + +inline Mixed::Mixed(util::Optional v) noexcept +{ + if (v) { + m_type = type_Int + 1; + int_val = *v; + } + else { + m_type = 0; + } +} + +inline Mixed::Mixed(util::Optional v) noexcept +{ + if (v) { + m_type = type_Bool + 1; + bool_val = *v; + } + else { + m_type = 0; + } +} + +inline Mixed::Mixed(util::Optional v) noexcept +{ + if (v) { + m_type = type_Float + 1; + float_val = *v; + } + else { + m_type = 0; + } +} + +inline Mixed::Mixed(util::Optional v) noexcept +{ + if (v) { + m_type = type_Double + 1; + double_val = *v; + } + else { + m_type = 0; + } +} + +inline Mixed::Mixed(util::Optional v) noexcept +{ + if (v) { + m_type = type_ObjectId + 1; + id_val = *v; + } + else { + m_type = 0; + } +} + +inline Mixed::Mixed(StringData v) noexcept +{ + if (!v.is_null()) { + m_type = type_String + 1; + string_val = v; + } + else { + m_type = 0; + } +} + +inline Mixed::Mixed(BinaryData v) noexcept +{ + if (!v.is_null()) { + m_type = type_Binary + 1; + binary_val = v; + } + else { + m_type = 0; + } +} + +inline Mixed::Mixed(Timestamp v) noexcept +{ + if (!v.is_null()) { + m_type = type_Timestamp + 1; + date_val = v; + } + else { + m_type = 0; + } +} + +inline Mixed::Mixed(Decimal128 v) +{ + if (!v.is_null()) { + m_type = type_Decimal + 1; + decimal_val = v; + } + else { + m_type = 0; + } +} + +inline Mixed::Mixed(ObjectId v) noexcept +{ + m_type = type_ObjectId + 1; + id_val = v; +} + +inline Mixed::Mixed(ObjKey v) noexcept +{ + if (v) { + m_type = type_Link + 1; + int_val = v.value; + } + else { + m_type = 0; + } +} + +template <> +inline int64_t Mixed::get() const noexcept +{ + REALM_ASSERT(get_type() == type_Int); + return int_val; +} + +inline int64_t Mixed::get_int() const +{ + return get(); +} + +template <> +inline bool Mixed::get() const noexcept +{ + REALM_ASSERT(get_type() == type_Bool); + return bool_val; +} + +inline bool Mixed::get_bool() const +{ + return get(); +} + +template <> +inline float Mixed::get() const noexcept +{ + REALM_ASSERT(get_type() == type_Float); + return float_val; +} + +inline float Mixed::get_float() const +{ + return get(); +} + +template <> +inline double Mixed::get() const noexcept +{ + REALM_ASSERT(get_type() == type_Double); + return double_val; +} + +inline double Mixed::get_double() const +{ + return get(); +} + +template <> +inline StringData Mixed::get() const noexcept +{ + REALM_ASSERT(get_type() == type_String); + return string_val; +} + +inline StringData Mixed::get_string() const +{ + return get(); +} + +template <> +inline BinaryData Mixed::get() const noexcept +{ + REALM_ASSERT(get_type() == type_Binary); + return binary_val; +} + +inline BinaryData Mixed::get_binary() const +{ + return get(); +} + +template <> +inline Timestamp Mixed::get() const noexcept +{ + REALM_ASSERT(get_type() == type_Timestamp); + return date_val; +} + +inline Timestamp Mixed::get_timestamp() const +{ + return get(); +} + +template <> +inline Decimal128 Mixed::get() const noexcept +{ + REALM_ASSERT(get_type() == type_Decimal); + return decimal_val; +} + +template <> +inline ObjectId Mixed::get() const noexcept +{ + REALM_ASSERT(get_type() == type_ObjectId); + return id_val; +} + +template <> +inline ObjKey Mixed::get() const noexcept +{ + REALM_ASSERT(get_type() == type_Link); + return ObjKey(int_val); +} + +inline bool Mixed::is_null() const +{ + return (m_type == 0); +} + +std::ostream& operator<<(std::ostream& out, const Mixed& m); + +} // namespace realm + +#endif // REALM_MIXED_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/node.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/node.hpp new file mode 100644 index 0000000..12a264a --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/node.hpp @@ -0,0 +1,378 @@ +/************************************************************************* + * + * Copyright 2018 Realm Inc. + * + * 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 REALM_NODE_HPP +#define REALM_NODE_HPP + +#include +#include + +namespace realm { + +/// Special index value. It has various meanings depending on +/// context. It is returned by some search functions to indicate 'not +/// found'. It is similar in function to std::string::npos. +const size_t npos = size_t(-1); + +/// Alias for realm::npos. +const size_t not_found = npos; + +/// All accessor classes that logically contains other objects must inherit +/// this class. +/// +/// A database node accessor contains information about the parent of the +/// referenced node. This 'reverse' reference is not explicitly present in the +/// underlying node hierarchy, but it is needed when modifying an array. A +/// modification may lead to relocation of the underlying array node, and the +/// parent must be updated accordingly. Since this applies recursivly all the +/// way to the root node, it is essential that the entire chain of parent +/// accessors is constructed and propperly maintained when a particular array is +/// modified. +class ArrayParent { +public: + virtual ~ArrayParent() noexcept {} + + virtual ref_type get_child_ref(size_t child_ndx) const noexcept = 0; + virtual void update_child_ref(size_t child_ndx, ref_type new_ref) = 0; +}; + +/// Provides access to individual array nodes of the database. +/// +/// This class serves purely as an accessor, it assumes no ownership of the +/// referenced memory. +/// +/// An node accessor can be in one of two states: attached or unattached. It is +/// in the attached state if, and only if is_attached() returns true. Most +/// non-static member functions of this class have undefined behaviour if the +/// accessor is in the unattached state. The exceptions are: is_attached(), +/// detach(), create(), init_from_ref(), init_from_mem(), init_from_parent(), +/// has_parent(), get_parent(), set_parent(), get_ndx_in_parent(), +/// set_ndx_in_parent(), adjust_ndx_in_parent(), and get_ref_from_parent(). +/// +/// An node accessor contains information about the parent of the referenced +/// node. This 'reverse' reference is not explicitly present in the +/// underlying node hierarchy, but it is needed when modifying a node. A +/// modification may lead to relocation of the underlying node, and the +/// parent must be updated accordingly. Since this applies recursively all the +/// way to the root node, it is essential that the entire chain of parent +/// accessors is constructed and properly maintained when a particular node is +/// modified. +/// +/// The parent reference (`pointer to parent`, `index in parent`) is updated +/// independently from the state of attachment to an underlying node. In +/// particular, the parent reference remains valid and is unaffected by changes +/// in attachment. These two aspects of the state of the accessor is updated +/// independently, and it is entirely the responsibility of the caller to update +/// them such that they are consistent with the underlying node hierarchy before +/// calling any method that modifies the underlying node. +/// +/// FIXME: This class currently has fragments of ownership, in particular the +/// constructors that allocate underlying memory. On the other hand, the +/// destructor never frees the memory. This is a problematic situation, because +/// it so easily becomes an obscure source of leaks. There are three options for +/// a fix of which the third is most attractive but hardest to implement: (1) +/// Remove all traces of ownership semantics, that is, remove the constructors +/// that allocate memory, but keep the trivial copy constructor. For this to +/// work, it is important that the constness of the accessor has nothing to do +/// with the constness of the underlying memory, otherwise constness can be +/// violated simply by copying the accessor. (2) Disallov copying but associate +/// the constness of the accessor with the constness of the underlying +/// memory. (3) Provide full ownership semantics like is done for Table +/// accessors, and provide a proper copy constructor that really produces a copy +/// of the node. For this to work, the class should assume ownership if, and +/// only if there is no parent. A copy produced by a copy constructor will not +/// have a parent. Even if the original was part of a database, the copy will be +/// free-standing, that is, not be part of any database. For intra, or inter +/// database copying, one would have to also specify the target allocator. +class Node : public NodeHeader { +public: + // FIXME: Should not be public + char* m_data = nullptr; // Points to first byte after header + + /*********************** Constructor / destructor ************************/ + + // The object will not be fully initialized when using this constructor + explicit Node(Allocator& allocator) noexcept + : m_alloc(allocator) + { + } + + virtual ~Node() {} + + /**************************** Initializers *******************************/ + + /// Same as init_from_ref(ref_type) but avoid the mapping of 'ref' to memory + /// pointer. + char* init_from_mem(MemRef mem) noexcept + { + char* header = mem.get_addr(); + m_ref = mem.get_ref(); + m_data = get_data_from_header(header); + m_size = get_size_from_header(header); + + return header; + } + + /************************** access functions *****************************/ + + bool is_attached() const noexcept + { + return m_data != nullptr; + } + + inline bool is_read_only() const noexcept + { + REALM_ASSERT_DEBUG(is_attached()); + return m_alloc.is_read_only(m_ref); + } + + size_t size() const noexcept + { + REALM_ASSERT_DEBUG(is_attached()); + return m_size; + } + + bool is_empty() const noexcept + { + return size() == 0; + } + + ref_type get_ref() const noexcept + { + return m_ref; + } + MemRef get_mem() const noexcept + { + return MemRef(get_header_from_data(m_data), m_ref, m_alloc); + } + Allocator& get_alloc() const noexcept + { + return m_alloc; + } + /// Get the address of the header of this array. + char* get_header() const noexcept + { + return get_header_from_data(m_data); + } + + bool has_parent() const noexcept + { + return m_parent != nullptr; + } + ArrayParent* get_parent() const noexcept + { + return m_parent; + } + size_t get_ndx_in_parent() const noexcept + { + return m_ndx_in_parent; + } + bool has_missing_parent_update() const noexcept + { + return m_missing_parent_update; + } + + /// Get the ref of this array as known to the parent. The caller must ensure + /// that the parent information ('pointer to parent' and 'index in parent') + /// is correct before calling this function. + ref_type get_ref_from_parent() const noexcept + { + REALM_ASSERT_DEBUG(m_parent); + ref_type ref = m_parent->get_child_ref(m_ndx_in_parent); + return ref; + } + + /***************************** modifiers *********************************/ + + /// Detach from the underlying array node. This method has no effect if the + /// accessor is currently unattached (idempotency). + void detach() noexcept + { + m_data = nullptr; + } + + /// Destroy only the array that this accessor is attached to, not the + /// children of that array. See non-static destroy_deep() for an + /// alternative. If this accessor is already in the detached state, this + /// function has no effect (idempotency). + void destroy() noexcept + { + if (!is_attached()) + return; + char* header = get_header_from_data(m_data); + m_alloc.free_(m_ref, header); + m_data = nullptr; + } + + /// Shorthand for `destroy(MemRef(ref, alloc), alloc)`. + static void destroy(ref_type ref, Allocator& alloc) noexcept + { + destroy(MemRef(ref, alloc), alloc); + } + + /// Destroy only the specified array node, not its children. See also + /// destroy_deep(MemRef, Allocator&). + static void destroy(MemRef mem, Allocator& alloc) noexcept + { + alloc.free_(mem); + } + + + /// Setting a new parent affects ownership of the attached array node, if + /// any. If a non-null parent is specified, and there was no parent + /// originally, then the caller passes ownership to the parent, and vice + /// versa. This assumes, of course, that the change in parentship reflects a + /// corresponding change in the list of children in the affected parents. + void set_parent(ArrayParent* parent, size_t ndx_in_parent) noexcept + { + m_parent = parent; + m_ndx_in_parent = ndx_in_parent; + } + void set_ndx_in_parent(size_t ndx) noexcept + { + m_ndx_in_parent = ndx; + } + + void clear_missing_parent_update() + { + m_missing_parent_update = false; + } + + /// Update the parents reference to this child. This requires, of course, + /// that the parent information stored in this child is up to date. If the + /// parent pointer is set to null, this function has no effect. + void update_parent() + { + if (m_parent) { + m_parent->update_child_ref(m_ndx_in_parent, m_ref); + } + else { + m_missing_parent_update = true; + } + } + +protected: + /// The total size in bytes (including the header) of a new empty + /// array. Must be a multiple of 8 (i.e., 64-bit aligned). + static const size_t initial_capacity = 128; + + size_t m_ref; + Allocator& m_alloc; + size_t m_size = 0; // Number of elements currently stored. + +#if REALM_ENABLE_MEMDEBUG + // If m_no_relocation is false, then copy_on_write() will always relocate this array, regardless if it's + // required or not. If it's true, then it will never relocate, which is currently only expeted inside + // GroupWriter::write_group() due to a unique chicken/egg problem (see description there). + bool m_no_relocation = false; +#endif + + void alloc(size_t init_size, size_t new_width); + void copy_on_write() + { +#if REALM_ENABLE_MEMDEBUG + // We want to relocate this array regardless if there is a need or not, in order to catch use-after-free bugs. + // Only exception is inside GroupWriter::write_group() (see explanation at the definition of the + // m_no_relocation + // member) + if (!m_no_relocation) { +#else + if (is_read_only()) { +#endif + do_copy_on_write(); + } + } + void copy_on_write(size_t min_size) + { +#if REALM_ENABLE_MEMDEBUG + // We want to relocate this array regardless if there is a need or not, in order to catch use-after-free bugs. + // Only exception is inside GroupWriter::write_group() (see explanation at the definition of the + // m_no_relocation + // member) + if (!m_no_relocation) { +#else + if (is_read_only()) { +#endif + do_copy_on_write(min_size); + } + } + void ensure_size(size_t min_size) + { + char* header = get_header_from_data(m_data); + size_t orig_capacity_bytes = get_capacity_from_header(header); + if (orig_capacity_bytes < min_size) { + do_copy_on_write(min_size); + } + } + + static MemRef create_node(size_t size, Allocator& alloc, bool context_flag = false, Type type = type_Normal, + WidthType width_type = wtype_Ignore, int width = 1); + + void set_header_size(size_t value) noexcept + { + set_size_in_header(value, get_header()); + } + + // Includes array header. Not necessarily 8-byte aligned. + virtual size_t calc_byte_len(size_t num_items, size_t width) const; + virtual size_t calc_item_count(size_t bytes, size_t width) const noexcept; + static void init_header(char* header, bool is_inner_bptree_node, bool has_refs, bool context_flag, + WidthType width_type, int width, size_t size, size_t capacity) noexcept; + +private: + ArrayParent* m_parent = nullptr; + size_t m_ndx_in_parent = 0; // Ignored if m_parent is null. + bool m_missing_parent_update = false; + + void do_copy_on_write(size_t minimum_size = 0); +}; + +class Spec; + +/// Base class for all nodes holding user data +class ArrayPayload { +public: + virtual ~ArrayPayload(); + virtual void init_from_ref(ref_type) noexcept = 0; + virtual void set_parent(ArrayParent* parent, size_t ndx_in_parent) noexcept = 0; + virtual bool need_spec() const + { + return false; + } + virtual void set_spec(Spec*, size_t) const {} +}; + + +inline void Node::init_header(char* header, bool is_inner_bptree_node, bool has_refs, bool context_flag, + WidthType width_type, int width, size_t size, size_t capacity) noexcept +{ + // Note: Since the header layout contains unallocated bit and/or + // bytes, it is important that we put the entire header into a + // well defined state initially. + std::fill(header, header + header_size, 0); + set_is_inner_bptree_node_in_header(is_inner_bptree_node, header); + set_hasrefs_in_header(has_refs, header); + set_context_flag_in_header(context_flag, header); + set_wtype_in_header(width_type, header); + set_width_in_header(width, header); + set_size_in_header(size, header); + set_capacity_in_header(capacity, header); +} +} // namespace realm + +#endif /* REALM_NODE_HPP */ diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/node_header.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/node_header.hpp new file mode 100644 index 0000000..b5805fc --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/node_header.hpp @@ -0,0 +1,244 @@ +/************************************************************************* + * + * Copyright 2018 Realm Inc. + * + * 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 REALM_NODE_HEADER_HPP +#define REALM_NODE_HEADER_HPP + +#include + +namespace realm { + +const size_t max_array_size = 0x00ffffffL; // Maximum number of elements in an array +const size_t max_array_payload_aligned = 0x07ffffc0L; // Maximum number of bytes that the payload of an array can be +// Even though the encoding supports arrays with size up to max_array_payload_aligned, +// the maximum allocation size is smaller as it must fit within a memory section +// (a contiguous virtual address range). This limitation is enforced in SlabAlloc::do_alloc(). + +class NodeHeader { +public: + enum Type { + type_Normal, + + /// This array is the main array of an innner node of a B+-tree as used + /// in table columns. + type_InnerBptreeNode, + + /// This array may contain refs to subarrays. An element whose least + /// significant bit is zero, is a ref pointing to a subarray. An element + /// whose least significant bit is one, is just a value. It is the + /// responsibility of the application to ensure that non-ref values have + /// their least significant bit set. This will generally be done by + /// shifting the desired vlue to the left by one bit position, and then + /// setting the vacated bit to one. + type_HasRefs + }; + + enum WidthType { + wtype_Bits = 0, // width indicates how many bits every element occupies + wtype_Multiply = 1, // width indicates how many bytes every element occupies + wtype_Ignore = 2, // each element is 1 byte + }; + + static const int header_size = 8; // Number of bytes used by header + + // The encryption layer relies on headers always fitting within a single page. + static_assert(header_size == 8, "Header must always fit in entirely on a page"); + + static char* get_data_from_header(char* header) noexcept + { + return header + header_size; + } + + static char* get_header_from_data(char* data) noexcept + { + return data - header_size; + } + + static const char* get_data_from_header(const char* header) noexcept + { + return get_data_from_header(const_cast(header)); + } + + static bool get_is_inner_bptree_node_from_header(const char* header) noexcept + { + typedef unsigned char uchar; + const uchar* h = reinterpret_cast(header); + return (int(h[4]) & 0x80) != 0; + } + + static bool get_hasrefs_from_header(const char* header) noexcept + { + typedef unsigned char uchar; + const uchar* h = reinterpret_cast(header); + return (int(h[4]) & 0x40) != 0; + } + + static bool get_context_flag_from_header(const char* header) noexcept + { + typedef unsigned char uchar; + const uchar* h = reinterpret_cast(header); + return (int(h[4]) & 0x20) != 0; + } + + static WidthType get_wtype_from_header(const char* header) noexcept + { + typedef unsigned char uchar; + const uchar* h = reinterpret_cast(header); + return WidthType((int(h[4]) & 0x18) >> 3); + } + + static uint_least8_t get_width_from_header(const char* header) noexcept + { + typedef unsigned char uchar; + const uchar* h = reinterpret_cast(header); + return uint_least8_t((1 << (int(h[4]) & 0x07)) >> 1); + } + + static size_t get_size_from_header(const char* header) noexcept + { + typedef unsigned char uchar; + const uchar* h = reinterpret_cast(header); + return (size_t(h[5]) << 16) + (size_t(h[6]) << 8) + h[7]; + } + + static size_t get_capacity_from_header(const char* header) noexcept + { + typedef unsigned char uchar; + const uchar* h = reinterpret_cast(header); + return (size_t(h[0]) << 19) + (size_t(h[1]) << 11) + (h[2] << 3); + } + + static Type get_type_from_header(const char* header) noexcept + { + if (get_is_inner_bptree_node_from_header(header)) + return type_InnerBptreeNode; + if (get_hasrefs_from_header(header)) + return type_HasRefs; + return type_Normal; + } + + static void set_is_inner_bptree_node_in_header(bool value, char* header) noexcept + { + typedef unsigned char uchar; + uchar* h = reinterpret_cast(header); + h[4] = uchar((int(h[4]) & ~0x80) | int(value) << 7); + } + + static void set_hasrefs_in_header(bool value, char* header) noexcept + { + typedef unsigned char uchar; + uchar* h = reinterpret_cast(header); + h[4] = uchar((int(h[4]) & ~0x40) | int(value) << 6); + } + + static void set_context_flag_in_header(bool value, char* header) noexcept + { + typedef unsigned char uchar; + uchar* h = reinterpret_cast(header); + h[4] = uchar((int(h[4]) & ~0x20) | int(value) << 5); + } + + static void set_wtype_in_header(WidthType value, char* header) noexcept + { + // Indicates how to calculate size in bytes based on width + // 0: bits (width/8) * size + // 1: multiply width * size + // 2: ignore 1 * size + typedef unsigned char uchar; + uchar* h = reinterpret_cast(header); + h[4] = uchar((int(h[4]) & ~0x18) | int(value) << 3); + } + + static void set_width_in_header(int value, char* header) noexcept + { + // Pack width in 3 bits (log2) + int w = 0; + while (value) { + ++w; + value >>= 1; + } + REALM_ASSERT_3(w, <, 8); + + typedef unsigned char uchar; + uchar* h = reinterpret_cast(header); + h[4] = uchar((int(h[4]) & ~0x7) | w); + } + + static void set_size_in_header(size_t value, char* header) noexcept + { + REALM_ASSERT_3(value, <=, max_array_size); + typedef unsigned char uchar; + uchar* h = reinterpret_cast(header); + h[5] = uchar((value >> 16) & 0x000000FF); + h[6] = uchar((value >> 8) & 0x000000FF); + h[7] = uchar(value & 0x000000FF); + } + + // Note: There is a copy of this function is test_alloc.cpp + static void set_capacity_in_header(size_t value, char* header) noexcept + { + REALM_ASSERT_3(value, <=, (0xffffff << 3)); + typedef unsigned char uchar; + uchar* h = reinterpret_cast(header); + h[0] = uchar((value >> 19) & 0x000000FF); + h[1] = uchar((value >> 11) & 0x000000FF); + h[2] = uchar(value >> 3 & 0x000000FF); + } + + static size_t get_byte_size_from_header(const char* header) noexcept + { + size_t size = get_size_from_header(header); + uint_least8_t width = get_width_from_header(header); + WidthType wtype = get_wtype_from_header(header); + size_t num_bytes = calc_byte_size(wtype, size, width); + + return num_bytes; + } + + static size_t calc_byte_size(WidthType wtype, size_t size, uint_least8_t width) noexcept + { + size_t num_bytes = 0; + switch (wtype) { + case wtype_Bits: { + // Current assumption is that size is at most 2^24 and that width is at most 64. + // In that case the following will never overflow. (Assuming that size_t is at least 32 bits) + REALM_ASSERT_3(size, <, 0x1000000); + size_t num_bits = size * width; + num_bytes = (num_bits + 7) >> 3; + break; + } + case wtype_Multiply: { + num_bytes = size * width; + break; + } + case wtype_Ignore: + num_bytes = size; + break; + } + + // Ensure 8-byte alignment + num_bytes = (num_bytes + 7) & ~size_t(7); + + num_bytes += header_size; + + return num_bytes; + } +}; +} + +#endif /* REALM_NODE_HEADER_HPP */ diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/null.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/null.hpp new file mode 100644 index 0000000..733e798 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/null.hpp @@ -0,0 +1,172 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_NULL_HPP +#define REALM_NULL_HPP + +#include +#include + +#include +#include +#include +#include + +namespace realm { + +/* +Represents null in Query, find(), get(), set(), etc. + +Float/Double: Realm can both store user-given NaNs and null. Any user-given signaling NaN is converted to +0x7fa00000 (if float) or 0x7ff4000000000000 (if double). Any user-given quiet NaN is converted to +0x7fc00000 (if float) or 0x7ff8000000000000 (if double). So Realm does not preserve the optional bits in +user-given NaNs. + +However, since both clang and gcc on x64 and ARM, and also Java on x64, return these bit patterns when +requesting NaNs, these will actually seem to roundtrip bit-exact for the end-user in most cases. + +If set_null() is called, a null is stored in form of the bit pattern 0xffffffff (if float) or +0xffffffffffffffff (if double). These are quiet NaNs. + +Executing a query that involves a float/double column that contains NaNs gives an undefined result. If +it contains signaling NaNs, it may throw an exception. + +Notes on IEEE: + +A NaN float is any bit pattern `s 11111111 S xxxxxxxxxxxxxxxxxxxxxx` where `s` and `x` are arbitrary, but at +least 1 `x` must be 1. If `S` is 1, it's a quiet NaN, else it's a signaling NaN. + +A NaN doubule is the same as above, but for `s eeeeeeeeeee S xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx` + +The `S` bit is at position 22 (float) or 51 (double). +*/ + +struct null { + null() + { + } + operator int64_t() + { + throw(LogicError::type_mismatch); + } + template + operator util::Optional() + { + return util::none; + } + + template + bool operator==(const T&) const + { + REALM_ASSERT(false); + return false; + } + template + bool operator!=(const T&) const + { + REALM_ASSERT(false); + return false; + } + template + bool operator>(const T&) const + { + REALM_ASSERT(false); + return false; + } + template + bool operator>=(const T&) const + { + REALM_ASSERT(false); + return false; + } + template + bool operator<=(const T&) const + { + REALM_ASSERT(false); + return false; + } + template + bool operator<(const T&) const + { + REALM_ASSERT(false); + return false; + } + + /// Returns whether `v` bitwise equals the null bit-pattern + template + static bool is_null_float(T v) + { + T i = null::get_null_float(); + return std::memcmp(&i, &v, sizeof(T)) == 0; + } + + /// Returns the quiet NaNs that represent null for floats/doubles in Realm in stored payload. + template + static T get_null_float() + { + typename std::conditional::value, uint32_t, uint64_t>::type i; + int64_t double_nan = 0x7ff80000000000aa; + i = std::is_same::value ? 0x7fc000aa : static_cast(double_nan); + T d = type_punning(i); + REALM_ASSERT_DEBUG(std::isnan(d)); + REALM_ASSERT_DEBUG(!is_signaling(d)); + return d; + } + + /// Takes a NaN as argument and returns whether or not it's signaling + template + static bool is_signaling(T v) + { + REALM_ASSERT(std::isnan(static_cast(v))); + typename std::conditional::value, uint32_t, uint64_t>::type i; + size_t signal_bit = std::is_same::value ? 22 : 51; // If this bit is set, it's quiet + i = type_punning(v); + return !(i & (1ull << signal_bit)); + } + + /// Converts any signaling or quiet NaN to their their respective bit patterns that are used on x64 gcc+clang, + /// ARM clang and x64 Java. + template + static T to_realm(T v) + { + if (std::isnan(static_cast(v))) { + typename std::conditional::value, uint32_t, uint64_t>::type i; + if (std::is_same::value) { + i = is_signaling(v) ? 0x7fa00000 : 0x7fc00000; + } + else { + i = static_cast(is_signaling(v) ? 0x7ff4000000000000 : 0x7ff8000000000000); + } + return type_punning(i); + } + else { + return v; + } + } +}; + +template +OS& operator<<(OS& os, const null&) +{ + os << "(null)"; + return os; +} + +} // namespace realm + +#endif // REALM_NULL_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/obj.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/obj.hpp new file mode 100644 index 0000000..f435570 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/obj.hpp @@ -0,0 +1,503 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_OBJ_HPP +#define REALM_OBJ_HPP + +#include +#include +#include +#include +#include + +#define REALM_CLUSTER_IF + +namespace realm { + +class Replication; +class TableView; +class ConstLstBase; +class LstBase; +struct GlobalKey; + +template +class ConstLstIf; + +template +class ConstLst; + +template +class Lst; +template +using LstPtr = std::unique_ptr>; +template +using ConstLstPtr = std::unique_ptr>; +using ConstLstBasePtr = std::unique_ptr; +using LstBasePtr = std::unique_ptr; + +class LnkLst; +class ConstLnkLst; +using LnkLstPtr = std::unique_ptr; +using ConstLnkLstPtr = std::unique_ptr; + +// 'Object' would have been a better name, but it clashes with a class in ObjectStore +class ConstObj { +public: + ConstObj() + : m_table(nullptr) + , m_row_ndx(size_t(-1)) + , m_storage_version(-1) + , m_valid(false) + { + } + ConstObj(ConstTableRef table, MemRef mem, ObjKey key, size_t row_ndx); + + Allocator& get_alloc() const; + + bool operator==(const ConstObj& other) const; + + ObjKey get_key() const + { + return m_key; + } + + GlobalKey get_object_id() const; + + ConstTableRef get_table() const + { + return m_table; + } + + Replication* get_replication() const; + + // Check if this object is default constructed + explicit operator bool() const + { + return m_table != nullptr; + } + + // Check if the object is still alive + bool is_valid() const; + // Will throw if object is not valid + void check_valid() const; + // Delete object from table. Object is invalid afterwards. + void remove(); + // Invalidate + // - this turns the object into a tombstone if links to the object exist. + // - deletes the object is no links to the object exist. + // - To be used by the Sync client. + void invalidate(); + + template + U get(ColKey col_key) const; + + Mixed get_any(ColKey col_key) const; + + template + U get(StringData col_name) const + { + return get(get_column_key(col_name)); + } + bool is_unresolved(ColKey col_key) const; + ConstObj get_linked_object(ColKey link_col_key) const; + int cmp(const ConstObj& other, ColKey col_key) const; + + template + ConstLst get_list(ColKey col_key) const; + template + ConstLstPtr get_list_ptr(ColKey col_key) const; + template + ConstLst get_list(StringData col_name) const + { + return get_list(get_column_key(col_name)); + } + + ConstLnkLst get_linklist(ColKey col_key) const; + ConstLnkLstPtr get_linklist_ptr(ColKey col_key) const; + ConstLnkLst get_linklist(StringData col_name) const; + + ConstLstBasePtr get_listbase_ptr(ColKey col_key) const; + + size_t get_link_count(ColKey col_key) const; + + bool is_null(ColKey col_key) const; + bool is_null(StringData col_name) const + { + return is_null(get_column_key(col_name)); + } + bool has_backlinks(bool only_strong_links) const; + size_t get_backlink_count() const; + size_t get_backlink_count(const Table& origin, ColKey origin_col_key) const; + ObjKey get_backlink(const Table& origin, ColKey origin_col_key, size_t backlink_ndx) const; + TableView get_backlink_view(TableRef src_table, ColKey src_col_key); + + // To be used by the query system when a single object should + // be tested. Will allow a function to be called in the context + // of the owning cluster. + template + bool evaluate(T func) const + { + Cluster cluster(0, get_alloc(), *get_tree_top()); + cluster.init(m_mem); + cluster.set_offset(m_key.value - cluster.get_key_value(m_row_ndx)); + return func(&cluster, m_row_ndx); + } + + void to_json(std::ostream& out, size_t link_depth, std::map& renames, + std::vector& followed) const; + void to_json(std::ostream& out, size_t link_depth = 0, + std::map* renames = nullptr) const + { + std::map renames2; + renames = renames ? renames : &renames2; + + std::vector followed; + to_json(out, link_depth, *renames, followed); + } + + std::string to_string() const; + + // Get the path in a minimal format without including object accessors. + // If you need to obtain additional information for each object in the path, + // you should use get_fat_path() or traverse_path() instead (see below). + struct PathElement; + struct Path { + TableKey top_table; + ObjKey top_objkey; + std::vector path_from_top; + }; + Path get_path() const; + + // Get the fat path to this object expressed as a vector of fat path elements. + // each Fat path elements include a ConstObj allowing for low cost access to the + // objects data. + // For a top-level object, the returned vector will be empty. + // For an embedded object, the vector has the top object as first element, + // and the embedded object itself is not included in the path. + struct FatPathElement; + using FatPath = std::vector; + FatPath get_fat_path() const; + + // For an embedded object, traverse the path leading to this object. + // The PathSizer is called first to set the size of the path + // Then there is one call for each object on that path, starting with the top level object + // The embedded object itself is not considered part of the path. + // Note: You should never provide the path_index for calls to traverse_path. + using Visitor = std::function; + using PathSizer = std::function; + void traverse_path(Visitor v, PathSizer ps, size_t path_index = 0) const; + + +protected: + friend class Obj; + friend class ColumnListBase; + friend class ConstLstBase; + friend class ConstLnkLst; + friend class LnkLst; + friend class LinkMap; + friend class ConstTableView; + friend class Transaction; + friend struct ClusterNode::IteratorState; + + mutable ConstTableRef m_table; + ObjKey m_key; + mutable MemRef m_mem; + mutable size_t m_row_ndx; + mutable uint64_t m_storage_version; + mutable bool m_valid; + + Allocator& _get_alloc() const; + bool update() const; + // update if needed - with and without check of table instance version: + bool update_if_needed() const; + bool _update_if_needed() const; // no check, use only when already checked + template + bool do_is_null(ColKey::Idx col_ndx) const; + + const ClusterTree* get_tree_top() const; + ColKey get_column_key(StringData col_name) const; + TableKey get_table_key() const; + TableRef get_target_table(ColKey col_key) const; + const Spec& get_spec() const; + + template + U _get(ColKey::Idx col_ndx) const; + + template + int cmp(const ConstObj& other, ColKey::Idx col_ndx) const; + int cmp(const ConstObj& other, ColKey::Idx col_ndx) const; + ObjKey get_backlink(ColKey backlink_col, size_t backlink_ndx) const; + std::vector get_all_backlinks(ColKey backlink_col) const; + ObjKey get_unfiltered_link(ColKey col_key) const; +}; + +std::ostream& operator<<(std::ostream&, const ConstObj& obj); + +class Obj : public ConstObj { +public: + Obj() + { + } + Obj(TableRef table, MemRef mem, ObjKey key, size_t row_ndx); + + TableRef get_table() const + { + return m_table.cast_away_const(); + } + + + template + Obj& set(ColKey col_key, U value, bool is_default = false); + // Create a new object and link it. If an embedded object + // is already set, it will be removed. If a non-embedded + // object is already set, we throw LogicError (to prevent + // dangling objects, since they do not delete automatically + // if they are not embedded...) + Obj create_and_set_linked_object(ColKey col_key, bool is_default = false); + // Clear all fields of a linked object returning it to its + // default state. If the object does not exist, create a + // new object and link it. (To Be Implemented) + Obj clear_linked_object(ColKey col_key); + Obj& set(ColKey col_key, Mixed value); + + template + Obj& set(StringData col_name, U value, bool is_default = false) + { + return set(get_column_key(col_name), value, is_default); + } + + Obj& set_null(ColKey col_key, bool is_default = false); + Obj& set_null(StringData col_name, bool is_default = false) + { + return set_null(get_column_key(col_name), is_default); + } + + Obj& add_int(ColKey col_key, int64_t value); + Obj& add_int(StringData col_name, int64_t value) + { + return add_int(get_column_key(col_name), value); + } + + template + Obj& set_list_values(ColKey col_key, const std::vector& values); + + template + std::vector get_list_values(ColKey col_key) const; + + template + Obj& set_all(Head v, Tail... tail); + + void assign(const ConstObj& other); + + Obj get_linked_object(ColKey link_col_key); + + template + Lst get_list(ColKey col_key) const; + template + LstPtr get_list_ptr(ColKey col_key) const; + + template + Lst get_list(StringData col_name) const + { + return get_list(get_column_key(col_name)); + } + + LnkLst get_linklist(ColKey col_key) const; + LnkLstPtr get_linklist_ptr(ColKey col_key) const; + LnkLst get_linklist(StringData col_name) const; + + LstBasePtr get_listbase_ptr(ColKey col_key) const; + void assign_pk_and_backlinks(const ConstObj& other); + +private: + friend class ArrayBacklink; + friend class CascadeState; + friend class Cluster; + friend class ConstLstBase; + friend class ConstObj; + template + friend class Lst; + friend class LnkLst; + friend class Table; + + Obj(const ConstObj& other) + : ConstObj(other) + { + } + template + Obj& _set(size_t col_ndx, Val v); + template + Obj& _set(size_t col_ndx, Head v, Tail... tail); + ColKey spec_ndx2colkey(size_t col_ndx); + bool ensure_writeable(); + void bump_content_version(); + void bump_both_versions(); + template + void do_set_null(ColKey col_key); + + void set_int(ColKey col_key, int64_t value); + void add_backlink(ColKey backlink_col, ObjKey origin_key); + bool remove_one_backlink(ColKey backlink_col, ObjKey origin_key); + void nullify_link(ColKey origin_col, ObjKey target_key); + // Used when inserting a new link. You will not remove existing links in this process + void set_backlink(ColKey col_key, ObjKey new_key) const; + // Used when replacing a link, return true if CascadeState contains objects to remove + bool replace_backlink(ColKey col_key, ObjKey old_key, ObjKey new_key, CascadeState& state) const; + // Used when removing a backlink, return true if CascadeState contains objects to remove + bool remove_backlink(ColKey col_key, ObjKey old_key, CascadeState& state) const; + template + inline void set_spec(T&, ColKey); +}; + +struct ConstObj::FatPathElement { + ConstObj obj; // Object which embeds... + ColKey col_key; // Column holding link or link list which embeds... + size_t index; // index into link list (or 0) +}; + +struct ConstObj::PathElement { + ColKey col_key; // Column holding link or link list which embeds... + size_t index; // index into link list (or 0) +}; + +inline Obj Obj::get_linked_object(ColKey link_col_key) +{ + return ConstObj::get_linked_object(link_col_key); +} + +template <> +Obj& Obj::set(ColKey, int64_t value, bool is_default); + +template <> +Obj& Obj::set(ColKey, ObjKey value, bool is_default); + + +template <> +inline Obj& Obj::set(ColKey col_key, int value, bool is_default) +{ + return set(col_key, int_fast64_t(value), is_default); +} + +template <> +inline Obj& Obj::set(ColKey col_key, uint_fast64_t value, bool is_default) +{ + int_fast64_t value_2 = 0; + if (REALM_UNLIKELY(util::int_cast_with_overflow_detect(value, value_2))) { + REALM_TERMINATE("Unsigned integer too big."); + } + return set(col_key, value_2, is_default); +} + +template <> +inline Obj& Obj::set(ColKey col_key, const char* str, bool is_default) +{ + return set(col_key, StringData(str), is_default); +} + +template <> +inline Obj& Obj::set(ColKey col_key, char* str, bool is_default) +{ + return set(col_key, StringData(str), is_default); +} + +template <> +inline Obj& Obj::set(ColKey col_key, std::string str, bool is_default) +{ + return set(col_key, StringData(str), is_default); +} + +template <> +inline Obj& Obj::set(ColKey col_key, realm::null, bool is_default) +{ + return set_null(col_key, is_default); +} + +template <> +inline Obj& Obj::set(ColKey col_key, util::Optional value, bool is_default) +{ + return value ? set(col_key, *value, is_default) : set_null(col_key, is_default); +} + +template <> +inline Obj& Obj::set(ColKey col_key, util::Optional value, bool is_default) +{ + return value ? set(col_key, *value, is_default) : set_null(col_key, is_default); +} + +template <> +inline Obj& Obj::set(ColKey col_key, util::Optional value, bool is_default) +{ + return value ? set(col_key, *value, is_default) : set_null(col_key, is_default); +} + +template <> +inline Obj& Obj::set(ColKey col_key, util::Optional value, bool is_default) +{ + return value ? set(col_key, *value, is_default) : set_null(col_key, is_default); +} + +template <> +inline Obj& Obj::set(ColKey col_key, util::Optional value, bool is_default) +{ + return value ? set(col_key, *value, is_default) : set_null(col_key, is_default); +} + +template +Obj& Obj::set_list_values(ColKey col_key, const std::vector& values) +{ + size_t sz = values.size(); + auto list = get_list(col_key); + list.resize(sz); + for (size_t i = 0; i < sz; i++) + list.set(i, values[i]); + + return *this; +} + +template +std::vector Obj::get_list_values(ColKey col_key) const +{ + std::vector values; + auto list = get_list(col_key); + for (auto v : list) + values.push_back(v); + + return values; +} + +template +inline Obj& Obj::_set(size_t col_ndx, Val v) +{ + return set(spec_ndx2colkey(col_ndx), v); +} + +template +inline Obj& Obj::_set(size_t col_ndx, Head v, Tail... tail) +{ + set(spec_ndx2colkey(col_ndx), v); + return _set(col_ndx + 1, tail...); +} + +template +inline Obj& Obj::set_all(Head v, Tail... tail) +{ + return _set(0, v, tail...); +} +} + +#endif // REALM_OBJ_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/obj_list.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/obj_list.hpp new file mode 100644 index 0000000..eae8bf0 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/obj_list.hpp @@ -0,0 +1,91 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_OBJ_LIST_HPP +#define REALM_OBJ_LIST_HPP + +#include + +namespace realm { + +class DescriptorOrdering; +class Table; +class ConstTableView; + +class ObjList { +public: + virtual ~ObjList(); + + virtual size_t size() const = 0; + virtual TableRef get_target_table() const = 0; + virtual ObjKey get_key(size_t ndx) const = 0; + virtual bool is_obj_valid(size_t ndx) const noexcept = 0; + virtual Obj get_object(size_t row_ndx) const = 0; + virtual void sync_if_needed() const = 0; + virtual void get_dependencies(TableVersions&) const = 0; + virtual bool is_in_sync() const = 0; + + // Get the versions of all tables which this list depends on + TableVersions get_dependency_versions() const + { + TableVersions ret; + get_dependencies(ret); + return ret; + } + ConstObj operator[](size_t ndx) const + { + return get_object(ndx); + } + ConstObj try_get_object(size_t row_ndx) const + { + REALM_ASSERT(row_ndx < size()); + return is_obj_valid(row_ndx) ? get_object(row_ndx) : ConstObj(); + } + + template + void for_each(F func) const + { + auto sz = size(); + for (size_t i = 0; i < sz; i++) { + auto o = try_get_object(i); + if (o && func(o)) + return; + } + } + + template + size_t find_first(ColKey column_key, T value) const + { + auto sz = size(); + for (size_t i = 0; i < sz; i++) { + auto o = try_get_object(i); + if (o) { + T v = o.get(column_key); + if (v == value) + return i; + } + } + return realm::npos; + } + + template + ConstTableView find_all(ColKey column_key, T value) const; +}; +} + +#endif /* SRC_REALM_OBJ_LIST_HPP_ */ diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/object_id.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/object_id.hpp new file mode 100644 index 0000000..db32558 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/object_id.hpp @@ -0,0 +1,119 @@ +/************************************************************************* + * + * Copyright 2019 Realm Inc. + * + * 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 REALM_OBJECT_ID_HPP +#define REALM_OBJECT_ID_HPP + +#include +#include +#include +#include + +namespace realm { + +class ObjectId { +public: + using ObjectIdBytes = std::array; + + /** + * Constructs an ObjectId with all bytes 0x00. + */ + ObjectId() noexcept = default; + + /** + * Checks if the given string is a valid object id. + */ + static bool is_valid_str(StringData) noexcept; + + /** + * Constructs an ObjectId from 24 hex characters. + */ + ObjectId(const char* init) noexcept; + + /** + * Constructs an ObjectID from an array of 12 unsigned bytes + */ + ObjectId(const ObjectIdBytes& init) noexcept; + + /** + * Constructs an ObjectId with the specified inputs, and a random number + */ + ObjectId(Timestamp d, int machine_id, int process_id) noexcept; + + /** + * Generates a new ObjectId using the algorithm to attempt to avoid collisions. + */ + static ObjectId gen(); + + bool operator==(const ObjectId& other) const + { + return m_bytes == other.m_bytes; + } + bool operator!=(const ObjectId& other) const + { + return m_bytes != other.m_bytes; + } + bool operator>(const ObjectId& other) const + { + return m_bytes > other.m_bytes; + } + bool operator<(const ObjectId& other) const + { + return m_bytes < other.m_bytes; + } + bool operator>=(const ObjectId& other) const + { + return m_bytes >= other.m_bytes; + } + bool operator<=(const ObjectId& other) const + { + return m_bytes <= other.m_bytes; + } + explicit operator Timestamp() const + { + return get_timestamp(); + } + + Timestamp get_timestamp() const; + std::string to_string() const; + ObjectIdBytes to_bytes() const; + size_t hash() const noexcept; + +private: + ObjectIdBytes m_bytes = {}; +}; + +inline std::ostream& operator<<(std::ostream& ostr, const ObjectId& id) +{ + ostr << id.to_string(); + return ostr; +} + +} // namespace realm + +namespace std { +template <> +struct hash { + size_t operator()(const realm::ObjectId& oid) const noexcept + { + return oid.hash(); + } +}; +} // namespace std + +#endif /* REALM_OBJECT_ID_HPP */ diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/owned_data.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/owned_data.hpp new file mode 100644 index 0000000..c707f9d --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/owned_data.hpp @@ -0,0 +1,96 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_OWNED_DATA_HPP +#define REALM_OWNED_DATA_HPP + +#include + +#include +#include + +namespace realm { + +/// A chunk of owned data. +class OwnedData { +public: + /// Construct a null reference. + OwnedData() noexcept + { + } + + /// If \a data_to_copy is 'null', \a data_size must be zero. + OwnedData(const char* data_to_copy, size_t data_size) + : m_size(data_size) + { + REALM_ASSERT_DEBUG(data_to_copy || data_size == 0); + if (data_to_copy) { + m_data = std::unique_ptr(new char[data_size]); + memcpy(m_data.get(), data_to_copy, data_size); + } + } + + /// If \a unique_data is 'null', \a data_size must be zero. + OwnedData(std::unique_ptr unique_data, size_t data_size) noexcept + : m_data(std::move(unique_data)) + , m_size(data_size) + { + REALM_ASSERT_DEBUG(m_data || m_size == 0); + } + + OwnedData(const OwnedData& other) + : OwnedData(other.m_data.get(), other.m_size) + { + } + OwnedData& operator=(const OwnedData& other); + + OwnedData(OwnedData&&) = default; + OwnedData& operator=(OwnedData&&) = default; + + const char* data() const + { + return m_data.get(); + } + size_t size() const + { + return m_size; + } + +private: + std::unique_ptr m_data; + size_t m_size = 0; +}; + +inline OwnedData& OwnedData::operator=(const OwnedData& other) +{ + if (this != &other) { + if (other.m_data) { + m_data = std::unique_ptr(new char[other.m_size]); + memcpy(m_data.get(), other.m_data.get(), other.m_size); + } + else { + m_data = nullptr; + } + m_size = other.m_size; + } + return *this; +} + +} // namespace realm + +#endif // REALM_OWNED_DATA_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/parser/collection_operator_expression.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/parser/collection_operator_expression.hpp new file mode 100644 index 0000000..21d17df --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/parser/collection_operator_expression.hpp @@ -0,0 +1,386 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// 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 REALM_COLLECTION_OPERATOR_EXPRESSION_HPP +#define REALM_COLLECTION_OPERATOR_EXPRESSION_HPP + +#include "primitive_list_expression.hpp" +#include "property_expression.hpp" +#include "parser.hpp" +#include "parser_utils.hpp" + +#include + +#include + +namespace realm { +namespace parser { + +template +struct CollectionOperatorGetter; + +template +struct CollectionOperatorExpression; + +template +void do_init(CollectionOperatorExpression& expression, std::string suffix_path, + parser::KeyPathMapping& mapping); + +template +void do_init(CollectionOperatorExpression& expression, std::string suffix_path, + parser::KeyPathMapping& mapping); + +template +struct CollectionOperatorExpression { + static constexpr parser::Expression::KeyPathOp operation_type = OpType; + std::function link_chain_getter; + ExpressionType pe; + ColKey operative_col_key; + DataType operative_col_type; + + CollectionOperatorExpression(ExpressionType&& exp, std::string suffix_path, parser::KeyPathMapping& mapping) + : pe(exp) + { + link_chain_getter = std::bind(&ExpressionType::link_chain_getter, pe); + do_init(*this, suffix_path, mapping); + } + + template + auto value_of_type_for_query() const + { + return CollectionOperatorGetter::convert(*this); + } +}; + +// Certain operations are disabled for some types (eg. a sum of timestamps is invalid). +// The operations that are supported have a specialisation with std::enable_if for that type below +// any type/operation combination that is not specialised will get the runtime error from the following +// default implementation. The return type is just a dummy to make things compile. +template +struct CollectionOperatorGetter { + static Columns convert(const CollectionOperatorExpression& op) + { + throw std::runtime_error( + util::format("Predicate error: comparison of type '%1' with result of '%2' is not supported.", + util::type_to_str(), util::collection_operator_to_str(op.operation_type))); + } +}; + +template +struct CollectionOperatorGetter< + RetType, parser::Expression::KeyPathOp::Min, PropertyExpression, + typename std::enable_if_t::value>> { + static SubColumnAggregate> + convert(const CollectionOperatorExpression& expr) + { + if (expr.pe.dest_type_is_backlink()) { + return expr.link_chain_getter() + .template column(*expr.pe.get_dest_table(), expr.pe.get_dest_col_key()) + .template column(expr.operative_col_key) + .min(); + } + else { + return expr.link_chain_getter() + .template column(expr.pe.get_dest_col_key()) + .template column(expr.operative_col_key) + .min(); + } + } +}; + +template +struct CollectionOperatorGetter< + RetType, parser::Expression::KeyPathOp::Min, PrimitiveListExpression, + typename std::enable_if_t::value>> { + static ListColumnAggregate> + convert(const CollectionOperatorExpression& expr) + { + return expr.link_chain_getter().template column>(expr.pe.get_dest_col_key()).min(); + } +}; + +template +struct CollectionOperatorGetter< + RetType, parser::Expression::KeyPathOp::Max, PropertyExpression, + typename std::enable_if_t::value>> { + static SubColumnAggregate> + convert(const CollectionOperatorExpression& expr) + { + if (expr.pe.dest_type_is_backlink()) { + return expr.link_chain_getter() + .template column(*expr.pe.get_dest_table(), expr.pe.get_dest_col_key()) + .template column(expr.operative_col_key) + .max(); + } + else { + return expr.link_chain_getter() + .template column(expr.pe.get_dest_col_key()) + .template column(expr.operative_col_key) + .max(); + } + } +}; + +template +struct CollectionOperatorGetter< + RetType, parser::Expression::KeyPathOp::Max, PrimitiveListExpression, + typename std::enable_if_t::value>> { + static ListColumnAggregate> + convert(const CollectionOperatorExpression& expr) + { + return expr.link_chain_getter().template column>(expr.pe.get_dest_col_key()).max(); + } +}; + +template +struct CollectionOperatorGetter< + RetType, parser::Expression::KeyPathOp::Sum, PropertyExpression, + typename std::enable_if_t::value>> { + static SubColumnAggregate> + convert(const CollectionOperatorExpression& expr) + { + if (expr.pe.dest_type_is_backlink()) { + return expr.link_chain_getter() + .template column(*expr.pe.get_dest_table(), expr.pe.get_dest_col_key()) + .template column(expr.operative_col_key) + .sum(); + } + else { + return expr.link_chain_getter() + .template column(expr.pe.get_dest_col_key()) + .template column(expr.operative_col_key) + .sum(); + } + } +}; + +template +struct CollectionOperatorGetter< + RetType, parser::Expression::KeyPathOp::Sum, PrimitiveListExpression, + typename std::enable_if_t::value>> { + static ListColumnAggregate> + convert(const CollectionOperatorExpression& expr) + { + return expr.link_chain_getter().template column>(expr.pe.get_dest_col_key()).sum(); + } +}; + +template +struct CollectionOperatorGetter< + RetType, parser::Expression::KeyPathOp::Avg, PropertyExpression, + typename std::enable_if_t::value>> { + static SubColumnAggregate> + convert(const CollectionOperatorExpression& expr) + { + if (expr.pe.dest_type_is_backlink()) { + return expr.link_chain_getter() + .template column(*expr.pe.get_dest_table(), expr.pe.get_dest_col_key()) + .template column(expr.operative_col_key) + .average(); + } + else { + return expr.link_chain_getter() + .template column(expr.pe.get_dest_col_key()) + .template column(expr.operative_col_key) + .average(); + } + } +}; + +template +struct CollectionOperatorGetter< + RetType, parser::Expression::KeyPathOp::Avg, PrimitiveListExpression, + typename std::enable_if_t::value>> { + static ListColumnAggregate> + convert(const CollectionOperatorExpression& expr) + { + return expr.link_chain_getter().template column>(expr.pe.get_dest_col_key()).average(); + } +}; + +template +struct CollectionOperatorGetter< + RetType, parser::Expression::KeyPathOp::Count, PropertyExpression, + typename std::enable_if_t::value>> { + static LinkCount + convert(const CollectionOperatorExpression& expr) + { + if (expr.pe.dest_type_is_backlink()) { + return expr.link_chain_getter() + .template column(*expr.pe.get_dest_table(), expr.pe.get_dest_col_key()) + .count(); + } + else { + return expr.link_chain_getter().template column(expr.pe.get_dest_col_key()).count(); + } + } +}; + +template +struct CollectionOperatorGetter< + RetType, parser::Expression::KeyPathOp::Count, PrimitiveListExpression, + typename std::enable_if_t::value>> { + static SizeOperator + convert(const CollectionOperatorExpression& expr) + { + return expr.pe.size_of_list>(); + } +}; + +template +struct CollectionOperatorGetter< + RetType, parser::Expression::KeyPathOp::BacklinkCount, PropertyExpression, + typename std::enable_if_t::value>> { + static BacklinkCount convert( + const CollectionOperatorExpression& expr) + { + if (expr.pe.link_chain.empty() || expr.pe.get_dest_col_key() == ColKey()) { + // here we are operating on the current table from a "@links.@count" query with no link keypath prefix + return expr.link_chain_getter().template get_backlink_count(); + } + else { + if (expr.pe.dest_type_is_backlink()) { + return expr.link_chain_getter() + .template column(*expr.pe.get_dest_table(), expr.pe.get_dest_col_key()) + .template backlink_count(); + } + else { + return expr.link_chain_getter() + .template column(expr.pe.get_dest_col_key()) + .template backlink_count(); + } + } + } +}; + +template <> +struct CollectionOperatorGetter { + static SizeOperator + convert(const CollectionOperatorExpression& expr) + { + return expr.link_chain_getter().template column(expr.pe.get_dest_col_key()).size(); + } +}; + +template <> +struct CollectionOperatorGetter { + static SizeOperator + convert(const CollectionOperatorExpression& expr) + { + return expr.link_chain_getter().template column(expr.pe.get_dest_col_key()).size(); + } +}; + +template <> +struct CollectionOperatorGetter { + static ColumnListElementLength convert( + const CollectionOperatorExpression& expr) + { + return expr.link_chain_getter().template column>(expr.pe.get_dest_col_key()).element_lengths(); + } +}; + +template <> +struct CollectionOperatorGetter { + static ColumnListElementLength convert( + const CollectionOperatorExpression& expr) + { + return expr.link_chain_getter().template column>(expr.pe.get_dest_col_key()).element_lengths(); + } +}; + +template +void do_init(CollectionOperatorExpression& expression, std::string suffix_path, + parser::KeyPathMapping& mapping) +{ + using namespace util; + + const bool requires_suffix_path = !( + OpType == parser::Expression::KeyPathOp::SizeString || OpType == parser::Expression::KeyPathOp::SizeBinary || + OpType == parser::Expression::KeyPathOp::Count || OpType == parser::Expression::KeyPathOp::BacklinkCount); + + if (requires_suffix_path) { + const Table* pre_link_table = expression.pe.link_chain_getter().get_base_table(); + REALM_ASSERT(pre_link_table); + StringData list_property_name; + if (expression.pe.dest_type_is_backlink()) { + list_property_name = "linking object"; + } + else { + list_property_name = pre_link_table->get_column_name(expression.pe.get_dest_col_key()); + } + realm_precondition(expression.pe.get_dest_type() == type_LinkList || expression.pe.dest_type_is_backlink(), + util::format("The '%1' operation must be used on a list property, but '%2' is not a list", + util::collection_operator_to_str(OpType), list_property_name)); + + ConstTableRef post_link_table; + if (expression.pe.dest_type_is_backlink()) { + post_link_table = expression.pe.get_dest_table(); + } + else { + post_link_table = expression.pe.get_dest_table()->get_link_target(expression.pe.get_dest_col_key()); + } + REALM_ASSERT(post_link_table); + StringData printable_post_link_table_name = util::get_printable_table_name(*post_link_table); + + KeyPath suffix_key_path = key_path_from_string(suffix_path); + + realm_precondition(suffix_path.size() > 0 && suffix_key_path.size() > 0, + util::format("A property from object '%1' must be provided to perform operation '%2'", + printable_post_link_table_name, util::collection_operator_to_str(OpType))); + size_t index = 0; + KeyPathElement element = mapping.process_next_path(post_link_table, suffix_key_path, index); + + realm_precondition( + suffix_key_path.size() == 1, + util::format("Unable to use '%1' because collection aggreate operations are only supported " + "for direct properties at this time", + suffix_path)); + + expression.operative_col_key = element.col_key; + expression.operative_col_type = DataType(element.col_key.get_type()); + } + else { // !requires_suffix_path + if (!expression.pe.link_chain.empty()) { + expression.operative_col_type = expression.pe.get_dest_type(); + } + + realm_precondition(suffix_path.empty(), + util::format("An extraneous property '%1' was found for operation '%2'", suffix_path, + util::collection_operator_to_str(OpType))); + } +} + +template +void do_init(CollectionOperatorExpression& expression, std::string suffix_path, + parser::KeyPathMapping&) +{ + realm_precondition(suffix_path.empty(), util::format("An extraneous property '%1' was found for operation '%2' " + "when applied to a list of primitive values '%3'", + suffix_path, util::collection_operator_to_str(OpType), + expression.pe.get_dest_table()->get_column_name( + expression.pe.get_dest_col_key()))); + + expression.operative_col_type = expression.pe.get_dest_type(); + expression.operative_col_key = expression.pe.get_dest_col_key(); +} + +} // namespace parser +} // namespace realm + +#endif // REALM_COLLECTION_OPERATOR_EXPRESSION_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/parser/expression_container.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/parser/expression_container.hpp new file mode 100644 index 0000000..d288604 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/parser/expression_container.hpp @@ -0,0 +1,102 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// 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 REALM_EXPRESSION_CONTAINER_HPP +#define REALM_EXPRESSION_CONTAINER_HPP + +#include + +#include "collection_operator_expression.hpp" +#include "parser.hpp" +#include "primitive_list_expression.hpp" +#include "property_expression.hpp" +#include "query_builder.hpp" +#include "subquery_expression.hpp" +#include "value_expression.hpp" + +namespace realm { +namespace parser { + +class ExpressionContainer +{ +public: + ExpressionContainer(Query& query, const parser::Expression& e, query_builder::Arguments& args, + parser::KeyPathMapping& mapping); + + bool is_null(); + + PropertyExpression& get_property(); + PrimitiveListExpression& get_primitive_list(); + ValueExpression& get_value(); + CollectionOperatorExpression& get_min(); + CollectionOperatorExpression& get_max(); + CollectionOperatorExpression& get_sum(); + CollectionOperatorExpression& get_avg(); + CollectionOperatorExpression& get_count(); + CollectionOperatorExpression& get_primitive_min(); + CollectionOperatorExpression& get_primitive_max(); + CollectionOperatorExpression& get_primitive_sum(); + CollectionOperatorExpression& get_primitive_avg(); + CollectionOperatorExpression& + get_primitive_count(); + CollectionOperatorExpression& + get_primitive_string_length(); + CollectionOperatorExpression& + get_primitive_binary_length(); + CollectionOperatorExpression& + get_backlink_count(); + CollectionOperatorExpression& get_size_string(); + CollectionOperatorExpression& get_size_binary(); + SubqueryExpression& get_subexpression(); + + std::vector get_keypaths(); + + DataType check_type_compatibility(DataType type); + DataType get_comparison_type(ExpressionContainer& rhs); + + enum class ExpressionInternal { + exp_Value, + exp_Property, + exp_PrimitiveList, + exp_OpMin, + exp_OpMax, + exp_OpSum, + exp_OpAvg, + exp_OpCount, + exp_OpMinPrimitive, + exp_OpMaxPrimitive, + exp_OpSumPrimitive, + exp_OpAvgPrimitive, + exp_OpCountPrimitive, + exp_OpSizeStringPrimitive, + exp_OpSizeBinaryPrimitive, + exp_OpSizeString, + exp_OpSizeBinary, + exp_OpBacklinkCount, + exp_SubQuery + }; + + ExpressionInternal type; +private: + util::Any storage; +}; + +} // namespace parser +} // namespace realm + +#endif // REALM_EXPRESSION_CONTAINER_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/parser/keypath_mapping.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/parser/keypath_mapping.hpp new file mode 100644 index 0000000..578efc4 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/parser/keypath_mapping.hpp @@ -0,0 +1,88 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// 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 REALM_KEYPATH_MAPPING_HPP +#define REALM_KEYPATH_MAPPING_HPP + +#include + +#include "parser_utils.hpp" + +#include +#include + +namespace realm { +namespace parser { + +struct KeyPathElement { + ConstTableRef table; + ColKey col_key; + enum class KeyPathOperation { None, BacklinkTraversal, BacklinkCount, ListOfPrimitivesElementLength } operation; + bool is_list_of_primitives() const + { + return bool(col_key) && col_key.get_type() != col_type_LinkList && col_key.get_attrs().test(col_attr_List); + } +}; + +class BacklinksRestrictedError : public std::runtime_error { +public: + BacklinksRestrictedError(const std::string& msg) + : std::runtime_error(msg) + { + } + /// runtime_error::what() returns the msg provided in the constructor. +}; + +struct TableAndColHash { + std::size_t operator()(const std::pair& p) const; +}; + + +// This class holds state which allows aliasing variable names in key paths used in queries. +// It is used to allow variable naming in subqueries such as 'SUBQUERY(list, $obj, $obj.intCol = 5).@count' +// It can also be used to allow querying named backlinks if bindings provide the mappings themselves. +class KeyPathMapping { +public: + KeyPathMapping(); + // returns true if added, false if duplicate key already exists + bool add_mapping(ConstTableRef table, std::string name, std::string alias); + void remove_mapping(ConstTableRef table, std::string name); + bool has_mapping(ConstTableRef table, std::string name); + KeyPathElement process_next_path(ConstTableRef table, util::KeyPath& path, size_t& index); + void set_allow_backlinks(bool allow); + bool backlinks_allowed() const + { + return m_allow_backlinks; + } + void set_backlink_class_prefix(std::string prefix); + static LinkChain link_chain_getter(ConstTableRef table, const std::vector& links, + ExpressionComparisonType type = ExpressionComparisonType::Any); + +protected: + bool m_allow_backlinks; + std::string m_backlink_class_prefix; + std::unordered_map, std::string, TableAndColHash> m_mapping; +}; + +std::vector generate_link_chain_from_string(Query& q, const std::string& key_path_string, + KeyPathMapping& mapping); + +} // namespace parser +} // namespace realm + +#endif // REALM_KEYPATH_MAPPING_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/parser/parser.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/parser/parser.hpp new file mode 100644 index 0000000..6eeff73 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/parser/parser.hpp @@ -0,0 +1,167 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// 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 REALM_PARSER_HPP +#define REALM_PARSER_HPP + +#include +#include +#include +#include + +namespace realm { + +namespace parser { + +struct Predicate; + +struct Expression +{ + enum class Type { + None, + Number, + String, + KeyPath, + Argument, + True, + False, + Null, + Timestamp, + Base64, + SubQuery, + ObjectId + } type; + enum class KeyPathOp { None, Min, Max, Avg, Sum, Count, SizeString, SizeBinary, BacklinkCount } collection_op; + std::string s; + std::vector time_inputs; + std::string op_suffix; + std::string subquery_path, subquery_var; + std::shared_ptr subquery; + enum class ComparisonType { Unspecified, Any, All, None } comparison_type = ComparisonType::Unspecified; + Expression(Type t = Type::None, std::string input = "") + : type(t) + , collection_op(KeyPathOp::None) + , s(input) + , comparison_type(ComparisonType::Unspecified) + { + } + Expression(std::vector&& timestamp) + : type(Type::Timestamp) + , collection_op(KeyPathOp::None) + , time_inputs(timestamp) + , comparison_type(ComparisonType::Unspecified) + { + } + Expression(std::string prefix, KeyPathOp op, std::string suffix, ComparisonType agg_type) + : type(Type::KeyPath) + , collection_op(op) + , s(prefix) + , op_suffix(suffix) + , comparison_type(agg_type) + { + } +}; + +struct Predicate +{ + enum class Type + { + Comparison, + Or, + And, + True, + False + } type = Type::And; + + enum class Operator { + None, + Equal, + NotEqual, + LessThan, + LessThanOrEqual, + GreaterThan, + GreaterThanOrEqual, + BeginsWith, + EndsWith, + Contains, + Like, + In + }; + + enum class OperatorOption + { + None, + CaseInsensitive, + }; + + struct Comparison + { + Operator op = Operator::None; + OperatorOption option = OperatorOption::None; + Expression expr[2] = {{Expression::Type::None, ""}, {Expression::Type::None, ""}}; + }; + + struct Compound + { + std::vector sub_predicates; + }; + + Comparison cmpr; + Compound cpnd; + + bool negate = false; + + Predicate(Type t, bool n = false) : type(t), negate(n) {} +}; + +struct DescriptorOrderingState +{ + struct PropertyState + { + std::string key_path; + std::string table_name; + bool ascending; + }; + struct SingleOrderingState + { + std::vector properties; + size_t limit; + enum class DescriptorType { Sort, Distinct, Limit, Include } type; + }; + std::vector orderings; +}; + +struct ParserResult +{ + Predicate predicate; + DescriptorOrderingState ordering; +}; + +ParserResult parse(const char* query); // assumes c-style null termination +ParserResult parse(const std::string& query); +ParserResult parse(const realm::StringData& query); + +DescriptorOrderingState parse_include_path(const realm::StringData& path); + +// run the analysis tool to check for cycles in the grammar +// returns the number of problems found and prints some info to std::cout +size_t analyze_grammar(); +} +} + +#endif // REALM_PARSER_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/parser/parser_utils.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/parser/parser_utils.hpp new file mode 100644 index 0000000..089ad18 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/parser/parser_utils.hpp @@ -0,0 +1,151 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// 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 REALM_PARSER_UTILS_HPP +#define REALM_PARSER_UTILS_HPP + +#include +#include +#include "parser.hpp" + +#include +#include +#include + +namespace realm { + +class Table; +class Timestamp; +class ObjectId; +class Decimal128; +struct Link; + +namespace util { + +// check a precondition and throw an exception if it is not met +// this should be used iff the condition being false indicates a bug in the caller +// of the function checking its preconditions +#define realm_precondition(condition, message) \ + if (!REALM_LIKELY(condition)) { \ + throw std::logic_error(message); \ + } + + +template +const char* type_to_str(); + +template <> +const char* type_to_str(); +template <> +const char* type_to_str(); +template <> +const char* type_to_str(); +template <> +const char* type_to_str(); +template <> +const char* type_to_str(); +template <> +const char* type_to_str(); +template <> +const char* type_to_str(); +template <> +const char* type_to_str(); +template <> +const char* type_to_str(); +template <> +const char* type_to_str(); + +const char* data_type_to_str(DataType type); +const char* collection_operator_to_str(parser::Expression::KeyPathOp op); +const char* comparison_type_to_str(parser::Expression::ComparisonType type); + +using KeyPath = std::vector; +KeyPath key_path_from_string(const std::string &s); +std::string key_path_to_string(const KeyPath& keypath); +StringData get_printable_table_name(StringData name); +StringData get_printable_table_name(const Table& table); + +// Converts ascii c-locale uppercase characters to lower case, +// leaves other char values unchanged. +inline char toLowerAscii(char c) +{ + if (isascii(c) && isupper(c)) { +#if REALM_ANDROID + return tolower(c); // _tolower is not supported on all ABI levels +#else + return _tolower(c); +#endif + } + return c; +} + +template +static constexpr bool TypeMaySupportSpecials = (realm::is_any::value || + std::numeric_limits::is_iec559); +// Looks for +-infinity, NaN +// There is spotty support for these edge cases on some platforms +// so we implement manual checks here +template +inline std::enable_if_t, bool> try_parse_specials(std::string str, T& ret) +{ + std::transform(str.begin(), str.end(), str.begin(), toLowerAscii); + if (std::numeric_limits::has_quiet_NaN && (str == "nan" || str == "+nan")) { + ret = std::numeric_limits::quiet_NaN(); + return true; + } + else if (std::numeric_limits::has_quiet_NaN && (str == "-nan")) { + ret = -std::numeric_limits::quiet_NaN(); + return true; + } + else if (std::numeric_limits::has_infinity && + (str == "+infinity" || str == "infinity" || str == "+inf" || str == "inf")) { + ret = std::numeric_limits::infinity(); + return true; + } + else if (std::numeric_limits::has_infinity && (str == "-infinity" || str == "-inf")) { + ret = -std::numeric_limits::infinity(); + return true; + } + return false; +} + +template +inline std::enable_if_t, bool> try_parse_specials(std::string, T&) +{ + return false; +} + +template +inline T string_to(std::string const& s) +{ + std::istringstream iss(s); + iss.imbue(std::locale::classic()); + T value; + iss >> value; + if (iss.fail()) { + if (!try_parse_specials(s, value)) { + throw std::invalid_argument(util::format("Cannot convert string '%1'", s)); + } + } + return value; +} + +} // namespace utils +} // namespace realm + +#endif // REALM_PARSER_UTILS_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/parser/primitive_list_expression.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/parser/primitive_list_expression.hpp new file mode 100644 index 0000000..a4e6244 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/parser/primitive_list_expression.hpp @@ -0,0 +1,71 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 REALM_PRIMITIVE_LIST_EXPRESSION_HPP +#define REALM_PRIMITIVE_LIST_EXPRESSION_HPP + +#include +#include +#include + +namespace realm { +namespace parser { + +struct PrimitiveListExpression { + Query& query; + std::vector link_chain; + ExpressionComparisonType comparison_type; + DataType get_dest_type() const; + ColKey get_dest_col_key() const; + ConstTableRef get_dest_table() const; + template + T size_of_list() const; + + PrimitiveListExpression(Query& q, std::vector&& chain, ExpressionComparisonType type); + + LinkChain link_chain_getter() const; + + template + auto value_of_type_for_query() const + { + return this->link_chain_getter().template column>(get_dest_col_key()); + } +}; + +inline DataType PrimitiveListExpression::get_dest_type() const +{ + REALM_ASSERT_DEBUG(link_chain.size() > 0); + return DataType(link_chain.back().col_key.get_type()); +} + +inline ColKey PrimitiveListExpression::get_dest_col_key() const +{ + REALM_ASSERT_DEBUG(link_chain.size() > 0); + return link_chain.back().col_key; +} + +inline ConstTableRef PrimitiveListExpression::get_dest_table() const +{ + REALM_ASSERT_DEBUG(link_chain.size() > 0); + return link_chain.back().table; +} + +} // namespace parser +} // namespace realm + +#endif // REALM_PRIMITIVE_LIST_EXPRESSION_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/parser/property_expression.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/parser/property_expression.hpp new file mode 100644 index 0000000..3b2162e --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/parser/property_expression.hpp @@ -0,0 +1,87 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// 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 REALM_PROPERTY_EXPRESSION_HPP +#define REALM_PROPERTY_EXPRESSION_HPP + +#include +#include +#include + +namespace realm { +namespace parser { + +struct PropertyExpression +{ + Query &query; + std::vector link_chain; + ExpressionComparisonType comparison_type; + DataType get_dest_type() const; + ColKey get_dest_col_key() const; + ConstTableRef get_dest_table() const; + bool dest_type_is_backlink() const; + bool dest_type_is_list_of_primitives() const; + + PropertyExpression(Query& q, std::vector&& chain, ExpressionComparisonType type); + + LinkChain link_chain_getter() const; + + template + auto value_of_type_for_query() const + { + return this->link_chain_getter().template column(get_dest_col_key()); + } +}; + +inline DataType PropertyExpression::get_dest_type() const +{ + REALM_ASSERT_DEBUG(link_chain.size() > 0); + REALM_ASSERT_DEBUG(link_chain.back().operation != KeyPathElement::KeyPathOperation::BacklinkCount); + return DataType(link_chain.back().col_key.get_type()); +} + +inline bool PropertyExpression::dest_type_is_backlink() const +{ + REALM_ASSERT_DEBUG(link_chain.size() > 0); + return link_chain.back().operation == KeyPathElement::KeyPathOperation::BacklinkTraversal; +} + +inline bool PropertyExpression::dest_type_is_list_of_primitives() const +{ + REALM_ASSERT_DEBUG(link_chain.size() > 0); + return link_chain.back().is_list_of_primitives(); +} + +inline ColKey PropertyExpression::get_dest_col_key() const +{ + REALM_ASSERT_DEBUG(link_chain.size() > 0); + return link_chain.back().col_key; +} + +inline ConstTableRef PropertyExpression::get_dest_table() const +{ + REALM_ASSERT_DEBUG(link_chain.size() > 0); + return link_chain.back().table; +} + + +} // namespace parser +} // namespace realm + +#endif // REALM_PROPERTY_EXPRESSION_HPP + diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/parser/query_builder.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/parser/query_builder.hpp new file mode 100644 index 0000000..cec09b0 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/parser/query_builder.hpp @@ -0,0 +1,217 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// 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 REALM_QUERY_BUILDER_HPP +#define REALM_QUERY_BUILDER_HPP + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace realm { +class Query; +class Realm; +class Table; +template class BasicRowExpr; +using RowExpr = BasicRowExpr; + +namespace parser { + struct Predicate; + struct DescriptorOrderingState; +} + +namespace query_builder { +class Arguments; + +void apply_predicate(Query& query, const parser::Predicate& predicate, Arguments& arguments, + parser::KeyPathMapping mapping = parser::KeyPathMapping()); + +void apply_ordering(DescriptorOrdering& ordering, ConstTableRef target, const parser::DescriptorOrderingState& state, + Arguments& arguments, parser::KeyPathMapping mapping = parser::KeyPathMapping()); +void apply_ordering(DescriptorOrdering& ordering, ConstTableRef target, const parser::DescriptorOrderingState& state, + parser::KeyPathMapping mapping = parser::KeyPathMapping()); + + +struct AnyContext +{ + template + T unbox(const util::Any& wrapper) { + return util::any_cast(wrapper); + } + bool is_null(const util::Any& wrapper) { + if (!wrapper.has_value()) { + return true; + } + if (wrapper.type() == typeid(realm::null)) { + return true; + } + return false; + } +}; + +class Arguments { +public: + virtual bool bool_for_argument(size_t argument_index) = 0; + virtual long long long_for_argument(size_t argument_index) = 0; + virtual float float_for_argument(size_t argument_index) = 0; + virtual double double_for_argument(size_t argument_index) = 0; + virtual StringData string_for_argument(size_t argument_index) = 0; + virtual BinaryData binary_for_argument(size_t argument_index) = 0; + virtual Timestamp timestamp_for_argument(size_t argument_index) = 0; + virtual ObjKey object_index_for_argument(size_t argument_index) = 0; + virtual ObjectId objectid_for_argument(size_t argument_index) = 0; + virtual Decimal128 decimal128_for_argument(size_t argument_index) = 0; + virtual bool is_argument_null(size_t argument_index) = 0; + + // dynamic conversion space with lifetime tied to this + // it is used for storing literal binary/string data + std::vector buffer_space; +}; + +template +class ArgumentConverter : public Arguments { +public: + ArgumentConverter(ContextType& context, const ValueType* arguments, size_t count) + : m_ctx(context) + , m_arguments(arguments) + , m_count(count) + {} + + bool bool_for_argument(size_t i) override { return get(i); } + long long long_for_argument(size_t i) override { return get(i); } + float float_for_argument(size_t i) override { return get(i); } + double double_for_argument(size_t i) override { return get(i); } + StringData string_for_argument(size_t i) override { return get(i); } + BinaryData binary_for_argument(size_t i) override { return get(i); } + Timestamp timestamp_for_argument(size_t i) override { return get(i); } + ObjectId objectid_for_argument(size_t i) override + { + return get(i); + } + Decimal128 decimal128_for_argument(size_t i) override + { + return get(i); + } + ObjKey object_index_for_argument(size_t i) override + { + return get(i); + } + bool is_argument_null(size_t i) override + { + return m_ctx.is_null(at(i)); + } + +private: + ContextType& m_ctx; + const ValueType* m_arguments; + size_t m_count; + + const ValueType& at(size_t index) const + { + if (index >= m_count) { + std::string error_message; + if (m_count) { + error_message = util::format("Request for argument at index %1 but only %2 argument%3 provided", + index, m_count, m_count == 1 ? " is" : "s are"); + } + else { + error_message = util::format("Request for argument at index %1 but no arguments are provided", index); + } + throw std::out_of_range(error_message); + } + return m_arguments[index]; + } + + template + T get(size_t index) const + { + return m_ctx.template unbox(at(index)); + } +}; + +class NoArgsError : public std::runtime_error { +public: + NoArgsError() + : std::runtime_error("Attempt to retreive an argument when no arguments were given") + { + } +}; + +class NoArguments : public Arguments { +public: + bool bool_for_argument(size_t) + { + throw NoArgsError(); + } + long long long_for_argument(size_t) + { + throw NoArgsError(); + } + float float_for_argument(size_t) + { + throw NoArgsError(); + } + double double_for_argument(size_t) + { + throw NoArgsError(); + } + StringData string_for_argument(size_t) + { + throw NoArgsError(); + } + BinaryData binary_for_argument(size_t) + { + throw NoArgsError(); + } + Timestamp timestamp_for_argument(size_t) + { + throw NoArgsError(); + } + ObjectId objectid_for_argument(size_t) + { + throw NoArgsError(); + } + Decimal128 decimal128_for_argument(size_t) + { + throw NoArgsError(); + } + ObjKey object_index_for_argument(size_t) + { + throw NoArgsError(); + } + bool is_argument_null(size_t) + { + throw NoArgsError(); + } +}; + +} // namespace query_builder +} // namespace realm + +#endif // REALM_QUERY_BUILDER_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/parser/subquery_expression.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/parser/subquery_expression.hpp new file mode 100644 index 0000000..1d3eb75 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/parser/subquery_expression.hpp @@ -0,0 +1,115 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// 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 REALM_SUBQUERY_EXPRESSION_HPP +#define REALM_SUBQUERY_EXPRESSION_HPP + +#include +#include +#include +#include + +#include "parser_utils.hpp" + +namespace realm { +namespace parser { + +template +struct SubqueryGetter; + +struct SubqueryExpression { + std::string var_name; + Query& query; + Query subquery; + std::vector link_chain; + DataType get_dest_type() const; + ColKey get_dest_col_key() const; + ConstTableRef get_dest_table() const; + bool dest_type_is_backlink() const; + + + SubqueryExpression(Query& q, const std::string& key_path_string, const std::string& variable_name, + parser::KeyPathMapping& mapping); + Query& get_subquery(); + + LinkChain link_chain_getter() const; + + template + auto value_of_type_for_query() const + { + return SubqueryGetter::convert(*this); + } +}; + +inline DataType SubqueryExpression::get_dest_type() const +{ + REALM_ASSERT_DEBUG(link_chain.size() > 0); + return DataType(link_chain.back().col_key.get_type()); +} + +inline bool SubqueryExpression::dest_type_is_backlink() const +{ + REALM_ASSERT_DEBUG(link_chain.size() > 0); + return link_chain.back().operation == KeyPathElement::KeyPathOperation::BacklinkTraversal; +} + +inline ColKey SubqueryExpression::get_dest_col_key() const +{ + REALM_ASSERT_DEBUG(link_chain.size() > 0); + return link_chain.back().col_key; +} + +inline ConstTableRef SubqueryExpression::get_dest_table() const +{ + REALM_ASSERT_DEBUG(link_chain.size() > 0); + return link_chain.back().table; +} + +// Certain operations are disabled for some types (eg. a sum of timestamps is invalid). +// The operations that are supported have a specialisation with std::enable_if for that type below +// any type/operation combination that is not specialised will get the runtime error from the following +// default implementation. The return type is just a dummy to make things compile. +template +struct SubqueryGetter { + static Columns convert(const SubqueryExpression&) + { + throw std::runtime_error( + util::format("Predicate error: comparison of type '%1' with result of a subquery count is not supported.", + util::type_to_str())); + } +}; + +template +struct SubqueryGetter::value>> { + static SubQueryCount convert(const SubqueryExpression& expr) + { + if (expr.dest_type_is_backlink()) { + return expr.link_chain_getter() + .template column(*expr.get_dest_table(), expr.get_dest_col_key(), expr.subquery) + .count(); + } + else { + return expr.link_chain_getter().template column(expr.get_dest_col_key(), expr.subquery).count(); + } + } +}; + +} // namespace parser +} // namespace realm + +#endif // REALM_SUBQUERY_EXPRESSION_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/parser/value_expression.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/parser/value_expression.hpp new file mode 100644 index 0000000..994ee5f --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/parser/value_expression.hpp @@ -0,0 +1,87 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// 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 REALM_VALUE_EXPRESSION_HPP +#define REALM_VALUE_EXPRESSION_HPP + +#include "parser.hpp" +#include "query_builder.hpp" + +namespace realm { +namespace parser { + +struct ValueExpression +{ + const parser::Expression* value; + query_builder::Arguments* arguments; + + ValueExpression(query_builder::Arguments* args, const parser::Expression* v); + bool is_null(); + template + bool is_type(); + template + RetType value_of_type_for_query(); +}; + +template +bool ValueExpression::is_type() +{ + try { + // as an optimization, handle the types we can here if it's known + if constexpr (std::is_same_v) { + if (value->type == parser::Expression::Type::Timestamp) { + return true; + } + } + if constexpr (std::is_same_v) { + if (value->type == parser::Expression::Type::ObjectId) { + return true; + } + } + if constexpr (realm::is_any_v) { + if (value->type == parser::Expression::Type::Number) { + return true; + } + } + if constexpr (std::is_same_v) { + if (value->type == parser::Expression::Type::String) { + return true; + } + } + if constexpr (std::is_same_v) { + if (value->type == parser::Expression::Type::True || value->type == parser::Expression::Type::False) { + return true; + } + } + if (value->type == parser::Expression::Type::Null) { + return false; + } + // attempt a cast + value_of_type_for_query(); + } + catch (const std::exception&) { + return false; + } + // the cast succeeded so it is convertible to type T + return true; +} + +} // namespace parser +} // namespace realm + +#endif // REALM_VALUE_EXPRESSION_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/query.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/query.hpp new file mode 100644 index 0000000..600b3e8 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/query.hpp @@ -0,0 +1,414 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_QUERY_HPP +#define REALM_QUERY_HPP + +#include +#include +#include +#include +#include +#include + +#define REALM_MULTITHREAD_QUERY 0 + +#if REALM_MULTITHREAD_QUERY +// FIXME: Use our C++ thread abstraction API since it provides a much +// higher level of encapsulation and safety. +#include +#endif + +#include +#include +#include +#include +#include +#include + +namespace realm { + + +// Pre-declarations +class ParentNode; +class Table; +class TableView; +class ConstTableView; +class Array; +class Expression; +class Group; +class Transaction; + +namespace metrics { +class QueryInfo; +} + +struct QueryGroup { + enum class State { + Default, + OrCondition, + OrConditionChildren, + }; + + QueryGroup() = default; + + QueryGroup(const QueryGroup&); + QueryGroup& operator=(const QueryGroup&); + + QueryGroup(QueryGroup&&) = default; + QueryGroup& operator=(QueryGroup&&) = default; + + std::unique_ptr m_root_node; + + bool m_pending_not = false; + State m_state = State::Default; +}; + +class Query final { +public: + Query(ConstTableRef table, ConstTableView* tv = nullptr); + Query(ConstTableRef table, std::unique_ptr); + Query(ConstTableRef table, const LnkLst& list); + Query(ConstTableRef table, LnkLstPtr&& list); + Query(); + Query(std::unique_ptr); + ~Query() noexcept; + + Query(const Query& copy); + Query& operator=(const Query& source); + + Query(Query&&); + Query& operator=(Query&&); + + // Find links that point to a specific target row + Query& links_to(ColKey column_key, ObjKey target_key); + // Find links that point to specific target objects + Query& links_to(ColKey column_key, const std::vector& target_obj); + + // Conditions: null + Query& equal(ColKey column_key, null); + Query& not_equal(ColKey column_key, null); + + // Conditions: int64_t + Query& equal(ColKey column_key, int64_t value); + Query& not_equal(ColKey column_key, int64_t value); + Query& greater(ColKey column_key, int64_t value); + Query& greater_equal(ColKey column_key, int64_t value); + Query& less(ColKey column_key, int64_t value); + Query& less_equal(ColKey column_key, int64_t value); + Query& between(ColKey column_key, int64_t from, int64_t to); + + // Conditions: int (we need those because conversion from '1234' is ambiguous with float/double) + Query& equal(ColKey column_key, int value); + Query& not_equal(ColKey column_key, int value); + Query& greater(ColKey column_key, int value); + Query& greater_equal(ColKey column_key, int value); + Query& less(ColKey column_key, int value); + Query& less_equal(ColKey column_key, int value); + Query& between(ColKey column_key, int from, int to); + + // Conditions: 2 int columns + Query& equal_int(ColKey column_key1, ColKey column_key2); + Query& not_equal_int(ColKey column_key1, ColKey column_key2); + Query& greater_int(ColKey column_key1, ColKey column_key2); + Query& less_int(ColKey column_key1, ColKey column_key2); + Query& greater_equal_int(ColKey column_key1, ColKey column_key2); + Query& less_equal_int(ColKey column_key1, ColKey column_key2); + + // Conditions: float + Query& equal(ColKey column_key, float value); + Query& not_equal(ColKey column_key, float value); + Query& greater(ColKey column_key, float value); + Query& greater_equal(ColKey column_key, float value); + Query& less(ColKey column_key, float value); + Query& less_equal(ColKey column_key, float value); + Query& between(ColKey column_key, float from, float to); + + // Conditions: 2 float columns + Query& equal_float(ColKey column_key1, ColKey column_key2); + Query& not_equal_float(ColKey column_key1, ColKey column_key2); + Query& greater_float(ColKey column_key1, ColKey column_key2); + Query& greater_equal_float(ColKey column_key1, ColKey column_key2); + Query& less_float(ColKey column_key1, ColKey column_key2); + Query& less_equal_float(ColKey column_key1, ColKey column_key2); + + // Conditions: double + Query& equal(ColKey column_key, double value); + Query& not_equal(ColKey column_key, double value); + Query& greater(ColKey column_key, double value); + Query& greater_equal(ColKey column_key, double value); + Query& less(ColKey column_key, double value); + Query& less_equal(ColKey column_key, double value); + Query& between(ColKey column_key, double from, double to); + + // Conditions: 2 double columns + Query& equal_double(ColKey column_key1, ColKey column_key2); + Query& not_equal_double(ColKey column_key1, ColKey column_key2); + Query& greater_double(ColKey column_key1, ColKey column_key2); + Query& greater_equal_double(ColKey column_key1, ColKey column_key2); + Query& less_double(ColKey column_key1, ColKey column_key2); + Query& less_equal_double(ColKey column_key1, ColKey column_key2); + + // Conditions: timestamp + Query& equal(ColKey column_key, Timestamp value); + Query& not_equal(ColKey column_key, Timestamp value); + Query& greater(ColKey column_key, Timestamp value); + Query& greater_equal(ColKey column_key, Timestamp value); + Query& less_equal(ColKey column_key, Timestamp value); + Query& less(ColKey column_key, Timestamp value); + + // Conditions: ObjectId + Query& equal(ColKey column_key, ObjectId value); + Query& not_equal(ColKey column_key, ObjectId value); + Query& greater(ColKey column_key, ObjectId value); + Query& greater_equal(ColKey column_key, ObjectId value); + Query& less_equal(ColKey column_key, ObjectId value); + Query& less(ColKey column_key, ObjectId value); + + // Conditions: Decimal128 + Query& equal(ColKey column_key, Decimal128 value); + Query& not_equal(ColKey column_key, Decimal128 value); + Query& greater(ColKey column_key, Decimal128 value); + Query& greater_equal(ColKey column_key, Decimal128 value); + Query& less_equal(ColKey column_key, Decimal128 value); + Query& less(ColKey column_key, Decimal128 value); + Query& between(ColKey column_key, Decimal128 from, Decimal128 to); + + // Conditions: size + Query& size_equal(ColKey column_key, int64_t value); + Query& size_not_equal(ColKey column_key, int64_t value); + Query& size_greater(ColKey column_key, int64_t value); + Query& size_greater_equal(ColKey column_key, int64_t value); + Query& size_less_equal(ColKey column_key, int64_t value); + Query& size_less(ColKey column_key, int64_t value); + Query& size_between(ColKey column_key, int64_t from, int64_t to); + + // Conditions: bool + Query& equal(ColKey column_key, bool value); + Query& not_equal(ColKey column_key, bool value); + + // Conditions: strings + Query& equal(ColKey column_key, StringData value, bool case_sensitive = true); + Query& not_equal(ColKey column_key, StringData value, bool case_sensitive = true); + Query& begins_with(ColKey column_key, StringData value, bool case_sensitive = true); + Query& ends_with(ColKey column_key, StringData value, bool case_sensitive = true); + Query& contains(ColKey column_key, StringData value, bool case_sensitive = true); + Query& like(ColKey column_key, StringData value, bool case_sensitive = true); + + // These are shortcuts for equal(StringData(c_str)) and + // not_equal(StringData(c_str)), and are needed to avoid unwanted + // implicit conversion of char* to bool. + Query& equal(ColKey column_key, const char* c_str, bool case_sensitive = true); + Query& not_equal(ColKey column_key, const char* c_str, bool case_sensitive = true); + + // Conditions: binary data + Query& equal(ColKey column_key, BinaryData value, bool case_sensitive = true); + Query& not_equal(ColKey column_key, BinaryData value, bool case_sensitive = true); + Query& begins_with(ColKey column_key, BinaryData value, bool case_sensitive = true); + Query& ends_with(ColKey column_key, BinaryData value, bool case_sensitive = true); + Query& contains(ColKey column_key, BinaryData value, bool case_sensitive = true); + Query& like(ColKey column_key, BinaryData b, bool case_sensitive = true); + + // Negation + Query& Not(); + + // Grouping + Query& group(); + Query& end_group(); + Query& Or(); + + Query& and_query(const Query& q); + Query& and_query(Query&& q); + Query operator||(const Query& q); + Query operator&&(const Query& q); + Query operator!(); + + + // Searching + ObjKey find(); + TableView find_all(size_t start = 0, size_t end = size_t(-1), size_t limit = size_t(-1)); + + // Aggregates + size_t count() const; + TableView find_all(const DescriptorOrdering& descriptor); + size_t count(const DescriptorOrdering& descriptor); + int64_t sum_int(ColKey column_key) const; + double average_int(ColKey column_key, size_t* resultcount = nullptr) const; + int64_t maximum_int(ColKey column_key, ObjKey* return_ndx = nullptr) const; + int64_t minimum_int(ColKey column_key, ObjKey* return_ndx = nullptr) const; + double sum_float(ColKey column_key) const; + double average_float(ColKey column_key, size_t* resultcount = nullptr) const; + float maximum_float(ColKey column_key, ObjKey* return_ndx = nullptr) const; + float minimum_float(ColKey column_key, ObjKey* return_ndx = nullptr) const; + double sum_double(ColKey column_key) const; + double average_double(ColKey column_key, size_t* resultcount = nullptr) const; + double maximum_double(ColKey column_key, ObjKey* return_ndx = nullptr) const; + double minimum_double(ColKey column_key, ObjKey* return_ndx = nullptr) const; + Timestamp maximum_timestamp(ColKey column_key, ObjKey* return_ndx = nullptr); + Timestamp minimum_timestamp(ColKey column_key, ObjKey* return_ndx = nullptr); + Decimal128 sum_decimal128(ColKey column_key) const; + Decimal128 maximum_decimal128(ColKey column_key, ObjKey* return_ndx = nullptr) const; + Decimal128 minimum_decimal128(ColKey column_key, ObjKey* return_ndx = nullptr) const; + Decimal128 average_decimal128(ColKey column_key, size_t* resultcount = nullptr) const; + + // Deletion + size_t remove(); + +#if REALM_MULTITHREAD_QUERY + // Multi-threading + TableView find_all_multi(size_t start = 0, size_t end = size_t(-1)); + ConstTableView find_all_multi(size_t start = 0, size_t end = size_t(-1)) const; + int set_threads(unsigned int threadcount); +#endif + + ConstTableRef& get_table() + { + return m_table; + } + + void get_outside_versions(TableVersions&) const; + + // True if matching rows are guaranteed to be returned in table order. + bool produces_results_in_table_order() const + { + return !m_view; + } + + // Calls sync_if_needed on the restricting view, if present. + // Returns the current version of the table(s) this query depends on, + // or empty vector if the query is not associated with a table. + TableVersions sync_view_if_needed() const; + + std::string validate(); + + std::string get_description() const; + std::string get_description(util::serializer::SerialisationState& state) const; + + bool eval_object(ConstObj& obj) const; + +private: + void create(); + + void init() const; + size_t find_internal(size_t start = 0, size_t end = size_t(-1)) const; + void handle_pending_not(); + void set_table(TableRef tr); +public: + std::unique_ptr clone_for_handover(Transaction* tr, PayloadPolicy policy) const + { + return std::make_unique(this, tr, policy); + } + + Query(const Query* source, Transaction* tr, PayloadPolicy policy); + Query(const Query& source, Transaction* tr, PayloadPolicy policy) + : Query(&source, tr, policy) + { + } + +private: + void add_expression_node(std::unique_ptr); + + template + Query& equal(ColKey column_key1, ColKey column_key2); + + template + Query& less(ColKey column_key1, ColKey column_key2); + + template + Query& less_equal(ColKey column_key1, ColKey column_key2); + + template + Query& greater(ColKey column_key1, ColKey column_key2); + + template + Query& greater_equal(ColKey column_key1, ColKey column_key2); + + template + Query& not_equal(ColKey column_key1, ColKey column_key2); + + template + Query& add_condition(ColKey column_key, T value); + + template + Query& add_size_condition(ColKey column_key, int64_t value); + + template + double average(ColKey column_key, size_t* resultcount = nullptr) const; + + template + R aggregate(ColKey column_key, size_t* resultcount = nullptr, ObjKey* return_ndx = nullptr) const; + + size_t find_best_node(ParentNode* pn) const; + void aggregate_internal(ParentNode* pn, QueryStateBase* st, size_t start, size_t end, + ArrayPayload* source_column) const; + + void find_all(ConstTableView& tv, size_t start = 0, size_t end = size_t(-1), size_t limit = size_t(-1)) const; + size_t do_count(size_t limit = size_t(-1)) const; + void delete_nodes() noexcept; + + bool has_conditions() const + { + return m_groups.size() > 0 && m_groups[0].m_root_node; + } + ParentNode* root_node() const + { + REALM_ASSERT(m_groups.size()); + return m_groups[0].m_root_node.get(); + } + + void add_node(std::unique_ptr); + + friend class Table; + friend class ConstTableView; + friend class SubQueryCount; + friend class PrimitiveListCount; + friend class metrics::QueryInfo; + + std::string error_code; + + std::vector m_groups; + mutable std::vector m_table_keys; + + TableRef m_table; + + // points to the base class of the restricting view. If the restricting + // view is a link view, m_source_link_list is non-zero. If it is a table view, + // m_source_table_view is non-zero. + ObjList* m_view = nullptr; + + // At most one of these can be non-zero, and if so the non-zero one indicates the restricting view. + LnkLstPtr m_source_link_list; // link lists are owned by the query. + ConstTableView* m_source_table_view = nullptr; // table views are not refcounted, and not owned by the query. + std::unique_ptr m_owned_source_table_view; // <--- except when indicated here +}; + +// Implementation: + +inline Query& Query::equal(ColKey column_key, const char* c_str, bool case_sensitive) +{ + return equal(column_key, StringData(c_str), case_sensitive); +} + +inline Query& Query::not_equal(ColKey column_key, const char* c_str, bool case_sensitive) +{ + return not_equal(column_key, StringData(c_str), case_sensitive); +} + +} // namespace realm + +#endif // REALM_QUERY_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/query_conditions.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/query_conditions.hpp new file mode 100644 index 0000000..bddc8b7 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/query_conditions.hpp @@ -0,0 +1,914 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_QUERY_CONDITIONS_HPP +#define REALM_QUERY_CONDITIONS_HPP + +#include +#include + +#include +#include +#include + +namespace realm { + +enum Action { + act_ReturnFirst, + act_Sum, + act_Max, + act_Min, + act_Count, + act_FindAll, + act_CallIdx, + act_CallbackIdx, + act_CallbackVal, + act_CallbackNone, + act_CallbackBoth, + act_Average +}; + +class ClusterKeyArray; + +class QueryStateBase { +public: + size_t m_match_count; + size_t m_limit; + int64_t m_minmax_index; // used only for min/max, to save index of current min/max value + uint64_t m_key_offset; + const ClusterKeyArray* m_key_values; + QueryStateBase(size_t limit) + : m_match_count(0) + , m_limit(limit) + , m_minmax_index(-1) + , m_key_offset(0) + , m_key_values(nullptr) + { + } + virtual ~QueryStateBase() + { + } + +private: + virtual void dyncast(); +}; + +template +class QueryState; + + +// Array::VTable only uses the first 4 conditions (enums) in an array of function pointers +enum { cond_Equal, cond_NotEqual, cond_Greater, cond_Less, cond_VTABLE_FINDER_COUNT, cond_None, cond_LeftNotNull }; + +// Quick hack to make "Queries with Integer null columns" able to compile in Visual Studio 2015 which doesn't full +// support sfinae +// (real cause hasn't been investigated yet, cannot exclude that we don't obey c++11 standard) +struct HackClass { + template + bool can_match(A, B, C) + { + REALM_ASSERT(false); + return false; + } + template + bool will_match(A, B, C) + { + REALM_ASSERT(false); + return false; + } +}; + +// Does v2 contain v1? +struct Contains : public HackClass { + bool operator()(StringData v1, const char*, const char*, StringData v2, bool = false, bool = false) const + { + return v2.contains(v1); + } + bool operator()(StringData v1, StringData v2, bool = false, bool = false) const + { + return v2.contains(v1); + } + bool operator()(BinaryData v1, BinaryData v2, bool = false, bool = false) const + { + return v2.contains(v1); + } + bool operator()(StringData v1, const std::array &charmap, StringData v2) const + { + return v2.contains(v1, charmap); + } + + template + bool operator()(A, B) const + { + REALM_ASSERT(false); + return false; + } + template + bool operator()(A, B, C, D) const + { + REALM_ASSERT(false); + return false; + } + bool operator()(int64_t, int64_t, bool, bool) const + { + REALM_ASSERT(false); + return false; + } + + static std::string description() + { + return "CONTAINS"; + } + + static const int condition = -1; +}; + +// Does v2 contain something like v1 (wildcard matching)? +struct Like : public HackClass { + bool operator()(StringData v1, const char*, const char*, StringData v2, bool = false, bool = false) const + { + return v2.like(v1); + } + bool operator()(BinaryData b1, const char*, const char*, BinaryData b2, bool = false, bool = false) const + { + StringData s1(b1.data(), b1.size()); + StringData s2(b2.data(), b2.size()); + return s2.like(s1); + } + bool operator()(StringData v1, StringData v2, bool = false, bool = false) const + { + return v2.like(v1); + } + bool operator()(BinaryData b1, BinaryData b2, bool = false, bool = false) const + { + StringData s1(b1.data(), b1.size()); + StringData s2(b2.data(), b2.size()); + return s2.like(s1); + } + + template + bool operator()(A, B) const + { + REALM_ASSERT(false); + return false; + } + + template + bool operator()(A, B, C, D) const + { + REALM_ASSERT(false); + return false; + } + + bool operator()(int64_t, int64_t, bool, bool) const + { + REALM_ASSERT(false); + return false; + } + + static std::string description() + { + return "LIKE"; + } + + static const int condition = -1; +}; + +// Does v2 begin with v1? +struct BeginsWith : public HackClass { + bool operator()(StringData v1, const char*, const char*, StringData v2, bool = false, bool = false) const + { + return v2.begins_with(v1); + } + bool operator()(StringData v1, StringData v2, bool = false, bool = false) const + { + return v2.begins_with(v1); + } + bool operator()(BinaryData v1, BinaryData v2, bool = false, bool = false) const + { + return v2.begins_with(v1); + } + + template + bool operator()(A, B, C, D) const + { + REALM_ASSERT(false); + return false; + } + template + bool operator()(A, B) const + { + REALM_ASSERT(false); + return false; + } + + static std::string description() + { + return "BEGINSWITH"; + } + + static const int condition = -1; +}; + +// Does v2 end with v1? +struct EndsWith : public HackClass { + bool operator()(StringData v1, const char*, const char*, StringData v2, bool = false, bool = false) const + { + return v2.ends_with(v1); + } + bool operator()(StringData v1, StringData v2, bool = false, bool = false) const + { + return v2.ends_with(v1); + } + bool operator()(BinaryData v1, BinaryData v2, bool = false, bool = false) const + { + return v2.ends_with(v1); + } + + template + bool operator()(A, B) const + { + REALM_ASSERT(false); + return false; + } + template + bool operator()(A, B, C, D) const + { + REALM_ASSERT(false); + return false; + } + + static std::string description() + { + return "ENDSWITH"; + } + + static const int condition = -1; +}; + +struct Equal { + static const int avx = 0x00; // _CMP_EQ_OQ + // bool operator()(const bool v1, const bool v2, bool v1null = false, bool v2null = false) const { return v1 == + // v2; } + bool operator()(StringData v1, const char*, const char*, StringData v2, bool = false, bool = false) const + { + return v1 == v2; + } + bool operator()(BinaryData v1, BinaryData v2, bool = false, bool = false) const + { + return v1 == v2; + } + + template + bool operator()(const T& v1, const T& v2, bool v1null = false, bool v2null = false) const + { + return (v1null && v2null) || (!v1null && !v2null && v1 == v2); + } + static const int condition = cond_Equal; + bool can_match(int64_t v, int64_t lbound, int64_t ubound) + { + return (v >= lbound && v <= ubound); + } + bool will_match(int64_t v, int64_t lbound, int64_t ubound) + { + return (v == 0 && ubound == 0 && lbound == 0); + } + + static std::string description() + { + return "=="; + } +}; + +struct NotEqual { + static const int avx = 0x0B; // _CMP_FALSE_OQ + bool operator()(StringData v1, const char*, const char*, StringData v2, bool = false, bool = false) const + { + return v1 != v2; + } + // bool operator()(BinaryData v1, BinaryData v2, bool = false, bool = false) const { return v1 != v2; } + + template + bool operator()(const T& v1, const T& v2, bool v1null = false, bool v2null = false) const + { + if (!v1null && !v2null) + return v1 != v2; + + if (v1null && v2null) + return false; + + return true; + } + + static const int condition = cond_NotEqual; + bool can_match(int64_t v, int64_t lbound, int64_t ubound) + { + return !(v == 0 && ubound == 0 && lbound == 0); + } + bool will_match(int64_t v, int64_t lbound, int64_t ubound) + { + return (v > ubound || v < lbound); + } + + template + bool operator()(A, B, C, D) const = delete; + + static std::string description() + { + return "!="; + } +}; + +// Does v2 contain v1? +struct ContainsIns : public HackClass { + bool operator()(StringData v1, const char* v1_upper, const char* v1_lower, StringData v2, bool = false, + bool = false) const + { + if (v2.is_null() && !v1.is_null()) + return false; + + if (v1.size() == 0 && !v2.is_null()) + return true; + + return search_case_fold(v2, v1_upper, v1_lower, v1.size()) != v2.size(); + } + + // Slow version, used if caller hasn't stored an upper and lower case version + bool operator()(StringData v1, StringData v2, bool = false, bool = false) const + { + if (v2.is_null() && !v1.is_null()) + return false; + + if (v1.size() == 0 && !v2.is_null()) + return true; + + std::string v1_upper = case_map(v1, true, IgnoreErrors); + std::string v1_lower = case_map(v1, false, IgnoreErrors); + return search_case_fold(v2, v1_upper.c_str(), v1_lower.c_str(), v1.size()) != v2.size(); + } + bool operator()(BinaryData b1, BinaryData b2, bool = false, bool = false) const + { + StringData s1(b1.data(), b1.size()); + StringData s2(b2.data(), b2.size()); + return this->operator()(s1, s2, false, false); + } + + // Case insensitive Boyer-Moore version + bool operator()(StringData v1, const char* v1_upper, const char* v1_lower, const std::array &charmap, StringData v2) const + { + if (v2.is_null() && !v1.is_null()) + return false; + + if (v1.size() == 0 && !v2.is_null()) + return true; + + return contains_ins(v2, v1_upper, v1_lower, v1.size(), charmap); + } + + + template + bool operator()(A, B) const + { + REALM_ASSERT(false); + return false; + } + template + bool operator()(A, B, C, D) const + { + REALM_ASSERT(false); + return false; + } + bool operator()(int64_t, int64_t, bool, bool) const + { + REALM_ASSERT(false); + return false; + } + + static std::string description() + { + return "CONTAINS[c]"; + } + + static const int condition = -1; +}; + +// Does v2 contain something like v1 (wildcard matching)? +struct LikeIns : public HackClass { + bool operator()(StringData v1, const char* v1_upper, const char* v1_lower, StringData v2, bool = false, + bool = false) const + { + if (v2.is_null() || v1.is_null()) { + return (v2.is_null() && v1.is_null()); + } + + return string_like_ins(v2, v1_lower, v1_upper); + } + bool operator()(BinaryData b1, const char* b1_upper, const char* b1_lower, BinaryData b2, bool = false, + bool = false) const + { + if (b2.is_null() || b1.is_null()) { + return (b2.is_null() && b1.is_null()); + } + StringData s2(b2.data(), b2.size()); + + return string_like_ins(s2, b1_lower, b1_upper); + } + + // Slow version, used if caller hasn't stored an upper and lower case version + bool operator()(StringData v1, StringData v2, bool = false, bool = false) const + { + if (v2.is_null() || v1.is_null()) { + return (v2.is_null() && v1.is_null()); + } + + std::string v1_upper = case_map(v1, true, IgnoreErrors); + std::string v1_lower = case_map(v1, false, IgnoreErrors); + return string_like_ins(v2, v1_lower, v1_upper); + } + bool operator()(BinaryData b1, BinaryData b2, bool = false, bool = false) const + { + if (b2.is_null() || b1.is_null()) { + return (b2.is_null() && b1.is_null()); + } + StringData s1(b1.data(), b1.size()); + StringData s2(b2.data(), b2.size()); + + std::string s1_upper = case_map(s1, true, IgnoreErrors); + std::string s1_lower = case_map(s1, false, IgnoreErrors); + return string_like_ins(s2, s1_lower, s1_upper); + } + + template + bool operator()(A, B) const + { + REALM_ASSERT(false); + return false; + } + template + bool operator()(A, B, C, D) const + { + REALM_ASSERT(false); + return false; + } + bool operator()(int64_t, int64_t, bool, bool) const + { + REALM_ASSERT(false); + return false; + } + + static std::string description() + { + return "LIKE[c]"; + } + + static const int condition = -1; +}; + +// Does v2 begin with v1? +struct BeginsWithIns : public HackClass { + bool operator()(StringData v1, const char* v1_upper, const char* v1_lower, StringData v2, bool = false, + bool = false) const + { + if (v2.is_null() && !v1.is_null()) + return false; + return v1.size() <= v2.size() && equal_case_fold(v2.prefix(v1.size()), v1_upper, v1_lower); + } + + // Slow version, used if caller hasn't stored an upper and lower case version + bool operator()(StringData v1, StringData v2, bool = false, bool = false) const + { + if (v2.is_null() && !v1.is_null()) + return false; + + if (v1.size() > v2.size()) + return false; + std::string v1_upper = case_map(v1, true, IgnoreErrors); + std::string v1_lower = case_map(v1, false, IgnoreErrors); + return equal_case_fold(v2.prefix(v1.size()), v1_upper.c_str(), v1_lower.c_str()); + } + bool operator()(BinaryData b1, BinaryData b2, bool = false, bool = false) const + { + StringData s1(b1.data(), b1.size()); + StringData s2(b2.data(), b2.size()); + return this->operator()(s1, s2, false, false); + } + + template + bool operator()(A, B) const + { + REALM_ASSERT(false); + return false; + } + template + bool operator()(A, B, C, D) const + { + REALM_ASSERT(false); + return false; + } + bool operator()(int64_t, int64_t, bool, bool) const + { + REALM_ASSERT(false); + return false; + } + + static std::string description() + { + return "BEGINSWITH[c]"; + } + + static const int condition = -1; +}; + +// Does v2 end with v1? +struct EndsWithIns : public HackClass { + bool operator()(StringData v1, const char* v1_upper, const char* v1_lower, StringData v2, bool = false, + bool = false) const + { + if (v2.is_null() && !v1.is_null()) + return false; + + return v1.size() <= v2.size() && equal_case_fold(v2.suffix(v1.size()), v1_upper, v1_lower); + } + + // Slow version, used if caller hasn't stored an upper and lower case version + bool operator()(StringData v1, StringData v2, bool = false, bool = false) const + { + if (v2.is_null() && !v1.is_null()) + return false; + + if (v1.size() > v2.size()) + return false; + std::string v1_upper = case_map(v1, true, IgnoreErrors); + std::string v1_lower = case_map(v1, false, IgnoreErrors); + return equal_case_fold(v2.suffix(v1.size()), v1_upper.c_str(), v1_lower.c_str()); + } + bool operator()(BinaryData b1, BinaryData b2, bool = false, bool = false) const + { + StringData s1(b1.data(), b1.size()); + StringData s2(b2.data(), b2.size()); + return this->operator()(s1, s2, false, false); + } + + template + bool operator()(A, B) const + { + REALM_ASSERT(false); + return false; + } + template + bool operator()(A, B, C, D) const + { + REALM_ASSERT(false); + return false; + } + bool operator()(int64_t, int64_t, bool, bool) const + { + REALM_ASSERT(false); + return false; + } + + static std::string description() + { + return "ENDSWITH[c]"; + } + + static const int condition = -1; +}; + +struct EqualIns : public HackClass { + bool operator()(StringData v1, const char* v1_upper, const char* v1_lower, StringData v2, bool = false, + bool = false) const + { + if (v1.is_null() != v2.is_null()) + return false; + + return v1.size() == v2.size() && equal_case_fold(v2, v1_upper, v1_lower); + } + + // Slow version, used if caller hasn't stored an upper and lower case version + bool operator()(StringData v1, StringData v2, bool = false, bool = false) const + { + if (v1.is_null() != v2.is_null()) + return false; + + if (v1.size() != v2.size()) + return false; + std::string v1_upper = case_map(v1, true, IgnoreErrors); + std::string v1_lower = case_map(v1, false, IgnoreErrors); + return equal_case_fold(v2, v1_upper.c_str(), v1_lower.c_str()); + } + bool operator()(BinaryData b1, BinaryData b2, bool = false, bool = false) const + { + StringData s1(b1.data(), b1.size()); + StringData s2(b2.data(), b2.size()); + return this->operator()(s1, s2, false, false); + } + + template + bool operator()(A, B) const + { + REALM_ASSERT(false); + return false; + } + template + bool operator()(A, B, C, D) const + { + REALM_ASSERT(false); + return false; + } + bool operator()(int64_t, int64_t, bool, bool) const + { + REALM_ASSERT(false); + return false; + } + + static std::string description() + { + return "==[c]"; + } + + static const int condition = -1; +}; + +struct NotEqualIns : public HackClass { + bool operator()(StringData v1, const char* v1_upper, const char* v1_lower, StringData v2, bool = false, + bool = false) const + { + if (v1.is_null() != v2.is_null()) + return true; + return v1.size() != v2.size() || !equal_case_fold(v2, v1_upper, v1_lower); + } + + // Slow version, used if caller hasn't stored an upper and lower case version + bool operator()(StringData v1, StringData v2, bool = false, bool = false) const + { + if (v1.is_null() != v2.is_null()) + return true; + + if (v1.size() != v2.size()) + return true; + std::string v1_upper = case_map(v1, true, IgnoreErrors); + std::string v1_lower = case_map(v1, false, IgnoreErrors); + return !equal_case_fold(v2, v1_upper.c_str(), v1_lower.c_str()); + } + bool operator()(BinaryData b1, BinaryData b2, bool = false, bool = false) const + { + StringData s1(b1.data(), b1.size()); + StringData s2(b2.data(), b2.size()); + return this->operator()(s1, s2, false, false); + } + + template + bool operator()(A, B) const + { + REALM_ASSERT(false); + return false; + } + template + bool operator()(A, B, C, D) const + { + REALM_ASSERT(false); + return false; + } + + static std::string description() + { + return "!=[c]"; + } + + static const int condition = -1; +}; + +struct Greater { + static const int avx = 0x1E; // _CMP_GT_OQ + template + bool operator()(const T& v1, const T& v2, bool v1null = false, bool v2null = false) const + { + if (v1null || v2null) + return false; + + return v1 > v2; + } + static const int condition = cond_Greater; + template + bool operator()(A, B, C, D) const + { + REALM_ASSERT(false); + return false; + } + + bool can_match(int64_t v, int64_t lbound, int64_t ubound) + { + static_cast(lbound); + return ubound > v; + } + bool will_match(int64_t v, int64_t lbound, int64_t ubound) + { + static_cast(ubound); + return lbound > v; + } + + static std::string description() + { + return ">"; + } +}; + +struct None { + template + bool operator()(const T&, const T&, bool = false, bool = false) const + { + return true; + } + static const int condition = cond_None; + template + bool operator()(A, B, C, D) const + { + REALM_ASSERT(false); + return false; + } + bool can_match(int64_t v, int64_t lbound, int64_t ubound) + { + static_cast(lbound); + static_cast(ubound); + static_cast(v); + return true; + } + bool will_match(int64_t v, int64_t lbound, int64_t ubound) + { + static_cast(lbound); + static_cast(ubound); + static_cast(v); + return true; + } + + static std::string description() + { + return "none"; + } +}; + +struct NotNull { + template + bool operator()(const T&, const T&, bool v = false, bool = false) const + { + return !v; + } + static const int condition = cond_LeftNotNull; + template + bool operator()(A, B, C, D) const + { + REALM_ASSERT(false); + return false; + } + bool can_match(int64_t v, int64_t lbound, int64_t ubound) + { + static_cast(lbound); + static_cast(ubound); + static_cast(v); + return true; + } + bool will_match(int64_t v, int64_t lbound, int64_t ubound) + { + static_cast(lbound); + static_cast(ubound); + static_cast(v); + return true; + } + static std::string description() + { + return "!= NULL"; + } +}; + + +struct Less { + static const int avx = 0x11; // _CMP_LT_OQ + template + bool operator()(const T& v1, const T& v2, bool v1null = false, bool v2null = false) const + { + if (v1null || v2null) + return false; + + return v1 < v2; + } + template + bool operator()(A, B, C, D) const + { + REALM_ASSERT(false); + return false; + } + static const int condition = cond_Less; + bool can_match(int64_t v, int64_t lbound, int64_t ubound) + { + static_cast(ubound); + return lbound < v; + } + bool will_match(int64_t v, int64_t lbound, int64_t ubound) + { + static_cast(lbound); + return ubound < v; + } + static std::string description() + { + return "<"; + } +}; + +struct LessEqual : public HackClass { + static const int avx = 0x12; // _CMP_LE_OQ + template + bool operator()(const T& v1, const T& v2, bool v1null = false, bool v2null = false) const + { + if (v1null && v2null) + return true; + + return (!v1null && !v2null && v1 <= v2); + } + bool operator()(const util::Optional& v1, const util::Optional& v2, bool v1null, bool v2null) const + { + if (v1null && v2null) + return false; + + return (!v1null && !v2null && v1.value() <= v2.value()); + } + template + bool operator()(A, B, C, D) const + { + REALM_ASSERT(false); + return false; + } + static std::string description() + { + return "<="; + } + static const int condition = -1; +}; + +struct GreaterEqual : public HackClass { + static const int avx = 0x1D; // _CMP_GE_OQ + template + bool operator()(const T& v1, const T& v2, bool v1null = false, bool v2null = false) const + { + if (v1null && v2null) + return true; + + return (!v1null && !v2null && v1 >= v2); + } + bool operator()(const util::Optional& v1, const util::Optional& v2, bool v1null, bool v2null) const + { + if (v1null && v2null) + return false; + + return (!v1null && !v2null && v1.value() >= v2.value()); + } + template + bool operator()(A, B, C, D) const + { + REALM_ASSERT(false); + return false; + } + static std::string description() + { + return ">="; + } + static const int condition = -1; +}; + + +// CompareLess is a temporary hack to have a generalized way to compare any realm types. Todo, enable correct < +// operator of StringData (currently gives circular header dependency with utf8.hpp) +template +struct CompareLess { + static bool compare(T v1, T v2, bool = false, bool = false) + { + return v1 < v2; + } +}; +template <> +struct CompareLess { + static bool compare(StringData v1, StringData v2, bool = false, bool = false) + { + bool ret = utf8_compare(v1.data(), v2.data()); + return ret; + } +}; + +} // namespace realm + +#endif // REALM_QUERY_CONDITIONS_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/query_engine.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/query_engine.hpp new file mode 100644 index 0000000..c8aeb84 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/query_engine.hpp @@ -0,0 +1,2562 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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. + * + **************************************************************************/ + +/* +A query consists of node objects, one for each query condition. Each node contains pointers to all other nodes: + +node1 node2 node3 +------ ----- ----- +node2* node1* node1* +node3* node3* node2* + +The construction of all this takes part in query.cpp. Each node has two important functions: + + aggregate(start, end) + aggregate_local(start, end) + +The aggregate() function executes the aggregate of a query. You can call the method on any of the nodes +(except children nodes of OrNode and SubtableNode) - it has the same behaviour. The function contains +scheduling that calls aggregate_local(start, end) on different nodes with different start/end ranges, +depending on what it finds is most optimal. + +The aggregate_local() function contains a tight loop that tests the condition of its own node, and upon match +it tests all other conditions at that index to report a full match or not. It will remain in the tight loop +after a full match. + +So a call stack with 2 and 9 being local matches of a node could look like this: + +aggregate(0, 10) + node1->aggregate_local(0, 3) + node2->find_first_local(2, 3) + node3->find_first_local(2, 3) + node3->aggregate_local(3, 10) + node1->find_first_local(4, 5) + node2->find_first_local(4, 5) + node1->find_first_local(7, 8) + node2->find_first_local(7, 8) + +find_first_local(n, n + 1) is a function that can be used to test a single row of another condition. Note that +this is very simplified. There are other statistical arguments to the methods, and also, find_first_local() can be +called from a callback function called by an integer Array. + + +Template arguments in methods: +---------------------------------------------------------------------------------------------------- + +TConditionFunction: Each node has a condition from query_conditions.c such as Equal, GreaterEqual, etc + +TConditionValue: Type of values in condition column. That is, int64_t, float, int, bool, etc + +TAction: What to do with each search result, from the enums act_ReturnFirst, act_Count, act_Sum, etc + +TResult: Type of result of actions - float, double, int64_t, etc. Special notes: For act_Count it's + int64_t, for RLM_FIND_ALL it's int64_t which points at destination array. + +TSourceColumn: Type of source column used in actions, or *ignored* if no source column is used (like for + act_Count, act_ReturnFirst) + + +There are two important classes used in queries: +---------------------------------------------------------------------------------------------------- +SequentialGetter Column iterator used to get successive values with leaf caching. Used both for condition columns + and aggregate source column + +AggregateState State of the aggregate - contains a state variable that stores intermediate sum, max, min, + etc, etc. + +*/ + +#ifndef REALM_QUERY_ENGINE_HPP +#define REALM_QUERY_ENGINE_HPP + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#if REALM_X86_OR_X64_TRUE && defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 160040219 +#include +#endif + +namespace realm { + +// Number of matches to find in best condition loop before breaking out to probe other conditions. Too low value gives +// too many constant time overheads everywhere in the query engine. Too high value makes it adapt less rapidly to +// changes in match frequencies. +const size_t findlocals = 64; + +// Average match distance in linear searches where further increase in distance no longer increases query speed +// (because time spent on handling each match becomes insignificant compared to time spent on the search). +const size_t bestdist = 512; + +// Minimum number of matches required in a certain condition before it can be used to compute statistics. Too high +// value can spent too much time in a bad node (with high match frequency). Too low value gives inaccurate statistics. +const size_t probe_matches = 4; + +const size_t bitwidth_time_unit = 64; + +typedef bool (*CallbackDummy)(int64_t); +using Evaluator = util::FunctionRef; + +class ParentNode { + typedef ParentNode ThisType; + +public: + ParentNode() = default; + virtual ~ParentNode() = default; + + virtual bool has_search_index() const + { + return false; + } + virtual void index_based_aggregate(size_t, Evaluator) {} + + void gather_children(std::vector& v) + { + m_children.clear(); + size_t i = v.size(); + v.push_back(this); + + if (m_child) + m_child->gather_children(v); + + m_children = v; + m_children.erase(m_children.begin() + i); + m_children.insert(m_children.begin(), this); + } + + double cost() const + { + return 8 * bitwidth_time_unit / m_dD + + m_dT; // dt = 1/64 to 1. Match dist is 8 times more important than bitwidth + } + + size_t find_first(size_t start, size_t end); + + bool match(ConstObj& obj); + + virtual void init(bool will_query_ranges) + { + if (m_child) + m_child->init(will_query_ranges); + + m_column_action_specializer = nullptr; + } + + void get_link_dependencies(std::vector& tables) const + { + collect_dependencies(tables); + if (m_child) + m_child->get_link_dependencies(tables); + } + + void set_table(ConstTableRef table) + { + if (table == m_table) + return; + + m_table = table; + if (m_condition_column_key != ColKey()) { + m_condition_column_name = m_table->get_column_name(m_condition_column_key); + } + if (m_child) + m_child->set_table(table); + table_changed(); + } + + void set_cluster(const Cluster* cluster) + { + m_cluster = cluster; + if (m_child) + m_child->set_cluster(cluster); + cluster_changed(); + } + + virtual void collect_dependencies(std::vector&) const + { + } + + virtual size_t find_first_local(size_t start, size_t end) = 0; + + virtual void aggregate_local_prepare(Action TAction, DataType col_id, bool nullable); + template + void aggregate_local_prepare(DataType col_id, bool nullable); + + template + bool column_action_specialization(QueryStateBase* st, ArrayPayload* source_column, size_t r) + { + // TResult: type of query result + // TSourceValue: type of aggregate source + using TSourceValue = typename LeafType::value_type; + using TResult = typename AggregateResultType::result_type; + + // Sum of float column must accumulate in double + static_assert( + !(TAction == act_Sum && (std::is_same_v && !std::is_same_v)), ""); + + TSourceValue av{}; + // uses_val test because compiler cannot see that IntegerColumn::get has no side effect and result is + // discarded + if (static_cast*>(st)->template uses_val() && source_column != nullptr) { + REALM_ASSERT_DEBUG(dynamic_cast(source_column) != nullptr); + av = static_cast(source_column)->get(r); + } + REALM_ASSERT_DEBUG(dynamic_cast*>(st) != nullptr); + bool cont = static_cast*>(st)->template match(r, 0, av); + return cont; + } + + virtual size_t aggregate_local(QueryStateBase* st, size_t start, size_t end, size_t local_limit, + ArrayPayload* source_column); + + + virtual std::string validate() + { + if (error_code != "") + return error_code; + if (m_child == nullptr) + return ""; + else + return m_child->validate(); + } + + ParentNode(const ParentNode& from); + + void add_child(std::unique_ptr child) + { + if (m_child) + m_child->add_child(std::move(child)); + else + m_child = std::move(child); + } + + virtual std::unique_ptr clone() const = 0; + + ColKey get_column_key(StringData column_name) const + { + ColKey column_key; + if (column_name.size() > 0) { + column_key = m_table.unchecked_ptr()->get_column_key(column_name); + if (column_key == ColKey()) { + throw LogicError(LogicError::column_does_not_exist); + } + } + return column_key; + } + + virtual std::string describe(util::serializer::SerialisationState&) const + { + return ""; + } + + virtual std::string describe_condition() const + { + return "matches"; + } + + virtual std::string describe_expression(util::serializer::SerialisationState& state) const + { + std::string s; + s = describe(state); + if (m_child) { + s = s + " and " + m_child->describe_expression(state); + } + return s; + } + + bool consume_condition(ParentNode& other, bool ignore_indexes) + { + // We can only combine conditions if they're the same operator on the + // same column and there's no additional conditions ANDed on + if (m_condition_column_key != other.m_condition_column_key) + return false; + if (m_child || other.m_child) + return false; + if (typeid(*this) != typeid(other)) + return false; + + // If a search index is present, don't try to combine conditions since index search is most likely faster. + // Assuming N elements to search and M conditions to check: + // 1) search index present: O(log(N)*M) + // 2) no search index, combine conditions: O(N) + // 3) no search index, conditions not combined: O(N*M) + // In practice N is much larger than M, so if we have a search index, choose 1, otherwise if possible + // choose 2. The exception is if we're inside a Not group or if the query is restricted to a view, as in those + // cases end will always be start+1 and we'll have O(N*M) runtime even with a search index, so we want to + // combine even with an index. + if (has_search_index() && !ignore_indexes) + return false; + return do_consume_condition(other); + } + + std::unique_ptr m_child; + std::vector m_children; + std::string m_condition_column_name; + mutable ColKey m_condition_column_key = ColKey(); // Column of search criteria + + double m_dD; // Average row distance between each local match at current position + double m_dT = 0.0; // Time overhead of testing index i + 1 if we have just tested index i. > 1 for linear scans, 0 + // for index/tableview + + size_t m_probes = 0; + size_t m_matches = 0; + +protected: + typedef bool (ParentNode::*Column_action_specialized)(QueryStateBase*, ArrayPayload*, size_t); + Column_action_specialized m_column_action_specializer = nullptr; + ConstTableRef m_table = ConstTableRef(); + const Cluster* m_cluster = nullptr; + QueryStateBase* m_state = nullptr; + std::string error_code; + + ColumnType get_real_column_type(ColKey key) + { + return m_table.unchecked_ptr()->get_real_column_type(key); + } + +private: + virtual void table_changed() + { + } + virtual void cluster_changed() + { + // TODO: Should eventually be pure + } + virtual bool do_consume_condition(ParentNode&) + { + return false; + } +}; + + +namespace _impl { + +template +struct CostHeuristic; + +template <> +struct CostHeuristic { + static constexpr double dD() + { + return 100.0; + } + static constexpr double dT() + { + return 1.0 / 4.0; + } +}; + +template <> +struct CostHeuristic { + static constexpr double dD() + { + return 100.0; + } + static constexpr double dT() + { + return 1.0 / 4.0; + } +}; + +// FIXME: Add AdaptiveStringColumn, BasicColumn, etc. +} + +class ColumnNodeBase : public ParentNode { +protected: + ColumnNodeBase(ColKey column_key) + { + m_condition_column_key = column_key; + } + + ColumnNodeBase(const ColumnNodeBase& from) + : ParentNode(from) + , m_last_local_match(from.m_last_local_match) + , m_local_matches(from.m_local_matches) + , m_local_limit(from.m_local_limit) + , m_fastmode_disabled(from.m_fastmode_disabled) + , m_action(from.m_action) + , m_state(from.m_state) + , m_source_column(from.m_source_column) + { + } + + template + bool match_callback(int64_t v) + { + using TSourceValue = typename LeafType::value_type; + using ResultType = typename AggregateResultType::result_type; + + size_t i = to_size_t(v); + m_last_local_match = i; + m_local_matches++; + + auto state = static_cast*>(m_state); + auto source_column = static_cast(m_source_column); + + // Test remaining sub conditions of this node. m_children[0] is the node that called match_callback(), so skip + // it + for (size_t c = 1; c < m_children.size(); c++) { + m_children[c]->m_probes++; + size_t m = m_children[c]->find_first_local(i, i + 1); + if (m != i) + return true; + } + + bool b; + if (state->template uses_val()) { // Compiler cannot see that IntegerColumn::Get has no side effect + // and result is discarded + TSourceValue av = source_column->get(i); + b = state->template match(i, 0, av); + } + else { + b = state->template match(i, 0, TSourceValue{}); + } + + return b; + } + + // Aggregate bookkeeping + size_t m_last_local_match = npos; + size_t m_local_matches = 0; + size_t m_local_limit = 0; + bool m_fastmode_disabled = false; + Action m_action; + QueryStateBase* m_state = nullptr; + // Column of values used in aggregate (act_FindAll, actReturnFirst, act_Sum, etc) + ArrayPayload* m_source_column = nullptr; +}; + +template +class IntegerNodeBase : public ColumnNodeBase { + using ThisType = IntegerNodeBase; + +public: + using TConditionValue = typename LeafType::value_type; + // static const bool nullable = ColType::nullable; + + template + bool find_callback_specialization(size_t start_in_leaf, size_t end_in_leaf) + { + using AggregateLeafType = typename GetLeafType::type; + auto cb = std::bind(std::mem_fn(&ThisType::template match_callback), this, + std::placeholders::_1); + return this->m_leaf_ptr->template find(m_value, start_in_leaf, + end_in_leaf, 0, nullptr, cb); + } + +protected: + size_t aggregate_local_impl(QueryStateBase* st, size_t start, size_t end, size_t local_limit, + ArrayPayload* source_column, int c) + { + m_table.check(); + REALM_ASSERT(m_cluster); + REALM_ASSERT(m_children.size() > 0); + m_local_matches = 0; + m_local_limit = local_limit; + m_last_local_match = start - 1; + m_state = st; + + // If there are no other nodes than us (m_children.size() == 1) AND the column used for our condition is + // the same as the column used for the aggregate action, then the entire query can run within scope of that + // column only, with no references to other columns: + bool fastmode = should_run_in_fastmode(source_column); + if (fastmode) { + bool cont; + cont = m_leaf_ptr->find(c, m_action, m_value, start, end, 0, static_cast*>(st)); + if (!cont) + return not_found; + } + // Else, for each match in this node, call our IntegerNodeBase::match_callback to test remaining nodes + // and/or extract + // aggregate payload from aggregate column: + else { + m_source_column = source_column; + bool cont = (this->*m_find_callback_specialized)(start, end); + if (!cont) + return not_found; + } + + if (m_local_matches == m_local_limit) { + m_dD = (m_last_local_match + 1 - start) / (m_local_matches + 1.0); + return m_last_local_match + 1; + } + else { + m_dD = (end - start) / (m_local_matches + 1.0); + return end; + } + } + + IntegerNodeBase(TConditionValue value, ColKey column_key) + : ColumnNodeBase(column_key) + , m_value(std::move(value)) + { + } + + IntegerNodeBase(const ThisType& from) + : ColumnNodeBase(from) + , m_value(from.m_value) + , m_find_callback_specialized(from.m_find_callback_specialized) + { + } + + void cluster_changed() override + { + // Assigning nullptr will cause the Leaf destructor to be called. Must + // be done before assigning a new one. Otherwise the destructor will be + // called after the constructor is called and that is unfortunate if + // the object has the same address. (As in this case) + m_array_ptr = nullptr; + // Create new Leaf + m_array_ptr = LeafPtr(new (&m_leaf_cache_storage) LeafType(m_table.unchecked_ptr()->get_alloc())); + m_cluster->init_leaf(this->m_condition_column_key, m_array_ptr.get()); + m_leaf_ptr = m_array_ptr.get(); + } + + void init(bool will_query_ranges) override + { + ColumnNodeBase::init(will_query_ranges); + + m_dT = _impl::CostHeuristic::dT(); + m_dD = _impl::CostHeuristic::dD(); + } + + bool should_run_in_fastmode(ArrayPayload* source_leaf) const + { + if (m_children.size() > 1 || m_fastmode_disabled) + return false; + if (source_leaf == nullptr) + return true; + // Compare leafs to see if they are the same + auto leaf = dynamic_cast(source_leaf); + return leaf ? leaf->get_ref() == m_leaf_ptr->get_ref() : false; + } + + // Search value: + TConditionValue m_value; + + // Leaf cache + using LeafCacheStorage = typename std::aligned_storage::type; + using LeafPtr = std::unique_ptr; + LeafCacheStorage m_leaf_cache_storage; + LeafPtr m_array_ptr; + const LeafType* m_leaf_ptr = nullptr; + + // Aggregate optimization + using TFind_callback_specialized = bool (ThisType::*)(size_t, size_t); + TFind_callback_specialized m_find_callback_specialized = nullptr; + + template + static TFind_callback_specialized get_specialized_callback(Action action, DataType col_id, bool is_nullable) + { + switch (action) { + case act_Count: + return get_specialized_callback_2_int(col_id, is_nullable); + case act_Sum: + return get_specialized_callback_2(col_id, is_nullable); + case act_Max: + return get_specialized_callback_2(col_id, is_nullable); + case act_Min: + return get_specialized_callback_2(col_id, is_nullable); + case act_FindAll: + return get_specialized_callback_2_int(col_id, is_nullable); + case act_CallbackIdx: + return get_specialized_callback_2_int(col_id, is_nullable); + default: + break; + } + REALM_ASSERT(false); // Invalid aggregate function + return nullptr; + } + + template + static TFind_callback_specialized get_specialized_callback_2(DataType col_id, bool is_nullable) + { + switch (col_id) { + case type_Int: + return get_specialized_callback_3(is_nullable); + case type_Float: + return get_specialized_callback_3(is_nullable); + case type_Double: + return get_specialized_callback_3(is_nullable); + case type_Timestamp: + return get_specialized_callback_3(is_nullable); + case type_Decimal: + return get_specialized_callback_3(is_nullable); + default: + break; + } + REALM_ASSERT(false); // Invalid aggregate source column + return nullptr; + } + + template + static TFind_callback_specialized get_specialized_callback_2_int(DataType col_id, bool is_nullable) + { + if (col_id == type_Int) { + return get_specialized_callback_3(is_nullable); + } + REALM_ASSERT(false); // Invalid aggregate source column + return nullptr; + } + + template + static TFind_callback_specialized get_specialized_callback_3(bool is_nullable) + { + if (is_nullable) { + return &IntegerNodeBase::template find_callback_specialization; + } + else { + return &IntegerNodeBase::template find_callback_specialization; + } + } +}; + + +template +class IntegerNode : public IntegerNodeBase { + using BaseType = IntegerNodeBase; + using ThisType = IntegerNode; + +public: + static const bool special_null_node = false; + using TConditionValue = typename BaseType::TConditionValue; + + IntegerNode(TConditionValue value, ColKey column_key) + : BaseType(value, column_key) + { + } + IntegerNode(const IntegerNode& from) + : BaseType(from) + { + } + + void aggregate_local_prepare(Action action, DataType col_id, bool is_nullable) override + { + this->m_fastmode_disabled = (col_id == type_Float || col_id == type_Double); + this->m_action = action; + this->m_find_callback_specialized = + IntegerNodeBase::template get_specialized_callback(action, col_id, + is_nullable); + } + + size_t aggregate_local(QueryStateBase* st, size_t start, size_t end, size_t local_limit, + ArrayPayload* source_column) override + { + constexpr int cond = TConditionFunction::condition; + return this->aggregate_local_impl(st, start, end, local_limit, source_column, cond); + } + + size_t find_first_local(size_t start, size_t end) override + { + return this->m_leaf_ptr->template find_first(this->m_value, start, end); + } + + std::string describe(util::serializer::SerialisationState& state) const override + { + return state.describe_column(ParentNode::m_table, ColumnNodeBase::m_condition_column_key) + " " + + describe_condition() + " " + util::serializer::print_value(this->m_value); + } + + std::string describe_condition() const override + { + return TConditionFunction::description(); + } + + std::unique_ptr clone() const override + { + return std::unique_ptr(new ThisType(*this)); + } +}; + +template +static size_t find_first_haystack(LeafType& leaf, NeedleContainer& needles, size_t start, size_t end) +{ + // for a small number of conditions, it is faster to do a linear search than to compute the hash + // the exact thresholds were found experimentally + if (needles.size() < linear_search_threshold) { + for (size_t i = start; i < end; ++i) { + auto element = leaf.get(i); + if (std::find(needles.begin(), needles.end(), element) != needles.end()) + return i; + } + } + else { + for (size_t i = start; i < end; ++i) { + auto element = leaf.get(i); + if (needles.count(element)) + return i; + } + } + return realm::npos; +} + +template +class IntegerNode : public IntegerNodeBase { +public: + using BaseType = IntegerNodeBase; + using TConditionValue = typename BaseType::TConditionValue; + using ThisType = IntegerNode; + + IntegerNode(TConditionValue value, ColKey column_key) + : BaseType(value, column_key) + { + } + ~IntegerNode() + { + } + + void init(bool will_query_ranges) override + { + BaseType::init(will_query_ranges); + m_nb_needles = m_needles.size(); + + if (has_search_index()) { + // _search_index_init(); + m_result.clear(); + auto index = ParentNode::m_table->get_search_index(ParentNode::m_condition_column_key); + index->find_all(m_result, BaseType::m_value); + m_result_get = 0; + m_last_start_key = ObjKey(); + IntegerNodeBase::m_dT = 0; + } + } + + bool do_consume_condition(ParentNode& node) override + { + auto& other = static_cast(node); + REALM_ASSERT(this->m_condition_column_key == other.m_condition_column_key); + REALM_ASSERT(other.m_needles.empty()); + if (m_needles.empty()) { + m_needles.insert(this->m_value); + } + m_needles.insert(other.m_value); + return true; + } + + bool has_search_index() const override + { + return this->m_table->has_search_index(IntegerNodeBase::m_condition_column_key); + } + + void index_based_aggregate(size_t limit, Evaluator evaluator) override + { + for (size_t t = 0; t < m_result.size() && limit > 0; ++t) { + auto obj = this->m_table->get_object(m_result[t]); + if (evaluator(obj)) { + --limit; + } + } + } + + void aggregate_local_prepare(Action action, DataType col_id, bool is_nullable) override + { + this->m_fastmode_disabled = (col_id == type_Float || col_id == type_Double); + this->m_action = action; + this->m_find_callback_specialized = + IntegerNodeBase::template get_specialized_callback(action, col_id, is_nullable); + } + + size_t aggregate_local(QueryStateBase* st, size_t start, size_t end, size_t local_limit, + ArrayPayload* source_column) override + { + constexpr int cond = Equal::condition; + return this->aggregate_local_impl(st, start, end, local_limit, source_column, cond); + } + + size_t find_first_local(size_t start, size_t end) override + { + REALM_ASSERT(this->m_table); + size_t s = realm::npos; + + if (start < end) { + if (m_nb_needles) { + s = find_first_haystack<22>(*this->m_leaf_ptr, m_needles, start, end); + } + else if (has_search_index()) { + ObjKey first_key = BaseType::m_cluster->get_real_key(start); + if (first_key < m_last_start_key) { + // We are not advancing through the clusters. We basically don't know where we are, + // so just start over from the beginning. + auto it = std::lower_bound(m_result.begin(), m_result.end(), first_key); + m_result_get = (it == m_result.end()) ? realm::npos : (it - m_result.begin()); + } + m_last_start_key = first_key; + + if (m_result_get < m_result.size()) { + auto actual_key = m_result[m_result_get]; + // skip through keys which are in "earlier" leafs than the one selected by start..end: + while (first_key > actual_key) { + m_result_get++; + if (m_result_get == m_result.size()) + return not_found; + actual_key = m_result[m_result_get]; + } + + // if actual key is bigger than last key, it is not in this leaf + ObjKey last_key = BaseType::m_cluster->get_real_key(end - 1); + if (actual_key > last_key) + return not_found; + + // key is known to be in this leaf, so find key whithin leaf keys + return BaseType::m_cluster->lower_bound_key( + ObjKey(actual_key.value - BaseType::m_cluster->get_offset())); + } + return not_found; + } + else if (end - start == 1) { + if (this->m_leaf_ptr->get(start) == this->m_value) { + s = start; + } + } + else { + s = this->m_leaf_ptr->template find_first(this->m_value, start, end); + } + } + + return s; + } + + std::string describe(util::serializer::SerialisationState& state) const override + { + REALM_ASSERT(this->m_condition_column_key); + std::string col_descr = state.describe_column(this->m_table, this->m_condition_column_key); + + if (m_needles.empty()) { + return col_descr + " " + Equal::description() + " " + + util::serializer::print_value(IntegerNodeBase::m_value); + } + + // FIXME: once the parser supports it, print something like "column IN {n1, n2, n3}" + std::string desc = "("; + bool is_first = true; + for (auto it : m_needles) { + if (!is_first) + desc += " or "; + desc += + col_descr + " " + Equal::description() + " " + util::serializer::print_value(it); // "it" may be null + is_first = false; + } + desc += ")"; + return desc; + } + + std::unique_ptr clone() const override + { + return std::unique_ptr(new ThisType(*this)); + } + +private: + std::unordered_set m_needles; + std::vector m_result; + size_t m_nb_needles = 0; + size_t m_result_get = 0; + ObjKey m_last_start_key; + + IntegerNode(const IntegerNode& from) + : BaseType(from) + , m_needles(from.m_needles) + { + } +}; + + +// This node is currently used for floats and doubles only +template +class FloatDoubleNode : public ParentNode { +public: + using TConditionValue = typename LeafType::value_type; + static const bool special_null_node = false; + + FloatDoubleNode(TConditionValue v, ColKey column_key) + : m_value(v) + { + m_condition_column_key = column_key; + m_dT = 1.0; + } + FloatDoubleNode(null, ColKey column_key) + : m_value(null::get_null_float()) + { + m_condition_column_key = column_key; + m_dT = 1.0; + } + + void cluster_changed() override + { + // Assigning nullptr will cause the Leaf destructor to be called. Must + // be done before assigning a new one. Otherwise the destructor will be + // called after the constructor is called and that is unfortunate if + // the object has the same address. (As in this case) + m_array_ptr = nullptr; + // Create new Leaf + m_array_ptr = LeafPtr(new (&m_leaf_cache_storage) LeafType(m_table.unchecked_ptr()->get_alloc())); + m_cluster->init_leaf(this->m_condition_column_key, m_array_ptr.get()); + m_leaf_ptr = m_array_ptr.get(); + } + + void init(bool will_query_ranges) override + { + ParentNode::init(will_query_ranges); + m_dD = 100.0; + } + + size_t find_first_local(size_t start, size_t end) override + { + TConditionFunction cond; + + auto find = [&](bool nullability) { + bool m_value_nan = nullability ? null::is_null_float(m_value) : false; + for (size_t s = start; s < end; ++s) { + TConditionValue v = m_leaf_ptr->get(s); + REALM_ASSERT(!(null::is_null_float(v) && !nullability)); + if (cond(v, m_value, nullability ? null::is_null_float(v) : false, m_value_nan)) + return s; + } + return not_found; + }; + + // This will inline the second case but no the first. Todo, use templated lambda when switching to c++14 + if (m_table->is_nullable(m_condition_column_key)) + return find(true); + else + return find(false); + } + + std::string describe(util::serializer::SerialisationState& state) const override + { + REALM_ASSERT(m_condition_column_key); + return state.describe_column(ParentNode::m_table, m_condition_column_key) + " " + describe_condition() + " " + + util::serializer::print_value(FloatDoubleNode::m_value); + } + std::string describe_condition() const override + { + return TConditionFunction::description(); + } + + std::unique_ptr clone() const override + { + return std::unique_ptr(new FloatDoubleNode(*this)); + } + + FloatDoubleNode(const FloatDoubleNode& from) + : ParentNode(from) + , m_value(from.m_value) + { + } + +protected: + TConditionValue m_value; + // Leaf cache + using LeafCacheStorage = typename std::aligned_storage::type; + using LeafPtr = std::unique_ptr; + LeafCacheStorage m_leaf_cache_storage; + LeafPtr m_array_ptr; + const LeafType* m_leaf_ptr = nullptr; +}; + +template +class SizeNode : public ParentNode { +public: + SizeNode(int64_t v, ColKey column) + : m_value(v) + { + m_condition_column_key = column; + } + + void cluster_changed() override + { + // Assigning nullptr will cause the Leaf destructor to be called. Must + // be done before assigning a new one. Otherwise the destructor will be + // called after the constructor is called and that is unfortunate if + // the object has the same address. (As in this case) + m_array_ptr = nullptr; + m_array_ptr = LeafPtr(new (&m_leaf_cache_storage) LeafType(m_table.unchecked_ptr()->get_alloc())); + m_cluster->init_leaf(this->m_condition_column_key, m_array_ptr.get()); + m_leaf_ptr = m_array_ptr.get(); + } + + void init(bool will_query_ranges) override + { + ParentNode::init(will_query_ranges); + m_dD = 10.0; + } + + size_t find_first_local(size_t start, size_t end) override + { + for (size_t s = start; s < end; ++s) { + T v = m_leaf_ptr->get(s); + if (v) { + int64_t sz = v.size(); + if (TConditionFunction()(sz, m_value)) + return s; + } + } + return not_found; + } + + std::unique_ptr clone() const override + { + return std::unique_ptr(new SizeNode(*this)); + } + + SizeNode(const SizeNode& from) + : ParentNode(from) + , m_value(from.m_value) + { + } + +private: + // Leaf cache + using LeafType = typename ColumnTypeTraits::cluster_leaf_type; + using LeafCacheStorage = typename std::aligned_storage::type; + using LeafPtr = std::unique_ptr; + LeafCacheStorage m_leaf_cache_storage; + LeafPtr m_array_ptr; + const LeafType* m_leaf_ptr = nullptr; + + int64_t m_value; +}; + + +template +class SizeListNode : public ParentNode { +public: + SizeListNode(int64_t v, ColKey column) + : m_value(v) + { + m_condition_column_key = column; + } + + void cluster_changed() override + { + // Assigning nullptr will cause the Leaf destructor to be called. Must + // be done before assigning a new one. Otherwise the destructor will be + // called after the constructor is called and that is unfortunate if + // the object has the same address. (As in this case) + m_array_ptr = nullptr; + m_array_ptr = LeafPtr(new (&m_leaf_cache_storage) ArrayList(m_table.unchecked_ptr()->get_alloc())); + m_cluster->init_leaf(this->m_condition_column_key, m_array_ptr.get()); + m_leaf_ptr = m_array_ptr.get(); + } + + void init(bool will_query_ranges) override + { + ParentNode::init(will_query_ranges); + m_dD = 50.0; + } + + size_t find_first_local(size_t start, size_t end) override + { + for (size_t s = start; s < end; ++s) { + ref_type ref = m_leaf_ptr->get(s); + if (ref) { + ListType list(m_table.unchecked_ptr()->get_alloc()); + list.init_from_ref(ref); + int64_t sz = list.size(); + if (TConditionFunction()(sz, m_value)) + return s; + } + } + return not_found; + } + + std::unique_ptr clone() const override + { + return std::unique_ptr(new SizeListNode(*this)); + } + + SizeListNode(const SizeListNode& from) + : ParentNode(from) + , m_value(from.m_value) + { + } + +private: + // Leaf cache + using ListType = BPlusTree; + using LeafCacheStorage = typename std::aligned_storage::type; + using LeafPtr = std::unique_ptr; + LeafCacheStorage m_leaf_cache_storage; + LeafPtr m_array_ptr; + const ArrayList* m_leaf_ptr = nullptr; + + int64_t m_value; +}; + + +template +class BinaryNode : public ParentNode { +public: + using TConditionValue = BinaryData; + static const bool special_null_node = false; + + BinaryNode(BinaryData v, ColKey column) + : m_value(v) + { + m_dT = 100.0; + m_condition_column_key = column; + } + + BinaryNode(null, ColKey column) + : BinaryNode(BinaryData{}, column) + { + } + + void cluster_changed() override + { + m_array_ptr = nullptr; + m_array_ptr = LeafPtr(new (&m_leaf_cache_storage) ArrayBinary(m_table.unchecked_ptr()->get_alloc())); + m_cluster->init_leaf(this->m_condition_column_key, m_array_ptr.get()); + m_leaf_ptr = m_array_ptr.get(); + } + + void init(bool will_query_ranges) override + { + ParentNode::init(will_query_ranges); + + m_dD = 100.0; + } + + size_t find_first_local(size_t start, size_t end) override + { + TConditionFunction condition; + for (size_t s = start; s < end; ++s) { + BinaryData value = m_leaf_ptr->get(s); + if (condition(m_value.get(), value)) + return s; + } + return not_found; + } + + virtual std::string describe(util::serializer::SerialisationState& state) const override + { + REALM_ASSERT(m_condition_column_key); + return state.describe_column(ParentNode::m_table, m_condition_column_key) + " " + + TConditionFunction::description() + " " + util::serializer::print_value(BinaryNode::m_value.get()); + } + + std::unique_ptr clone() const override + { + return std::unique_ptr(new BinaryNode(*this)); + } + + BinaryNode(const BinaryNode& from) + : ParentNode(from) + , m_value(from.m_value) + { + } + +private: + OwnedBinaryData m_value; + using LeafCacheStorage = typename std::aligned_storage::type; + using LeafPtr = std::unique_ptr; + LeafCacheStorage m_leaf_cache_storage; + LeafPtr m_array_ptr; + const ArrayBinary* m_leaf_ptr = nullptr; +}; + +template +class BoolNode : public ParentNode { +public: + using TConditionValue = bool; + + BoolNode(util::Optional v, ColKey column) + : m_value(v) + { + m_condition_column_key = column; + } + + BoolNode(const BoolNode& from) + : ParentNode(from) + , m_value(from.m_value) + { + } + + void cluster_changed() override + { + m_array_ptr = nullptr; + m_array_ptr = LeafPtr(new (&m_leaf_cache_storage) ArrayBoolNull(m_table.unchecked_ptr()->get_alloc())); + m_cluster->init_leaf(this->m_condition_column_key, m_array_ptr.get()); + m_leaf_ptr = m_array_ptr.get(); + } + + void init(bool will_query_ranges) override + { + ParentNode::init(will_query_ranges); + + m_dD = 100.0; + } + + size_t find_first_local(size_t start, size_t end) override + { + TConditionFunction condition; + bool m_value_is_null = !m_value; + for (size_t s = start; s < end; ++s) { + util::Optional value = m_leaf_ptr->get(s); + if (condition(value, m_value, !value, m_value_is_null)) + return s; + } + return not_found; + } + + virtual std::string describe(util::serializer::SerialisationState& state) const override + { + return state.describe_column(ParentNode::m_table, m_condition_column_key) + " " + + TConditionFunction::description() + " " + util::serializer::print_value(m_value); + } + + std::unique_ptr clone() const override + { + return std::unique_ptr(new BoolNode(*this)); + } + +private: + util::Optional m_value; + using LeafCacheStorage = typename std::aligned_storage::type; + using LeafPtr = std::unique_ptr; + LeafCacheStorage m_leaf_cache_storage; + LeafPtr m_array_ptr; + const ArrayBoolNull* m_leaf_ptr = nullptr; +}; + +class TimestampNodeBase : public ParentNode { +public: + using TConditionValue = Timestamp; + static const bool special_null_node = false; + + TimestampNodeBase(Timestamp v, ColKey column) + : m_value(v) + { + m_condition_column_key = column; + } + + TimestampNodeBase(null, ColKey column) + : TimestampNodeBase(Timestamp{}, column) + { + } + + void cluster_changed() override + { + m_array_ptr = nullptr; + m_array_ptr = LeafPtr(new (&m_leaf_cache_storage) ArrayTimestamp(m_table.unchecked_ptr()->get_alloc())); + m_cluster->init_leaf(this->m_condition_column_key, m_array_ptr.get()); + m_leaf_ptr = m_array_ptr.get(); + } + + void init(bool will_query_ranges) override + { + ParentNode::init(will_query_ranges); + + m_dD = 100.0; + } + +protected: + TimestampNodeBase(const TimestampNodeBase& from) + : ParentNode(from) + , m_value(from.m_value) + { + } + + Timestamp m_value; + using LeafCacheStorage = typename std::aligned_storage::type; + using LeafPtr = std::unique_ptr; + LeafCacheStorage m_leaf_cache_storage; + LeafPtr m_array_ptr; + const ArrayTimestamp* m_leaf_ptr = nullptr; +}; + +template +class TimestampNode : public TimestampNodeBase { +public: + using TimestampNodeBase::TimestampNodeBase; + + size_t find_first_local(size_t start, size_t end) override + { + return m_leaf_ptr->find_first(m_value, start, end); + } + + std::string describe(util::serializer::SerialisationState& state) const override + { + REALM_ASSERT(m_condition_column_key); + return state.describe_column(ParentNode::m_table, m_condition_column_key) + " " + + TConditionFunction::description() + " " + util::serializer::print_value(TimestampNode::m_value); + } + + std::unique_ptr clone() const override + { + return std::unique_ptr(new TimestampNode(*this)); + } + +protected: + TimestampNode(const TimestampNode& from, Transaction* tr) + : TimestampNodeBase(from, tr) + { + } +}; + +class DecimalNodeBase : public ParentNode { +public: + using TConditionValue = Decimal128; + static const bool special_null_node = false; + + DecimalNodeBase(Decimal128 v, ColKey column) + : m_value(v) + { + m_condition_column_key = column; + } + + DecimalNodeBase(null, ColKey column) + : DecimalNodeBase(Decimal128{null()}, column) + { + } + + void cluster_changed() override + { + m_array_ptr = nullptr; + m_array_ptr = LeafPtr(new (&m_leaf_cache_storage) ArrayDecimal128(m_table.unchecked_ptr()->get_alloc())); + m_cluster->init_leaf(this->m_condition_column_key, m_array_ptr.get()); + m_leaf_ptr = m_array_ptr.get(); + } + + void init(bool will_query_ranges) override + { + ParentNode::init(will_query_ranges); + + m_dD = 100.0; + } + +protected: + DecimalNodeBase(const DecimalNodeBase& from) + : ParentNode(from) + , m_value(from.m_value) + { + } + + Decimal128 m_value; + using LeafCacheStorage = typename std::aligned_storage::type; + using LeafPtr = std::unique_ptr; + LeafCacheStorage m_leaf_cache_storage; + LeafPtr m_array_ptr; + const ArrayDecimal128* m_leaf_ptr = nullptr; +}; + +template +class DecimalNode : public DecimalNodeBase { +public: + using DecimalNodeBase::DecimalNodeBase; + + size_t find_first_local(size_t start, size_t end) override + { + TConditionFunction cond; + bool value_is_null = m_value.is_null(); + for (size_t i = start; i < end; i++) { + Decimal128 val = m_leaf_ptr->get(i); + if (cond(val, m_value, val.is_null(), value_is_null)) + return i; + } + return realm::npos; + } + + std::string describe(util::serializer::SerialisationState& state) const override + { + REALM_ASSERT(m_condition_column_key); + return state.describe_column(ParentNode::m_table, m_condition_column_key) + " " + + TConditionFunction::description() + " " + util::serializer::print_value(DecimalNode::m_value); + } + + std::unique_ptr clone() const override + { + return std::unique_ptr(new DecimalNode(*this)); + } + +protected: + DecimalNode(const DecimalNode& from, Transaction* tr) + : DecimalNodeBase(from, tr) + { + } +}; + +class ObjectIdNodeBase : public ParentNode { +public: + using TConditionValue = ObjectId; + static const bool special_null_node = false; + + ObjectIdNodeBase(ObjectId v, ColKey column) + : m_value(v) + { + m_condition_column_key = column; + } + + ObjectIdNodeBase(null, ColKey column) + : ObjectIdNodeBase(ObjectId{}, column) + { + m_value_is_null = true; + } + + void cluster_changed() override + { + m_array_ptr = nullptr; + m_array_ptr = LeafPtr(new (&m_leaf_cache_storage) ArrayObjectIdNull(m_table.unchecked_ptr()->get_alloc())); + m_cluster->init_leaf(this->m_condition_column_key, m_array_ptr.get()); + m_leaf_ptr = m_array_ptr.get(); + } + + void init(bool will_query_ranges) override + { + ParentNode::init(will_query_ranges); + + m_dD = 100.0; + } + +protected: + ObjectIdNodeBase(const ObjectIdNodeBase& from) + : ParentNode(from) + , m_value(from.m_value) + , m_value_is_null(from.m_value_is_null) + { + } + + ObjectId m_value; + bool m_value_is_null = false; + using LeafCacheStorage = + typename std::aligned_storage::type; + using LeafPtr = std::unique_ptr; + LeafCacheStorage m_leaf_cache_storage; + LeafPtr m_array_ptr; + const ArrayObjectIdNull* m_leaf_ptr = nullptr; +}; + +template +class ObjectIdNode : public ObjectIdNodeBase { +public: + using ObjectIdNodeBase::ObjectIdNodeBase; + + size_t find_first_local(size_t start, size_t end) override + { + TConditionFunction cond; + for (size_t i = start; i < end; i++) { + util::Optional val = m_leaf_ptr->get(i); + if (val) { + if (cond(*val, m_value, false, m_value_is_null)) + return i; + } + else { + if (cond(ObjectId{}, m_value, true, m_value_is_null)) + return i; + } + } + return realm::npos; + } + + std::string describe(util::serializer::SerialisationState& state) const override + { + REALM_ASSERT(m_condition_column_key); + return state.describe_column(ParentNode::m_table, m_condition_column_key) + " " + + TConditionFunction::description() + " " + + (m_value_is_null ? util::serializer::print_value(realm::null()) + : util::serializer::print_value(ObjectIdNode::m_value)); + } + + std::unique_ptr clone() const override + { + return std::unique_ptr(new ObjectIdNode(*this)); + } + +protected: + ObjectIdNode(const ObjectIdNode& from, Transaction* tr) + : ObjectIdNode(from, tr) + { + } +}; + +class StringNodeBase : public ParentNode { +public: + using TConditionValue = StringData; + static const bool special_null_node = true; + + StringNodeBase(StringData v, ColKey column) + : m_value(v.is_null() ? util::none : util::make_optional(std::string(v))) + { + m_condition_column_key = column; + } + + void table_changed() override + { + m_is_string_enum = m_table.unchecked_ptr()->is_enumerated(m_condition_column_key); + } + + void cluster_changed() override + { + // Assigning nullptr will cause the Leaf destructor to be called. Must + // be done before assigning a new one. Otherwise the destructor will be + // called after the constructor is called and that is unfortunate if + // the object has the same address. (As in this case) + m_array_ptr = nullptr; + // Create new Leaf + m_array_ptr = LeafPtr(new (&m_leaf_cache_storage) ArrayString(m_table.unchecked_ptr()->get_alloc())); + m_cluster->init_leaf(this->m_condition_column_key, m_array_ptr.get()); + m_leaf_ptr = m_array_ptr.get(); + } + + void init(bool will_query_ranges) override + { + ParentNode::init(will_query_ranges); + + m_dT = 10.0; + m_probes = 0; + m_matches = 0; + m_end_s = 0; + m_leaf_start = 0; + m_leaf_end = 0; + } + + virtual void clear_leaf_state() + { + m_array_ptr = nullptr; + } + + StringNodeBase(const StringNodeBase& from) + : ParentNode(from) + , m_value(from.m_value) + , m_is_string_enum(from.m_is_string_enum) + { + } + + virtual std::string describe(util::serializer::SerialisationState& state) const override + { + REALM_ASSERT(m_condition_column_key); + StringData sd; + if (bool(StringNodeBase::m_value)) { + sd = StringData(StringNodeBase::m_value.value()); + } + return state.describe_column(ParentNode::m_table, m_condition_column_key) + " " + describe_condition() + " " + + util::serializer::print_value(sd); + } + +protected: + util::Optional m_value; + + using LeafCacheStorage = typename std::aligned_storage::type; + using LeafPtr = std::unique_ptr; + LeafCacheStorage m_leaf_cache_storage; + LeafPtr m_array_ptr; + const ArrayString* m_leaf_ptr = nullptr; + + bool m_is_string_enum = false; + + size_t m_end_s = 0; + size_t m_leaf_start = 0; + size_t m_leaf_end = 0; + + inline StringData get_string(size_t s) + { + return m_leaf_ptr->get(s); + } +}; + +// Conditions for strings. Note that Equal is specialized later in this file! +template +class StringNode : public StringNodeBase { +public: + StringNode(StringData v, ColKey column) + : StringNodeBase(v, column) + { + auto upper = case_map(v, true); + auto lower = case_map(v, false); + if (!upper || !lower) { + error_code = "Malformed UTF-8: " + std::string(v); + } + else { + m_ucase = std::move(*upper); + m_lcase = std::move(*lower); + } + } + + void init(bool will_query_ranges) override + { + clear_leaf_state(); + + m_dD = 100.0; + + StringNodeBase::init(will_query_ranges); + } + + size_t find_first_local(size_t start, size_t end) override + { + TConditionFunction cond; + + for (size_t s = start; s < end; ++s) { + StringData t = get_string(s); + + if (cond(StringData(m_value), m_ucase.c_str(), m_lcase.c_str(), t)) + return s; + } + return not_found; + } + + virtual std::string describe_condition() const override + { + return TConditionFunction::description(); + } + + std::unique_ptr clone() const override + { + return std::unique_ptr(new StringNode(*this)); + } + + StringNode(const StringNode& from) + : StringNodeBase(from) + , m_ucase(from.m_ucase) + , m_lcase(from.m_lcase) + { + } + +protected: + std::string m_ucase; + std::string m_lcase; +}; + +// Specialization for Contains condition on Strings - we specialize because we can utilize Boyer-Moore +template <> +class StringNode : public StringNodeBase { +public: + StringNode(StringData v, ColKey column) + : StringNodeBase(v, column) + , m_charmap() + { + if (v.size() == 0) + return; + + // Build a dictionary of char-to-last distances in the search string + // (zero indicates that the char is not in needle) + size_t last_char_pos = v.size() - 1; + for (size_t i = 0; i < last_char_pos; ++i) { + // we never jump longer increments than 255 chars, even if needle is longer (to fit in one byte) + uint8_t jump = last_char_pos - i < 255 ? static_cast(last_char_pos - i) : 255; + + unsigned char c = v[i]; + m_charmap[c] = jump; + } + } + + void init(bool will_query_ranges) override + { + clear_leaf_state(); + + m_dD = 100.0; + + StringNodeBase::init(will_query_ranges); + } + + + size_t find_first_local(size_t start, size_t end) override + { + Contains cond; + + for (size_t s = start; s < end; ++s) { + StringData t = get_string(s); + + if (cond(StringData(m_value), m_charmap, t)) + return s; + } + return not_found; + } + + virtual std::string describe_condition() const override + { + return Contains::description(); + } + + + std::unique_ptr clone() const override + { + return std::unique_ptr(new StringNode(*this)); + } + + StringNode(const StringNode& from) + : StringNodeBase(from) + , m_charmap(from.m_charmap) + { + } + +protected: + std::array m_charmap; +}; + +// Specialization for ContainsIns condition on Strings - we specialize because we can utilize Boyer-Moore +template <> +class StringNode : public StringNodeBase { +public: + StringNode(StringData v, ColKey column) + : StringNodeBase(v, column) + , m_charmap() + { + auto upper = case_map(v, true); + auto lower = case_map(v, false); + if (!upper || !lower) { + error_code = "Malformed UTF-8: " + std::string(v); + } + else { + m_ucase = std::move(*upper); + m_lcase = std::move(*lower); + } + + if (v.size() == 0) + return; + + // Build a dictionary of char-to-last distances in the search string + // (zero indicates that the char is not in needle) + size_t last_char_pos = m_ucase.size() - 1; + for (size_t i = 0; i < last_char_pos; ++i) { + // we never jump longer increments than 255 chars, even if needle is longer (to fit in one byte) + uint8_t jump = last_char_pos - i < 255 ? static_cast(last_char_pos - i) : 255; + + unsigned char uc = m_ucase[i]; + unsigned char lc = m_lcase[i]; + m_charmap[uc] = jump; + m_charmap[lc] = jump; + } + } + + void init(bool will_query_ranges) override + { + clear_leaf_state(); + + m_dD = 100.0; + + StringNodeBase::init(will_query_ranges); + } + + + size_t find_first_local(size_t start, size_t end) override + { + ContainsIns cond; + + for (size_t s = start; s < end; ++s) { + StringData t = get_string(s); + // The current behaviour is to return all results when querying for a null string. + // See comment above Query_NextGen_StringConditions on why every string including "" contains null. + if (!bool(m_value)) { + return s; + } + if (cond(StringData(m_value), m_ucase.c_str(), m_lcase.c_str(), m_charmap, t)) + return s; + } + return not_found; + } + + virtual std::string describe_condition() const override + { + return ContainsIns::description(); + } + + std::unique_ptr clone() const override + { + return std::unique_ptr(new StringNode(*this)); + } + + StringNode(const StringNode& from) + : StringNodeBase(from) + , m_charmap(from.m_charmap) + , m_ucase(from.m_ucase) + , m_lcase(from.m_lcase) + { + } + +protected: + std::array m_charmap; + std::string m_ucase; + std::string m_lcase; +}; + +class StringNodeEqualBase : public StringNodeBase { +public: + StringNodeEqualBase(StringData v, ColKey column) + : StringNodeBase(v, column) + { + } + StringNodeEqualBase(const StringNodeEqualBase& from) + : StringNodeBase(from) + , m_has_search_index(from.m_has_search_index) + { + } + + void init(bool) override; + + bool has_search_index() const override + { + return m_has_search_index; + } + + void cluster_changed() override + { + // If we use searchindex, we do not need further access to clusters + if (!m_has_search_index) { + StringNodeBase::cluster_changed(); + } + } + + + size_t find_first_local(size_t start, size_t end) override; + + virtual std::string describe_condition() const override + { + return Equal::description(); + } + +protected: + ObjKey m_actual_key; + ObjKey m_last_start_key; + size_t m_results_start; + size_t m_results_ndx; + size_t m_results_end; + bool m_has_search_index = false; + + inline BinaryData str_to_bin(const StringData& s) noexcept + { + return BinaryData(s.data(), s.size()); + } + + virtual ObjKey get_key(size_t ndx) = 0; + virtual void _search_index_init() = 0; + virtual size_t _find_first_local(size_t start, size_t end) = 0; +}; + +// Specialization for Equal condition on Strings - we specialize because we can utilize indexes (if they exist) for +// Equal. This specialisation also supports combining other StringNode conditions into itself in order to +// optimise the non-indexed linear search that can be happen when many conditions are OR'd together in an "IN" query. +// Future optimization: make specialization for greater, notequal, etc +template <> +class StringNode : public StringNodeEqualBase { +public: + using StringNodeEqualBase::StringNodeEqualBase; + + void table_changed() override + { + StringNodeBase::table_changed(); + m_has_search_index = m_table.unchecked_ptr()->has_search_index(m_condition_column_key) || + m_table.unchecked_ptr()->get_primary_key_column() == m_condition_column_key; + } + + void _search_index_init() override; + + bool do_consume_condition(ParentNode& other) override; + + std::unique_ptr clone() const override + { + return std::unique_ptr(new StringNode(*this)); + } + + std::string describe(util::serializer::SerialisationState& state) const override; + + StringNode(const StringNode& from) + : StringNodeEqualBase(from) + { + for (auto& needle : from.m_needles) { + if (needle.is_null()) { + m_needles.emplace(); + } + else { + m_needle_storage.push_back(std::make_unique(needle.size())); + std::copy(needle.data(), needle.data() + needle.size(), m_needle_storage.back().get()); + m_needles.insert(StringData(m_needle_storage.back().get(), needle.size())); + } + } + } + void index_based_aggregate(size_t limit, Evaluator evaluator) override + { + if (limit == 0) + return; + if (m_index_matches == nullptr) { + if (m_results_end) { // 1 result + auto obj = m_table->get_object(m_actual_key); + evaluator(obj); + } + } + else { // multiple results + for (size_t t = m_results_start; t < m_results_end && limit > 0; ++t) { + auto obj = m_table->get_object(ObjKey(m_index_matches->get(t))); + if (evaluator(obj)) { + --limit; + } + } + } + } + +private: + std::unique_ptr m_index_matches; + + ObjKey get_key(size_t ndx) override + { + if (IntegerColumn* vec = m_index_matches.get()) { + return ObjKey(vec->get(ndx)); + } + else if (m_results_end == 1) { + return m_actual_key; + } + return ObjKey(); + } + + size_t _find_first_local(size_t start, size_t end) override; + std::unordered_set m_needles; + std::vector> m_needle_storage; +}; + + +// Specialization for EqualIns condition on Strings - we specialize because we can utilize indexes (if they exist) for +// EqualIns. +template <> +class StringNode : public StringNodeEqualBase { +public: + StringNode(StringData v, ColKey column) + : StringNodeEqualBase(v, column) + { + auto upper = case_map(v, true); + auto lower = case_map(v, false); + if (!upper || !lower) { + error_code = "Malformed UTF-8: " + std::string(v); + } + else { + m_ucase = std::move(*upper); + m_lcase = std::move(*lower); + } + } + + void clear_leaf_state() override + { + StringNodeEqualBase::clear_leaf_state(); + m_index_matches.clear(); + } + + void table_changed() override + { + StringNodeBase::table_changed(); + m_has_search_index = m_table.unchecked_ptr()->has_search_index(m_condition_column_key); + } + void _search_index_init() override; + + virtual std::string describe_condition() const override + { + return EqualIns::description(); + } + + std::unique_ptr clone() const override + { + return std::unique_ptr(new StringNode(*this)); + } + + StringNode(const StringNode& from) + : StringNodeEqualBase(from) + , m_ucase(from.m_ucase) + , m_lcase(from.m_lcase) + { + } + + void index_based_aggregate(size_t limit, Evaluator evaluator) override + { + for (size_t t = 0; t < m_index_matches.size() && limit > 0; ++t) { + auto obj = m_table->get_object(m_index_matches[t]); + if (evaluator(obj)) { + --limit; + } + } + } + +private: + // Used for index lookup + std::vector m_index_matches; + std::string m_ucase; + std::string m_lcase; + + ObjKey get_key(size_t ndx) override + { + return m_index_matches[ndx]; + } + + size_t _find_first_local(size_t start, size_t end) override; +}; + +// OR node contains at least two node pointers: Two or more conditions to OR +// together in m_conditions, and the next AND condition (if any) in m_child. +// +// For 'second.equal(23).begin_group().first.equal(111).Or().first.equal(222).end_group().third().equal(555)', this +// will first set m_conditions[0] = left-hand-side through constructor, and then later, when .first.equal(222) is +// invoked, invocation will set m_conditions[1] = right-hand-side through Query& Query::Or() (see query.cpp). +// In there, m_child is also set to next AND condition (if any exists) following the OR. +class OrNode : public ParentNode { +public: + OrNode(std::unique_ptr condition) + { + m_dT = 50.0; + if (condition) + m_conditions.emplace_back(std::move(condition)); + } + + OrNode(const OrNode& other) + : ParentNode(other) + { + for (const auto& condition : other.m_conditions) { + m_conditions.emplace_back(condition->clone()); + } + } + + void table_changed() override + { + for (auto& condition : m_conditions) { + condition->set_table(m_table); + } + } + + void cluster_changed() override + { + for (auto& condition : m_conditions) { + condition->set_cluster(m_cluster); + } + + m_start.clear(); + m_start.resize(m_conditions.size(), 0); + + m_last.clear(); + m_last.resize(m_conditions.size(), 0); + + m_was_match.clear(); + m_was_match.resize(m_conditions.size(), false); + } + + std::string describe(util::serializer::SerialisationState& state) const override + { + std::string s; + for (size_t i = 0; i < m_conditions.size(); ++i) { + if (m_conditions[i]) { + s += m_conditions[i]->describe_expression(state); + if (i != m_conditions.size() - 1) { + s += " or "; + } + } + } + if (m_conditions.size() > 1) { + s = "(" + s + ")"; + } + return s; + } + + void collect_dependencies(std::vector& versions) const override + { + for (const auto& cond : m_conditions) { + cond->collect_dependencies(versions); + } + } + + void init(bool will_query_ranges) override + { + ParentNode::init(will_query_ranges); + + m_dD = 10.0; + + combine_conditions(!will_query_ranges); + + m_start.clear(); + m_start.resize(m_conditions.size(), 0); + + m_last.clear(); + m_last.resize(m_conditions.size(), 0); + + m_was_match.clear(); + m_was_match.resize(m_conditions.size(), false); + + std::vector v; + for (auto& condition : m_conditions) { + condition->init(will_query_ranges); + v.clear(); + condition->gather_children(v); + } + } + + size_t find_first_local(size_t start, size_t end) override + { + if (start >= end) + return not_found; + + size_t index = not_found; + + for (size_t c = 0; c < m_conditions.size(); ++c) { + // out of order search; have to discard cached results + if (start < m_start[c]) { + m_last[c] = 0; + m_was_match[c] = false; + } + // already searched this range and didn't match + else if (m_last[c] >= end) + continue; + // already search this range and *did* match + else if (m_was_match[c] && m_last[c] >= start) { + if (index > m_last[c]) + index = m_last[c]; + continue; + } + + m_start[c] = start; + size_t fmax = std::max(m_last[c], start); + size_t f = m_conditions[c]->find_first(fmax, end); + m_was_match[c] = f != not_found; + m_last[c] = f == not_found ? end : f; + if (f != not_found && index > m_last[c]) + index = m_last[c]; + } + + return index; + } + + std::string validate() override + { + if (error_code != "") + return error_code; + if (m_conditions.size() == 0) + return "Missing left-hand side of OR"; + if (m_conditions.size() == 1) + return "Missing right-hand side of OR"; + std::string s; + if (m_child != 0) + s = m_child->validate(); + if (s != "") + return s; + for (size_t i = 0; i < m_conditions.size(); ++i) { + s = m_conditions[i]->validate(); + if (s != "") + return s; + } + return ""; + } + + std::unique_ptr clone() const override + { + return std::unique_ptr(new OrNode(*this)); + } + + std::vector> m_conditions; + +private: + void combine_conditions(bool ignore_indexes) + { + std::sort(m_conditions.begin(), m_conditions.end(), + [](auto& a, auto& b) { return a->m_condition_column_key < b->m_condition_column_key; }); + + auto prev = m_conditions.begin()->get(); + auto cond = [&](auto& node) { + if (prev->consume_condition(*node, ignore_indexes)) + return true; + prev = &*node; + return false; + }; + m_conditions.erase(std::remove_if(m_conditions.begin() + 1, m_conditions.end(), cond), m_conditions.end()); + } + + // start index of the last find for each cond + std::vector m_start; + // last looked at index of the lasft find for each cond + // is a matching index if m_was_match is true + std::vector m_last; + std::vector m_was_match; +}; + + +class NotNode : public ParentNode { +public: + NotNode(std::unique_ptr condition) + : m_condition(std::move(condition)) + { + m_dT = 50.0; + } + + void table_changed() override + { + m_condition->set_table(m_table); + } + + void cluster_changed() override + { + m_condition->set_cluster(m_cluster); + // Heuristics bookkeeping: + m_known_range_start = 0; + m_known_range_end = 0; + m_first_in_known_range = not_found; + } + + void init(bool will_query_ranges) override + { + ParentNode::init(will_query_ranges); + + m_dD = 10.0; + + std::vector v; + + m_condition->init(false); + v.clear(); + m_condition->gather_children(v); + } + + size_t find_first_local(size_t start, size_t end) override; + + std::string validate() override + { + if (error_code != "") + return error_code; + if (m_condition == 0) + return "Missing argument to Not"; + std::string s; + if (m_child != 0) + s = m_child->validate(); + if (s != "") + return s; + s = m_condition->validate(); + if (s != "") + return s; + return ""; + } + + std::string describe(util::serializer::SerialisationState& state) const override + { + if (m_condition) { + return "!(" + m_condition->describe_expression(state) + ")"; + } + return "!()"; + } + + void collect_dependencies(std::vector& versions) const override + { + if (m_condition) { + m_condition->collect_dependencies(versions); + } + } + + + std::unique_ptr clone() const override + { + return std::unique_ptr(new NotNode(*this)); + } + + NotNode(const NotNode& from) + : ParentNode(from) + , m_condition(from.m_condition ? from.m_condition->clone() : nullptr) + , m_known_range_start(from.m_known_range_start) + , m_known_range_end(from.m_known_range_end) + , m_first_in_known_range(from.m_first_in_known_range) + { + } + + std::unique_ptr m_condition; + +private: + // FIXME This heuristic might as well be reused for all condition nodes. + size_t m_known_range_start; + size_t m_known_range_end; + size_t m_first_in_known_range; + + bool evaluate_at(size_t rowndx); + void update_known(size_t start, size_t end, size_t first); + size_t find_first_loop(size_t start, size_t end); + size_t find_first_covers_known(size_t start, size_t end); + size_t find_first_covered_by_known(size_t start, size_t end); + size_t find_first_overlap_lower(size_t start, size_t end); + size_t find_first_overlap_upper(size_t start, size_t end); + size_t find_first_no_overlap(size_t start, size_t end); +}; + + +// Compare two columns with eachother row-by-row +template +class TwoColumnsNode : public ParentNode { +public: + using TConditionValue = typename LeafType::value_type; + + TwoColumnsNode(ColKey column1, ColKey column2) + { + m_dT = 100.0; + m_condition_column_key1 = column1; + m_condition_column_key2 = column2; + } + + ~TwoColumnsNode() noexcept override + { + } + + void cluster_changed() override + { + m_array_ptr1 = nullptr; + m_array_ptr1 = LeafPtr(new (&m_leaf_cache_storage1) LeafType(m_table.unchecked_ptr()->get_alloc())); + this->m_cluster->init_leaf(this->m_condition_column_key1, m_array_ptr1.get()); + m_leaf_ptr1 = m_array_ptr1.get(); + + m_array_ptr2 = nullptr; + m_array_ptr2 = LeafPtr(new (&m_leaf_cache_storage2) LeafType(m_table.unchecked_ptr()->get_alloc())); + this->m_cluster->init_leaf(this->m_condition_column_key2, m_array_ptr2.get()); + m_leaf_ptr2 = m_array_ptr2.get(); + } + + virtual std::string describe(util::serializer::SerialisationState& state) const override + { + REALM_ASSERT(m_condition_column_key1 && m_condition_column_key2); + return state.describe_column(ParentNode::m_table, m_condition_column_key1) + " " + describe_condition() + + " " + state.describe_column(ParentNode::m_table, m_condition_column_key2); + } + + virtual std::string describe_condition() const override + { + return TConditionFunction::description(); + } + + void init(bool will_query_ranges) override + { + ParentNode::init(will_query_ranges); + m_dD = 100.0; + } + + size_t find_first_local(size_t start, size_t end) override + { + size_t s = start; + + while (s < end) { + if (std::is_same::value) { + // For int64_t we've created an array intrinsics named compare_leafs which template expands bitwidths + // of boths arrays to make Get faster. + QueryState qs(act_ReturnFirst); + bool resume = m_leaf_ptr1->template compare_leafs( + m_leaf_ptr2, start, end, 0, &qs, CallbackDummy()); + + if (resume) + s = end; + else + return to_size_t(qs.m_state); + } + else { +// This is for float and double. + +#if 0 && defined(REALM_COMPILER_AVX) +// AVX has been disabled because of array alignment (see https://app.asana.com/0/search/8836174089724/5763107052506) +// +// For AVX you can call things like if (sseavx<1>()) to test for AVX, and then utilize _mm256_movemask_ps (VC) +// or movemask_cmp_ps (gcc/clang) +// +// See https://github.com/rrrlasse/realm/tree/AVX for an example of utilizing AVX for a two-column search which has +// been benchmarked to: floats: 288 ms vs 552 by using AVX compared to 2-level-unrolled FPU loop. doubles: 415 ms vs +// 475 (more bandwidth bound). Tests against SSE have not been performed; AVX may not pay off. Please benchmark +#endif + + TConditionValue v1 = m_leaf_ptr1->get(s); + TConditionValue v2 = m_leaf_ptr2->get(s); + TConditionFunction C; + + if (C(v1, v2)) + return s; + else + s++; + } + } + return not_found; + } + + std::unique_ptr clone() const override + { + return std::unique_ptr(new TwoColumnsNode(*this)); + } + + TwoColumnsNode(const TwoColumnsNode& from) + : ParentNode(from) + , m_condition_column_key1(from.m_condition_column_key1) + , m_condition_column_key2(from.m_condition_column_key2) + { + } + +private: + mutable ColKey m_condition_column_key1; + mutable ColKey m_condition_column_key2; + + using LeafCacheStorage = typename std::aligned_storage::type; + using LeafPtr = std::unique_ptr; + + LeafCacheStorage m_leaf_cache_storage1; + LeafPtr m_array_ptr1; + const LeafType* m_leaf_ptr1 = nullptr; + LeafCacheStorage m_leaf_cache_storage2; + LeafPtr m_array_ptr2; + const LeafType* m_leaf_ptr2 = nullptr; +}; + + +// For Next-Generation expressions like col1 / col2 + 123 > col4 * 100. +class ExpressionNode : public ParentNode { +public: + ExpressionNode(std::unique_ptr); + + void init(bool) override; + size_t find_first_local(size_t start, size_t end) override; + + void table_changed() override; + void cluster_changed() override; + void collect_dependencies(std::vector&) const override; + + virtual std::string describe(util::serializer::SerialisationState& state) const override; + + std::unique_ptr clone() const override; + +private: + ExpressionNode(const ExpressionNode& from); + + std::unique_ptr m_expression; +}; + + +class LinksToNode : public ParentNode { +public: + LinksToNode(ColKey origin_column_key, ObjKey target_key) + : m_target_keys(1, target_key) + { + m_dD = 10.0; + m_dT = 50.0; + m_condition_column_key = origin_column_key; + } + + LinksToNode(ColKey origin_column_key, const std::vector& target_keys) + : m_target_keys(target_keys) + { + m_dD = 10.0; + m_dT = 50.0; + m_condition_column_key = origin_column_key; + } + + void table_changed() override + { + m_column_type = m_table.unchecked_ptr()->get_column_type(m_condition_column_key); + REALM_ASSERT(m_column_type == type_Link || m_column_type == type_LinkList); + } + + void cluster_changed() override + { + m_array_ptr = nullptr; + if (m_column_type == type_Link) { + m_array_ptr = LeafPtr(new (&m_storage.m_list) ArrayKey(m_table.unchecked_ptr()->get_alloc())); + } + else if (m_column_type == type_LinkList) { + m_array_ptr = LeafPtr(new (&m_storage.m_linklist) ArrayList(m_table.unchecked_ptr()->get_alloc())); + } + m_cluster->init_leaf(this->m_condition_column_key, m_array_ptr.get()); + m_leaf_ptr = m_array_ptr.get(); + } + + virtual std::string describe(util::serializer::SerialisationState& state) const override + { + REALM_ASSERT(m_condition_column_key); + if (m_target_keys.size() > 1) + throw SerialisationError("Serialising a query which links to multiple objects is currently unsupported."); + return state.describe_column(ParentNode::m_table, m_condition_column_key) + " " + describe_condition() + " " + + util::serializer::print_value(m_target_keys[0]); + } + + virtual std::string describe_condition() const override + { + return "=="; + } + + size_t find_first_local(size_t start, size_t end) override + { + if (m_column_type == type_Link) { + for (auto& key : m_target_keys) { + if (key) { + // LinkColumn stores link to row N as the integer N + 1 + auto pos = static_cast(m_leaf_ptr)->find_first(key, start, end); + if (pos != realm::npos) { + return pos; + } + } + } + } + else if (m_column_type == type_LinkList) { + ArrayKeyNonNullable arr(m_table.unchecked_ptr()->get_alloc()); + for (size_t i = start; i < end; i++) { + if (ref_type ref = static_cast(m_leaf_ptr)->get(i)) { + arr.init_from_ref(ref); + for (auto& key : m_target_keys) { + if (key) { + if (arr.find_first(key, 0, arr.size()) != not_found) + return i; + } + } + } + } + } + + return not_found; + } + + std::unique_ptr clone() const override + { + return std::unique_ptr(new LinksToNode(*this)); + } + +private: + std::vector m_target_keys; + DataType m_column_type = type_Link; + using LeafPtr = std::unique_ptr; + union Storage { + typename std::aligned_storage::type m_list; + typename std::aligned_storage::type m_linklist; + }; + Storage m_storage; + LeafPtr m_array_ptr; + const ArrayPayload* m_leaf_ptr = nullptr; + + + LinksToNode(const LinksToNode& source) + : ParentNode(source) + , m_target_keys(source.m_target_keys) + , m_column_type(source.m_column_type) + { + } +}; + +} // namespace realm + +#endif // REALM_QUERY_ENGINE_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/query_expression.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/query_expression.hpp new file mode 100644 index 0000000..3f30e2f --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/query_expression.hpp @@ -0,0 +1,4635 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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. + * + **************************************************************************/ + +/* +This file lets you write queries in C++ syntax like: Expression* e = (first + 1 / second >= third + 12.3); + +Type conversion/promotion semantics is the same as in the C++ expressions, e.g float + int > double == float + +(float)int > double. + + +Grammar: +----------------------------------------------------------------------------------------------------------------------- + Expression: Subexpr2 Compare Subexpr2 + operator! Expression + + Subexpr2: Value + Columns + Subexpr2 Operator Subexpr2 + power(Subexpr2) // power(x) = x * x, as example of unary operator + + Value: T + + Operator>: +, -, *, / + + Compare: ==, !=, >=, <=, >, < + + T: bool, int, int64_t, float, double, StringData + + +Class diagram +----------------------------------------------------------------------------------------------------------------------- +Subexpr2 + void evaluate(size_t i, ValueBase* destination) + +Compare: public Subexpr2 + size_t find_first(size_t start, size_t end) // main method that executes query + + unique_ptr m_left; // left expression subtree + unique_ptr m_right; // right expression subtree + +Operator: public Subexpr2 + void evaluate(size_t i, ValueBase* destination) + unique_ptr m_left; // left expression subtree + unique_ptr m_right; // right expression subtree + +Value: public Subexpr2 + void evaluate(size_t i, ValueBase* destination) + T m_v[8]; + +Columns: public Subexpr2 + void evaluate(size_t i, ValueBase* destination) + SequentialGetter sg; // class bound to a column, lets you read values in a fast way + Table* m_table; + +class ColumnAccessor<>: public Columns + + +Call diagram: +----------------------------------------------------------------------------------------------------------------------- +Example of 'table.first > 34.6 + table.second': + +size_t Compare::find_first()-------------+ + | | + | | + | | + +--> Columns::evaluate() +--------> Operator::evaluate() + | | + Value::evaluate() Columns::evaluate() + +Operator, Value and Columns have an evaluate(size_t i, ValueBase* destination) method which returns a Value +containing 8 values representing table rows i...i + 7. + +So Value contains 8 concecutive values and all operations are based on these chunks. This is +to save overhead by virtual calls needed for evaluating a query that has been dynamically constructed at runtime. + + +Memory allocation: +----------------------------------------------------------------------------------------------------------------------- +Subexpressions created by the end-user are stack allocated. They are cloned to the heap when passed to UnaryOperator, +Operator, and Compare. Those types own the clones and deallocate them when destroyed. + + +Caveats, notes and todos +----------------------------------------------------------------------------------------------------------------------- + * Perhaps disallow columns from two different tables in same expression + * The name Columns (with s) an be confusing because we also have Column (without s) + * We have Columns::m_table, Query::m_table and ColumnAccessorBase::m_table that point at the same thing, even with + ColumnAccessor<> extending Columns. So m_table is redundant, but this is in order to keep class dependencies and + entanglement low so that the design is flexible (if you perhaps later want a Columns class that is not dependent + on ColumnAccessor) + +Nulls +----------------------------------------------------------------------------------------------------------------------- +First note that at array level, nulls are distinguished between non-null in different ways: +String: + m_data == 0 && m_size == 0 + +Integer, Bool stored in ArrayIntNull: + value == get(0) (entry 0 determins a magic value that represents nulls) + +Float/double: + null::is_null(value) which tests if value bit-matches one specific bit pattern reserved for null + +The Columns class encapsulates all this into a simple class that, for any type T has + evaluate(size_t index) that reads values from a column, taking nulls in count + get(index) + set(index) + is_null(index) + set_null(index) +*/ + +#ifndef REALM_QUERY_EXPRESSION_HPP +#define REALM_QUERY_EXPRESSION_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +// Normally, if a next-generation-syntax condition is supported by the old query_engine.hpp, a query_engine node is +// created because it's faster (by a factor of 5 - 10). Because many of our existing next-generation-syntax unit +// unit tests are indeed simple enough to fallback to old query_engine, query_expression gets low test coverage. Undef +// flag to get higher query_expression test coverage. This is a good idea to try out each time you develop on/modify +// query_expression. + +#define REALM_OLDQUERY_FALLBACK + +namespace realm { + +template +T minimum(T a, T b) +{ + return a < b ? a : b; +} + +#ifdef REALM_OLDQUERY_FALLBACK +// Hack to avoid template instantiation errors. See create(). Todo, see if we can simplify only_numeric somehow +namespace _impl { + +template +inline T only_numeric(U in) +{ + return static_cast(util::unwrap(in)); +} + +template +inline Decimal128 only_numeric(const Decimal128& d) +{ + return d; +} + +template +inline int only_numeric(const StringData&) +{ + REALM_ASSERT(false); + return 0; +} + +template +inline int only_numeric(const BinaryData&) +{ + REALM_ASSERT(false); + return 0; +} + + +template +inline int only_numeric(const realm::null&) +{ + REALM_ASSERT(false); + return 0; +} + +template +inline std::enable_if_t, int> only_numeric(const ObjectId&) +{ + REALM_ASSERT(false); + return 0; +} + +template +inline std::enable_if_t, int> only_numeric(const Timestamp&) +{ + REALM_ASSERT(false); + return 0; +} + +template +inline StringData only_string_op_types(T in) +{ + REALM_ASSERT(false); + static_cast(in); + return StringData(); +} + +inline BinaryData only_string_op_types(BinaryData in) +{ + return in; +} + +template <> +inline StringData only_string_op_types(StringData in) +{ + return in; +} + +template +inline T no_timestamp(U in) +{ + return static_cast(util::unwrap(in)); +} + +template +inline int no_timestamp(const Timestamp&) +{ + REALM_ASSERT(false); + return 0; +} + +} // namespace _impl + +#endif // REALM_OLDQUERY_FALLBACK + +template +struct Plus { + T operator()(T v1, T v2) const + { + return v1 + v2; + } + static std::string description() + { + return "+"; + } + typedef T type; +}; + +template +struct Minus { + T operator()(T v1, T v2) const + { + return v1 - v2; + } + static std::string description() + { + return "-"; + } + typedef T type; +}; + +template +struct Div { + T operator()(T v1, T v2) const + { + return v1 / v2; + } + static std::string description() + { + return "/"; + } + typedef T type; +}; + +template +struct Mul { + T operator()(T v1, T v2) const + { + return v1 * v2; + } + static std::string description() + { + return "*"; + } + typedef T type; +}; + +// Unary operator +template +struct Pow { + T operator()(T v) const + { + return v * v; + } + static std::string description() + { + return "^"; + } + typedef T type; +}; + +// Finds a common type for T1 and T2 according to C++ conversion/promotion in arithmetic (float + int => float, etc) +template ::is_integer || std::is_same_v, + bool T2_is_int = std::numeric_limits::is_integer || std::is_same_v, + bool T1_is_widest = (sizeof(T1) > sizeof(T2) || std::is_same_v)> +struct Common; +template +struct Common { + typedef T1 type; +}; +template +struct Common { + typedef T2 type; +}; +template +struct Common { + typedef T1 type; +}; +template +struct Common { + typedef T2 type; +}; + + +struct ValueBase { + static const size_t chunk_size = 8; + virtual void export_bool(ValueBase& destination) const = 0; + virtual void export_Timestamp(ValueBase& destination) const = 0; + virtual void export_ObjectId(ValueBase& destination) const = 0; + virtual void export_Decimal(ValueBase& destination) const = 0; + virtual void export_int(ValueBase& destination) const = 0; + virtual void export_float(ValueBase& destination) const = 0; + virtual void export_int64_t(ValueBase& destination) const = 0; + virtual void export_double(ValueBase& destination) const = 0; + virtual void export_StringData(ValueBase& destination) const = 0; + virtual void export_BinaryData(ValueBase& destination) const = 0; + virtual void export_null(ValueBase& destination) const = 0; + virtual void import(const ValueBase& destination) = 0; + + // If true, all values in the class come from a link list of a single field in the parent table (m_table). If + // false, then values come from successive rows of m_table (query operations are operated on in bulks for speed) + bool m_from_link_list; + + // Number of values stored in the class. + size_t m_values; +}; + +class Expression { +public: + Expression() + { + } + virtual ~Expression() + { + } + + virtual double init() + { + return 50.0; // Default dT + } + + virtual size_t find_first(size_t start, size_t end) const = 0; + virtual void set_base_table(ConstTableRef table) = 0; + virtual void set_cluster(const Cluster*) = 0; + virtual void collect_dependencies(std::vector&) const + { + } + virtual ConstTableRef get_base_table() const = 0; + virtual std::string description(util::serializer::SerialisationState& state) const = 0; + + virtual std::unique_ptr clone() const = 0; +}; + +template +std::unique_ptr make_expression(Args&&... args) +{ + return std::unique_ptr(new T(std::forward(args)...)); +} + +class Subexpr { +public: + virtual ~Subexpr() + { + } + + virtual std::unique_ptr clone() const = 0; + + // When the user constructs a query, it always "belongs" to one single base/parent table (regardless of + // any links or not and regardless of any queries assembled with || or &&). When you do a Query::find(), + // then Query::m_table is set to this table, and set_base_table() is called on all Columns and LinkMaps in + // the query expression tree so that they can set/update their internals as required. + // + // During thread-handover of a Query, set_base_table() is also called to make objects point at the new table + // instead of the old one from the old thread. + virtual void set_base_table(ConstTableRef) {} + + virtual std::string description(util::serializer::SerialisationState& state) const = 0; + + virtual void set_cluster(const Cluster*) + { + } + + // Recursively fetch tables of columns in expression tree. Used when user first builds a stand-alone expression + // and + // binds it to a Query at a later time + virtual ConstTableRef get_base_table() const + { + return nullptr; + } + + virtual void collect_dependencies(std::vector&) const + { + } + + virtual bool has_constant_evaluation() const + { + return false; + } + + virtual bool has_search_index() const + { + return false; + } + + virtual std::vector find_all(Mixed) const + { + return {}; + } + + virtual DataType get_type() const = 0; + + virtual void evaluate(size_t index, ValueBase& destination) = 0; + // This function supports SubColumnAggregate + virtual void evaluate(ObjKey, ValueBase&) + { + REALM_ASSERT(false); // Unimplemented + } + + virtual ExpressionComparisonType get_comparison_type() const + { + return ExpressionComparisonType::Any; + } +}; + +template +std::unique_ptr make_subexpr(Args&&... args) +{ + return std::unique_ptr(new T(std::forward(args)...)); +} + +template +class Columns; +template +class Value; +class ConstantStringValue; +template +class Subexpr2; +template +class Operator; +template +class UnaryOperator; +template +class SizeOperator; +template +class Compare; +template +class UnaryLinkCompare; +class ColumnAccessorBase; + + +// Handle cases where left side is a constant (int, float, int64_t, double, StringData) +template +Query create(L left, const Subexpr2& right) +{ +// Purpose of below code is to intercept the creation of a condition and test if it's supported by the old +// query_engine.hpp which is faster. If it's supported, create a query_engine.hpp node, otherwise create a +// query_expression.hpp node. +// +// This method intercepts only Value Subexpr2. Interception of Subexpr2 Subexpr is elsewhere. + +#ifdef REALM_OLDQUERY_FALLBACK // if not defined, then never fallback to query_engine.hpp; always use query_expression + const Columns* column = dynamic_cast*>(&right); + // TODO: recognize size operator expressions + // auto size_operator = dynamic_cast, Subexpr>*>(&right); + + if (column && + ((std::numeric_limits::is_integer && std::numeric_limits::is_integer) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v)) && + !column->links_exist()) { + ConstTableRef t = column->get_base_table(); + Query q = Query(t); + + if (std::is_same_v) + q.greater(column->column_key(), _impl::only_numeric(left)); + else if (std::is_same_v) + q.less(column->column_key(), _impl::only_numeric(left)); + else if (std::is_same_v) + q.equal(column->column_key(), left); + else if (std::is_same_v) + q.not_equal(column->column_key(), left); + else if (std::is_same_v) + q.greater_equal(column->column_key(), _impl::only_numeric(left)); + else if (std::is_same_v) + q.less_equal(column->column_key(), _impl::only_numeric(left)); + else if (std::is_same_v) + q.equal(column->column_key(), _impl::only_string_op_types(left), false); + else if (std::is_same_v) + q.not_equal(column->column_key(), _impl::only_string_op_types(left), false); + else if (std::is_same_v) + q.begins_with(column->column_key(), _impl::only_string_op_types(left)); + else if (std::is_same_v) + q.begins_with(column->column_key(), _impl::only_string_op_types(left), false); + else if (std::is_same_v) + q.ends_with(column->column_key(), _impl::only_string_op_types(left)); + else if (std::is_same_v) + q.ends_with(column->column_key(), _impl::only_string_op_types(left), false); + else if (std::is_same_v) + q.contains(column->column_key(), _impl::only_string_op_types(left)); + else if (std::is_same_v) + q.contains(column->column_key(), _impl::only_string_op_types(left), false); + else if (std::is_same_v) + q.like(column->column_key(), _impl::only_string_op_types(left)); + else if (std::is_same_v) + q.like(column->column_key(), _impl::only_string_op_types(left), false); + else { + // query_engine.hpp does not support this Cond. Please either add support for it in query_engine.hpp or + // fallback to using use 'return new Compare<>' instead. + REALM_ASSERT(false); + } + // Return query_engine.hpp node + return q; + } + else +#endif + { + // Return query_expression.hpp node + using CommonType = typename Common::type; + using ValueType = + typename std::conditional, ConstantStringValue, Value>::type; + return make_expression>(make_subexpr(left), right.clone()); + } +} + + +// All overloads where left-hand-side is Subexpr2: +// +// left-hand-side operator right-hand-side +// Subexpr2 +, -, *, /, <, >, ==, !=, <=, >= R, Subexpr2 +// +// For L = R = {int, int64_t, float, double, StringData, Timestamp}: +template +class Overloads { + typedef typename Common::type CommonType; + + std::unique_ptr clone_subexpr() const + { + return static_cast&>(*this).clone(); + } + +public: + // Arithmetic, right side constant + Operator> operator+(R right) const + { + return {clone_subexpr(), make_subexpr>(right)}; + } + Operator> operator-(R right) const + { + return {clone_subexpr(), make_subexpr>(right)}; + } + Operator> operator*(R right) const + { + return {clone_subexpr(), make_subexpr>(right)}; + } + Operator> operator/(R right) const + { + return {clone_subexpr(), make_subexpr>(right)}; + } + + // Arithmetic, right side subexpression + Operator> operator+(const Subexpr2& right) const + { + return {clone_subexpr(), right.clone()}; + } + Operator> operator-(const Subexpr2& right) const + { + return {clone_subexpr(), right.clone()}; + } + Operator> operator*(const Subexpr2& right) const + { + return {clone_subexpr(), right.clone()}; + } + Operator> operator/(const Subexpr2& right) const + { + return {clone_subexpr(), right.clone()}; + } + + // Compare, right side constant + Query operator>(R right) + { + return create(right, static_cast&>(*this)); + } + Query operator<(R right) + { + return create(right, static_cast&>(*this)); + } + Query operator>=(R right) + { + return create(right, static_cast&>(*this)); + } + Query operator<=(R right) + { + return create(right, static_cast&>(*this)); + } + Query operator==(R right) + { + return create(right, static_cast&>(*this)); + } + Query operator!=(R right) + { + return create(right, static_cast&>(*this)); + } + + // Purpose of this method is to intercept the creation of a condition and test if it's supported by the old + // query_engine.hpp which is faster. If it's supported, create a query_engine.hpp node, otherwise create a + // query_expression.hpp node. + // + // This method intercepts Subexpr2 Subexpr2 only. Value Subexpr2 is intercepted elsewhere. + template + Query create2(const Subexpr2& right) + { +#ifdef REALM_OLDQUERY_FALLBACK // if not defined, never fallback query_engine; always use query_expression + // Test if expressions are of type Columns. Other possibilities are Value and Operator. + const Columns* left_col = dynamic_cast*>(static_cast*>(this)); + const Columns* right_col = dynamic_cast*>(&right); + + // query_engine supports 'T-column ' for T = {int64_t, float, double}, op = {<, >, ==, !=, <=, + // >=}, + // but only if both columns are non-nullable, and aren't in linked tables. + if (left_col && right_col && std::is_same_v && !left_col->is_nullable() && !right_col->is_nullable() && + !left_col->links_exist() && !right_col->links_exist()) { + ConstTableRef t = left_col->get_base_table(); + + if (std::numeric_limits::is_integer) { + if (std::is_same_v) + return Query(t).less_int(left_col->column_key(), right_col->column_key()); + if (std::is_same_v) + return Query(t).greater_int(left_col->column_key(), right_col->column_key()); + if (std::is_same_v) + return Query(t).equal_int(left_col->column_key(), right_col->column_key()); + if (std::is_same_v) + return Query(t).not_equal_int(left_col->column_key(), right_col->column_key()); + if (std::is_same_v) + return Query(t).less_equal_int(left_col->column_key(), right_col->column_key()); + if (std::is_same_v) + return Query(t).greater_equal_int(left_col->column_key(), right_col->column_key()); + } + else if (std::is_same_v) { + if (std::is_same_v) + return Query(t).less_float(left_col->column_key(), right_col->column_key()); + if (std::is_same_v) + return Query(t).greater_float(left_col->column_key(), right_col->column_key()); + if (std::is_same_v) + return Query(t).equal_float(left_col->column_key(), right_col->column_key()); + if (std::is_same_v) + return Query(t).not_equal_float(left_col->column_key(), right_col->column_key()); + if (std::is_same_v) + return Query(t).less_equal_float(left_col->column_key(), right_col->column_key()); + if (std::is_same_v) + return Query(t).greater_equal_float(left_col->column_key(), right_col->column_key()); + } + else if (std::is_same_v) { + if (std::is_same_v) + return Query(t).less_double(left_col->column_key(), right_col->column_key()); + if (std::is_same_v) + return Query(t).greater_double(left_col->column_key(), right_col->column_key()); + if (std::is_same_v) + return Query(t).equal_double(left_col->column_key(), right_col->column_key()); + if (std::is_same_v) + return Query(t).not_equal_double(left_col->column_key(), right_col->column_key()); + if (std::is_same_v) + return Query(t).less_equal_double(left_col->column_key(), right_col->column_key()); + if (std::is_same_v) + return Query(t).greater_equal_double(left_col->column_key(), right_col->column_key()); + } + } +#endif + // Return query_expression.hpp node + return make_expression::type>>(clone_subexpr(), right.clone()); + } + + // Compare, right side subexpression + Query operator==(const Subexpr2& right) + { + return create2(right); + } + Query operator!=(const Subexpr2& right) + { + return create2(right); + } + Query operator>(const Subexpr2& right) + { + return create2(right); + } + Query operator<(const Subexpr2& right) + { + return create2(right); + } + Query operator>=(const Subexpr2& right) + { + return create2(right); + } + Query operator<=(const Subexpr2& right) + { + return create2(right); + } +}; + +// With this wrapper class we can define just 20 overloads inside Overloads instead of 5 * 20 = 100. Todo: We +// can +// consider if it's simpler/better to remove this class completely and just list all 100 overloads manually anyway. +template +class Subexpr2 : public Subexpr, + public Overloads, + public Overloads, + public Overloads, + public Overloads, + public Overloads, + public Overloads, + public Overloads, + public Overloads, + public Overloads, + public Overloads, + public Overloads { +public: + virtual ~Subexpr2() + { + } + + DataType get_type() const final + { + return ColumnTypeTraits::id; + } + +#define RLM_U2(t, o) using Overloads::operator o; +#define RLM_U(o) \ + RLM_U2(int, o) \ + RLM_U2(float, o) \ + RLM_U2(double, o) \ + RLM_U2(int64_t, o) \ + RLM_U2(StringData, o) \ + RLM_U2(bool, o) \ + RLM_U2(Timestamp, o) \ + RLM_U2(ObjectId, o) \ + RLM_U2(Decimal128, o) \ + RLM_U2(null, o) + RLM_U(+) RLM_U(-) RLM_U(*) RLM_U(/) RLM_U(>) RLM_U(<) RLM_U(==) RLM_U(!=) RLM_U(>=) RLM_U(<=) +}; + +// Subexpr2 only provides equality comparisons. Their implementations can be found later in this file. +template <> +class Subexpr2 : public Subexpr { +public: + DataType get_type() const final + { + return type_Link; + } +}; + +template <> +class Subexpr2 : public Subexpr, public Overloads { +public: + Query equal(StringData sd, bool case_sensitive = true); + Query equal(const Subexpr2& col, bool case_sensitive = true); + Query not_equal(StringData sd, bool case_sensitive = true); + Query not_equal(const Subexpr2& col, bool case_sensitive = true); + Query begins_with(StringData sd, bool case_sensitive = true); + Query begins_with(const Subexpr2& col, bool case_sensitive = true); + Query ends_with(StringData sd, bool case_sensitive = true); + Query ends_with(const Subexpr2& col, bool case_sensitive = true); + Query contains(StringData sd, bool case_sensitive = true); + Query contains(const Subexpr2& col, bool case_sensitive = true); + Query like(StringData sd, bool case_sensitive = true); + Query like(const Subexpr2& col, bool case_sensitive = true); + DataType get_type() const final + { + return type_String; + } +}; + +template <> +class Subexpr2 : public Subexpr, public Overloads { +public: + Query equal(BinaryData sd, bool case_sensitive = true); + Query equal(const Subexpr2& col, bool case_sensitive = true); + Query not_equal(BinaryData sd, bool case_sensitive = true); + Query not_equal(const Subexpr2& col, bool case_sensitive = true); + Query begins_with(BinaryData sd, bool case_sensitive = true); + Query begins_with(const Subexpr2& col, bool case_sensitive = true); + Query ends_with(BinaryData sd, bool case_sensitive = true); + Query ends_with(const Subexpr2& col, bool case_sensitive = true); + Query contains(BinaryData sd, bool case_sensitive = true); + Query contains(const Subexpr2& col, bool case_sensitive = true); + Query like(BinaryData sd, bool case_sensitive = true); + Query like(const Subexpr2& col, bool case_sensitive = true); + DataType get_type() const final + { + return type_Binary; + } +}; + + +/* +This class is used to store N values of type T = {int64_t, bool or StringData}, and allows an entry +to be null too. It's used by the Value class for internal storage. + +To indicate nulls, we could have chosen a separate bool vector or some other bitmask construction. But for +performance, we customize indication of nulls to match the same indication that is used in the persisted database +file + +Queries in query_expression.hpp execute by processing chunks of 8 rows at a time. Assume you have a column: + + price (int) = {1, 2, 3, null, 1, 6, 6, 9, 5, 2, null} + +And perform a query: + + Query q = (price + 2 == 5); + +query_expression.hpp will then create a NullableVector = {5, 5, 5, 5, 5, 5, 5, 5} and then read values +NullableVector = {1, 2, 3, null, 1, 6, 6, 9} from the column, and then perform `+` and `==` on these chunks. + +See the top of this file for more information on all this. + +Assume the user specifies the null constant in a query: + +Query q = (price == null) + +The query system will then construct a NullableVector of type `null` (NullableVector). This allows compile +time optimizations for these cases. +*/ + +template +struct NullableVector { + + // Searches the PairsToMatch for the first that has the Query type as the first type and returns the second type. + // If no pair matches, returns the Query type unmodified. + template + struct TypeMapperImpl; + template + using TypeMapper = typename TypeMapperImpl::type; + + template + struct TypeMapperImpl { + using type = Query; // Base case + }; + template + struct TypeMapperImpl, Rest...> { + using type = V; // Found a match + }; + template + struct TypeMapperImpl, Rest...> { + using type = TypeMapper; // Keep looking + }; + + using t_storage = TypeMapper, // + std::pair, // + std::pair>>; + + NullableVector() + { + } + + NullableVector& operator=(const NullableVector& other) + { + if (this != &other) { + init(other.m_size); + realm::safe_copy_n(other.m_first, other.m_size, m_first); + m_null = other.m_null; + } + return *this; + } + + NullableVector(const NullableVector& other) + { + init(other.m_size); + realm::safe_copy_n(other.m_first, other.m_size, m_first); + m_null = other.m_null; + } + + ~NullableVector() + { + dealloc(); + } + + T operator[](size_t index) const + { + REALM_ASSERT_3(index, <, m_size); + return static_cast(m_first[index]); + } + + inline bool is_null(size_t index) const + { + REALM_ASSERT((std::is_same_v)); + return m_first[index] == m_null; + } + + inline void set_null(size_t index) + { + REALM_ASSERT((std::is_same_v)); + m_first[index] = m_null; + } + + template + typename std::enable_if, void>::type set(size_t index, t_storage value) + { + REALM_ASSERT((std::is_same_v)); + + // If value collides with magic null value, then switch to a new unique representation for null + if (REALM_UNLIKELY(value == m_null)) { + // adding a prime will generate 2^64 unique values. Todo: Only works on 2's complement architecture + uint64_t candidate = static_cast(m_null) + 0xfffffffbULL; + while (std::find(m_first, m_first + m_size, static_cast(candidate)) != m_first + m_size) + candidate += 0xfffffffbULL; + std::replace(m_first, m_first + m_size, m_null, static_cast(candidate)); + } + m_first[index] = value; + } + + template + typename std::enable_if::value, + void>::type + set(size_t index, T value) + { + m_first[index] = value; + } + + inline util::Optional get(size_t index) const + { + if (is_null(index)) + return util::none; + + return util::make_optional((*this)[index]); + } + + inline void set(size_t index, util::Optional value) + { + if (value) { + set(index, *value); + } + else { + set_null(index); + } + } + + void fill(T value) + { + for (size_t t = 0; t < m_size; t++) { + if (std::is_same_v) + set_null(t); + else + set(t, value); + } + } + + void init(size_t size) + { + if (size == m_size) + return; + + dealloc(); + m_size = size; + if (m_size > 0) { + if (m_size > prealloc) + m_first = reinterpret_cast(new t_storage[m_size]); + else + m_first = m_cache; + } + } + + void init(size_t size, T values) + { + init(size); + fill(values); + } + + void init(const std::vector& values) + { + size_t sz = values.size(); + init(sz); + for (size_t t = 0; t < sz; t++) { + set(t, values[t]); + } + } + + void init(const std::vector>& values) + { + size_t sz = values.size(); + init(sz); + for (size_t t = 0; t < sz; t++) { + if (values[t]) { + set(t, values[t]); + } + else { + set_null(t); + } + } + } + + void dealloc() + { + if (m_first) { + if (m_size > prealloc) + delete[] m_first; + m_first = nullptr; + } + } + + t_storage m_cache[prealloc]; + t_storage* m_first = &m_cache[0]; + size_t m_size = 0; + + int64_t m_null = reinterpret_cast(&m_null); // choose magic value to represent nulls +}; + +template +struct NullableVector, prealloc>; // NullableVector> is banned. + +// Double +// NOTE: fails in gcc 4.8 without `inline`. Do not remove. Same applies for all methods below. +template <> +inline bool NullableVector::is_null(size_t index) const +{ + return null::is_null_float(m_first[index]); +} + +template <> +inline void NullableVector::set_null(size_t index) +{ + m_first[index] = null::get_null_float(); +} + +// Float +template <> +inline bool NullableVector::is_null(size_t index) const +{ + return null::is_null_float(m_first[index]); +} + +template <> +inline void NullableVector::set_null(size_t index) +{ + m_first[index] = null::get_null_float(); +} + + +// Null +template <> +inline void NullableVector::set_null(size_t) +{ + return; +} +template <> +inline bool NullableVector::is_null(size_t) const +{ + return true; +} + +// StringData + +template <> +inline bool NullableVector::is_null(size_t index) const +{ + return m_first[index].is_null(); +} + +template <> +inline void NullableVector::set_null(size_t index) +{ + m_first[index] = StringData(); +} + +// BinaryData + +template <> +inline bool NullableVector::is_null(size_t index) const +{ + return m_first[index].is_null(); +} + +template <> +inline void NullableVector::set_null(size_t index) +{ + m_first[index] = BinaryData(); +} + +// Timestamp + +template <> +inline bool NullableVector::is_null(size_t index) const +{ + return m_first[index].is_null(); +} + +template <> +inline void NullableVector::set_null(size_t index) +{ + m_first[index] = Timestamp{}; +} + +// ObjectId + +template <> +inline bool NullableVector::is_null(size_t index) const +{ + return !m_first[index]; +} + +template <> +inline void NullableVector::set_null(size_t index) +{ + m_first[index].reset(); +} + +template <> +inline ObjectId NullableVector::operator[](size_t index) const +{ + REALM_ASSERT_3(index, <, m_size); + const auto& opt = m_first[index]; + return opt ? *opt : ObjectId(); +} + +// Decimal128 + +template <> +inline bool NullableVector::is_null(size_t index) const +{ + return m_first[index].is_null(); +} + +template <> +inline void NullableVector::set_null(size_t index) +{ + m_first[index] = Decimal128{realm::null()}; +} + +// ref_type +template <> +inline bool NullableVector::is_null(size_t index) const +{ + return m_first[index] == 0; +} +template <> +inline void NullableVector::set_null(size_t index) +{ + m_first[index] = 0; +} + +// SizeOfList +template <> +inline bool NullableVector::is_null(size_t index) const +{ + return m_first[index].is_null(); +} +template <> +inline void NullableVector::set_null(size_t index) +{ + m_first[index].set_null(); +} + +// Key +template <> +inline bool NullableVector::is_null(size_t index) const +{ + return m_first[index] == null_key; +} +template <> +inline void NullableVector::set_null(size_t index) +{ + m_first[index] = ObjKey{}; +} + +template +struct OperatorOptionalAdapter { + template + util::Optional operator()(const util::Optional& left, const util::Optional& right) + { + if (!left || !right) + return util::none; + return Operator()(*left, *right); + } + + template + util::Optional operator()(const util::Optional& arg) + { + if (!arg) + return util::none; + return Operator()(*arg); + } +}; + + +struct TrueExpression : Expression { + size_t find_first(size_t start, size_t end) const override + { + REALM_ASSERT(start <= end); + if (start != end) + return start; + + return realm::not_found; + } + void set_base_table(ConstTableRef) override {} + void set_cluster(const Cluster*) override + { + } + ConstTableRef get_base_table() const override + { + return nullptr; + } + std::string description(util::serializer::SerialisationState&) const override + { + return "TRUEPREDICATE"; + } + std::unique_ptr clone() const override + { + return std::unique_ptr(new TrueExpression(*this)); + } +}; + + +struct FalseExpression : Expression { + size_t find_first(size_t, size_t) const override + { + return realm::not_found; + } + void set_base_table(ConstTableRef) override {} + void set_cluster(const Cluster*) override + { + } + std::string description(util::serializer::SerialisationState&) const override + { + return "FALSEPREDICATE"; + } + ConstTableRef get_base_table() const override + { + return nullptr; + } + std::unique_ptr clone() const override + { + return std::unique_ptr(new FalseExpression(*this)); + } +}; + + +// Stores N values of type T. Can also exchange data with other ValueBase of different types +template +class Value : public ValueBase, public Subexpr2 { +public: + Value() + { + init(false, 1, T()); + } + Value(T v) + { + init(false, 1, v); + } + + Value(bool from_link_list, size_t values) + { + init(from_link_list, values, T()); + } + + Value(bool from_link_list, size_t values, T v) + { + init(from_link_list, values, v); + } + + Value(const Value&) = default; + Value& operator=(const Value&) = default; + + void init(bool from_link_list, size_t values, T v) + { + m_storage.init(values, v); + ValueBase::m_from_link_list = from_link_list; + ValueBase::m_values = values; + } + + void init(bool from_link_list, size_t values) + { + m_storage.init(values); + ValueBase::m_from_link_list = from_link_list; + ValueBase::m_values = values; + } + + void init(bool from_link_list, const std::vector& values) + { + m_storage.init(values); + ValueBase::m_from_link_list = from_link_list; + ValueBase::m_values = values.size(); + } + + void init(bool from_link_list, const std::vector>& values) + { + m_storage.init(values); + ValueBase::m_from_link_list = from_link_list; + ValueBase::m_values = values.size(); + } + + std::string description(util::serializer::SerialisationState&) const override + { + if (ValueBase::m_from_link_list) { + return util::serializer::print_value(util::to_string(ValueBase::m_values) + + (ValueBase::m_values == 1 ? " value" : " values")); + } + if (m_storage.m_size > 0) { + return util::serializer::print_value(m_storage[0]); + } + return ""; + } + + bool has_constant_evaluation() const override + { + return true; + } + + void evaluate(size_t, ValueBase& destination) override + { + destination.import(*this); + } + + + template + REALM_FORCEINLINE void fun(const Value* left, const Value* right) + { + OperatorOptionalAdapter o; + + if (!left->m_from_link_list && !right->m_from_link_list) { + // Operate on values one-by-one (one value is one row; no links) + size_t min = std::min(left->m_values, right->m_values); + init(false, min); + + for (size_t i = 0; i < min; i++) { + m_storage.set(i, o(left->m_storage.get(i), right->m_storage.get(i))); + } + } + else if (left->m_from_link_list && right->m_from_link_list) { + // FIXME: Many-to-many links not supported yet. Need to specify behaviour + REALM_ASSERT_DEBUG(false); + } + else if (!left->m_from_link_list && right->m_from_link_list) { + // Right values come from link. Left must come from single row. + REALM_ASSERT_DEBUG(left->m_values > 0); + init(true, right->m_values); + + auto left_value = left->m_storage.get(0); + for (size_t i = 0; i < right->m_values; i++) { + m_storage.set(i, o(left_value, right->m_storage.get(i))); + } + } + else if (left->m_from_link_list && !right->m_from_link_list) { + // Same as above, but with left values coming from links + REALM_ASSERT_DEBUG(right->m_values > 0); + init(true, left->m_values); + + auto right_value = right->m_storage.get(0); + for (size_t i = 0; i < left->m_values; i++) { + m_storage.set(i, o(left->m_storage.get(i), right_value)); + } + } + } + + template + REALM_FORCEINLINE void fun(const Value* value) + { + init(value->m_from_link_list, value->m_values); + + OperatorOptionalAdapter o; + for (size_t i = 0; i < value->m_values; i++) { + m_storage.set(i, o(value->m_storage.get(i))); + } + } + + + // Below import and export methods are for type conversion between float, double, int64_t, etc. + template + REALM_FORCEINLINE std::enable_if_t::value> export2(ValueBase& destination) const + { + Value& d = static_cast&>(destination); + d.init(ValueBase::m_from_link_list, ValueBase::m_values, D()); + for (size_t t = 0; t < ValueBase::m_values; t++) { + if (m_storage.is_null(t)) + d.m_storage.set_null(t); + else { + d.m_storage.set(t, static_cast(m_storage[t])); + } + } + } + + template + static constexpr bool IsNullToObjectId = std::is_same::value&& std::is_same::value; + + template + static constexpr bool IsObjectIdToTimestamp = + std::is_same::value&& std::is_same::value; + + // we specialize here to convert between null and ObjectId without having a constructor from null + template + REALM_FORCEINLINE std::enable_if_t> export2(ValueBase& destination) const + { + Value& d = static_cast&>(destination); + d.init(ValueBase::m_from_link_list, ValueBase::m_values, D()); + for (size_t t = 0; t < ValueBase::m_values; t++) { + d.m_storage.set_null(t); + } + } + + // we specialize here because the conversion from ObjectId to Timestamp has been made explicit in order to catch + // wrong auto conversions + template + REALM_FORCEINLINE std::enable_if_t> export2(ValueBase& destination) const + { + Value& d = static_cast&>(destination); + d.init(ValueBase::m_from_link_list, ValueBase::m_values, D()); + for (size_t t = 0; t < ValueBase::m_values; t++) { + if (m_storage.is_null(t)) { + d.m_storage.set_null(t); + } + else { + d.m_storage.set(t, m_storage[t].get_timestamp()); + } + } + } + + template + REALM_FORCEINLINE + std::enable_if_t::value && !IsNullToObjectId && !IsObjectIdToTimestamp> + export2(ValueBase&) const + { + // export2 is instantiated for impossible conversions like T=StringData, D=int64_t. These are never + // performed at runtime but would result in a compiler error if we did not provide this implementation. + REALM_ASSERT_DEBUG(false); + } + + REALM_FORCEINLINE void export_Timestamp(ValueBase& destination) const override + { + export2(destination); + } + + REALM_FORCEINLINE void export_ObjectId(ValueBase& destination) const override + { + export2(destination); + } + + REALM_FORCEINLINE void export_Decimal(ValueBase& destination) const override + { + export2(destination); + } + + REALM_FORCEINLINE void export_bool(ValueBase& destination) const override + { + export2(destination); + } + + REALM_FORCEINLINE void export_int64_t(ValueBase& destination) const override + { + export2(destination); + } + + REALM_FORCEINLINE void export_float(ValueBase& destination) const override + { + export2(destination); + } + + REALM_FORCEINLINE void export_int(ValueBase& destination) const override + { + export2(destination); + } + + REALM_FORCEINLINE void export_double(ValueBase& destination) const override + { + export2(destination); + } + REALM_FORCEINLINE void export_StringData(ValueBase& destination) const override + { + export2(destination); + } + REALM_FORCEINLINE void export_BinaryData(ValueBase& destination) const override + { + export2(destination); + } + REALM_FORCEINLINE void export_null(ValueBase& destination) const override + { + Value& d = static_cast&>(destination); + d.init(m_from_link_list, m_values); + } + + REALM_FORCEINLINE void import(const ValueBase& source) override + { + if (std::is_same_v) + source.export_int(*this); + else if (std::is_same_v) + source.export_Timestamp(*this); + else if (std::is_same_v) + source.export_ObjectId(*this); + else if (std::is_same_v) + source.export_Decimal(*this); + else if (std::is_same_v) + source.export_bool(*this); + else if (std::is_same_v) + source.export_float(*this); + else if (std::is_same_v) + source.export_double(*this); + else if (std::is_same_v || std::is_same_v) + source.export_int64_t(*this); + else if (std::is_same_v) + source.export_StringData(*this); + else if (std::is_same_v) + source.export_BinaryData(*this); + else if (std::is_same_v) + source.export_null(*this); + else + REALM_ASSERT_DEBUG(false); + } + + // Given a TCond (==, !=, >, <, >=, <=) and two Value, return index of first match + template + REALM_FORCEINLINE static size_t compare_const(const Value* left, Value* right, + ExpressionComparisonType comparison) + { + TCond c; + const size_t sz = right->ValueBase::m_values; + bool left_is_null = left->m_storage.is_null(0); + if (!right->m_from_link_list) { + REALM_ASSERT_DEBUG(comparison == + ExpressionComparisonType::Any); // ALL/NONE not supported for non list types + for (size_t m = 0; m < sz; m++) { + if (c(left->m_storage[0], right->m_storage[m], left_is_null, right->m_storage.is_null(m))) + return m; + } + } + else if (comparison == ExpressionComparisonType::None) { + for (size_t m = 0; m < sz; m++) { + if (c(left->m_storage[0], right->m_storage[m], left_is_null, right->m_storage.is_null(m))) + return not_found; + } + return 0; // no values matched, return match + } + else if (comparison == ExpressionComparisonType::All) { + for (size_t m = 0; m < sz; m++) { + if (!c(left->m_storage[0], right->m_storage[m], left_is_null, right->m_storage.is_null(m))) + return not_found; // one did not match + } + return 0; // all values matched (or there this is an empty list), return match + } + else { // ANY from list + for (size_t m = 0; m < sz; m++) { + if (c(left->m_storage[0], right->m_storage[m], left_is_null, right->m_storage.is_null(m))) + return 0; + } + return not_found; // no match + } + return not_found; + } + + template + REALM_FORCEINLINE static size_t compare(Value* left, Value* right, ExpressionComparisonType left_cmp_type, + ExpressionComparisonType right_cmp_type) + { + TCond c; + + if (!left->m_from_link_list && !right->m_from_link_list) { + REALM_ASSERT_DEBUG(left_cmp_type == + ExpressionComparisonType::Any); // ALL/NONE not supported for non list types + REALM_ASSERT_DEBUG(right_cmp_type == + ExpressionComparisonType::Any); // ALL/NONE not supported for non list types + // Compare values one-by-one (one value is one row; no link lists) + size_t min = minimum(left->ValueBase::m_values, right->ValueBase::m_values); + for (size_t m = 0; m < min; m++) { + + if (c(left->m_storage[m], right->m_storage[m], left->m_storage.is_null(m), + right->m_storage.is_null(m))) + return m; + } + } + else if (left->m_from_link_list && right->m_from_link_list) { + // FIXME: Many-to-many links not supported yet. Need to specify behaviour + // knowing the comparison types means we can potentially support things such as: + // ALL list.int > list.[FIRST].int + // ANY list.int > ALL list2.int + // NONE list.int > ANY list2.int + REALM_ASSERT_DEBUG(false); + } + else if (!left->m_from_link_list && right->m_from_link_list) { + // Right values come from link list. Left must come from single row. Semantics: Match if at least 1 + // linked-to-value fulfills the condition + REALM_ASSERT_DEBUG(left->m_values > 0); + const size_t num_right_values = right->m_values; + if (right_cmp_type == ExpressionComparisonType::Any) { + for (size_t r = 0; r < num_right_values; r++) { + if (c(left->m_storage[0], right->m_storage[r], left->m_storage.is_null(0), + right->m_storage.is_null(r))) + return 0; + } + } + else if (right_cmp_type == ExpressionComparisonType::All) { + for (size_t r = 0; r < num_right_values; r++) { + if (!c(left->m_storage[0], right->m_storage[r], left->m_storage.is_null(0), + right->m_storage.is_null(r))) + return not_found; // one didn't match + } + return 0; // all matched + } + else if (right_cmp_type == ExpressionComparisonType::None) { + for (size_t r = 0; r < num_right_values; r++) { + if (c(left->m_storage[0], right->m_storage[r], left->m_storage.is_null(0), + right->m_storage.is_null(r))) + return not_found; // one matched, none not satisfied + } + return 0; // none matched + } + } + else if (left->m_from_link_list && !right->m_from_link_list) { + // Same as above, but with left values coming from link list. + REALM_ASSERT_DEBUG(right->m_values > 0); + const size_t num_left_values = left->m_values; + if (left_cmp_type == ExpressionComparisonType::Any) { + for (size_t l = 0; l < num_left_values; l++) { + if (c(left->m_storage[l], right->m_storage[0], left->m_storage.is_null(l), + right->m_storage.is_null(0))) + return 0; + } + } + else if (left_cmp_type == ExpressionComparisonType::All) { + for (size_t l = 0; l < num_left_values; l++) { + if (!c(left->m_storage[l], right->m_storage[0], left->m_storage.is_null(l), + right->m_storage.is_null(0))) + return not_found; // one did not match, All not satisfied + } + return 0; // all matched + } + else if (left_cmp_type == ExpressionComparisonType::None) { + for (size_t l = 0; l < num_left_values; l++) { + if (c(left->m_storage[l], right->m_storage[0], left->m_storage.is_null(l), + right->m_storage.is_null(0))) + return not_found; // one matched, none not satisfied + } + return 0; // none matched + } + } + + return not_found; // no match + } + + std::unique_ptr clone() const override + { + return make_subexpr>(*this); + } + + NullableVector m_storage; +}; + +class ConstantStringValue : public Value { +public: + ConstantStringValue(const StringData& string) + : Value() + , m_string(string.is_null() ? util::none : util::make_optional(std::string(string))) + { + init(false, 1, m_string); + } + + std::unique_ptr clone() const override + { + return std::unique_ptr(new ConstantStringValue(*this)); + } + +private: + ConstantStringValue(const ConstantStringValue& other) + : Value() + , m_string(other.m_string) + { + init(other.m_from_link_list, other.m_values, m_string); + } + + util::Optional m_string; +}; + +// All overloads where left-hand-side is L: +// +// left-hand-side operator right-hand-side +// L +, -, *, /, <, >, ==, !=, <=, >= Subexpr2 +// +// For L = R = {int, int64_t, float, double, Timestamp, ObjectId, Decimal128}: +// Compare numeric values +template +Query operator>(double left, const Subexpr2& right) +{ + return create(left, right); +} +template +Query operator>(float left, const Subexpr2& right) +{ + return create(left, right); +} +template +Query operator>(int left, const Subexpr2& right) +{ + return create(left, right); +} +template +Query operator>(int64_t left, const Subexpr2& right) +{ + return create(left, right); +} +template +Query operator>(Timestamp left, const Subexpr2& right) +{ + return create(left, right); +} +template +Query operator>(ObjectId left, const Subexpr2& right) +{ + return create(left, right); +} +template +Query operator>(Decimal128 left, const Subexpr2& right) +{ + return create(left, right); +} + +template +Query operator<(double left, const Subexpr2& right) +{ + return create(left, right); +} +template +Query operator<(float left, const Subexpr2& right) +{ + return create(left, right); +} +template +Query operator<(int left, const Subexpr2& right) +{ + return create(left, right); +} +template +Query operator<(int64_t left, const Subexpr2& right) +{ + return create(left, right); +} +template +Query operator<(Timestamp left, const Subexpr2& right) +{ + return create(left, right); +} +template +Query operator<(ObjectId left, const Subexpr2& right) +{ + return create(left, right); +} +template +Query operator<(Decimal128 left, const Subexpr2& right) +{ + return create(left, right); +} + +template +Query operator==(double left, const Subexpr2& right) +{ + return create(left, right); +} +template +Query operator==(float left, const Subexpr2& right) +{ + return create(left, right); +} +template +Query operator==(int left, const Subexpr2& right) +{ + return create(left, right); +} +template +Query operator==(int64_t left, const Subexpr2& right) +{ + return create(left, right); +} +template +Query operator==(Timestamp left, const Subexpr2& right) +{ + return create(left, right); +} +template +Query operator==(ObjectId left, const Subexpr2& right) +{ + return create(left, right); +} +template +Query operator==(Decimal128 left, const Subexpr2& right) +{ + return create(left, right); +} +template +Query operator==(bool left, const Subexpr2& right) +{ + return create(left, right); +} + +template +Query operator>=(double left, const Subexpr2& right) +{ + return create(left, right); +} +template +Query operator>=(float left, const Subexpr2& right) +{ + return create(left, right); +} +template +Query operator>=(int left, const Subexpr2& right) +{ + return create(left, right); +} +template +Query operator>=(int64_t left, const Subexpr2& right) +{ + return create(left, right); +} +template +Query operator>=(Timestamp left, const Subexpr2& right) +{ + return create(left, right); +} +template +Query operator>=(ObjectId left, const Subexpr2& right) +{ + return create(left, right); +} +template +Query operator>=(Decimal128 left, const Subexpr2& right) +{ + return create(left, right); +} + +template +Query operator<=(double left, const Subexpr2& right) +{ + return create(left, right); +} +template +Query operator<=(float left, const Subexpr2& right) +{ + return create(left, right); +} +template +Query operator<=(int left, const Subexpr2& right) +{ + return create(left, right); +} +template +Query operator<=(int64_t left, const Subexpr2& right) +{ + return create(left, right); +} +template +Query operator<=(Timestamp left, const Subexpr2& right) +{ + return create(left, right); +} +template +Query operator<=(ObjectId left, const Subexpr2& right) +{ + return create(left, right); +} +template +Query operator<=(Decimal128 left, const Subexpr2& right) +{ + return create(left, right); +} + +template +Query operator!=(double left, const Subexpr2& right) +{ + return create(left, right); +} +template +Query operator!=(float left, const Subexpr2& right) +{ + return create(left, right); +} +template +Query operator!=(int left, const Subexpr2& right) +{ + return create(left, right); +} +template +Query operator!=(int64_t left, const Subexpr2& right) +{ + return create(left, right); +} +template +Query operator!=(Timestamp left, const Subexpr2& right) +{ + return create(left, right); +} +template +Query operator!=(ObjectId left, const Subexpr2& right) +{ + return create(left, right); +} +template +Query operator!=(Decimal128 left, const Subexpr2& right) +{ + return create(left, right); +} +template +Query operator!=(bool left, const Subexpr2& right) +{ + return create(left, right); +} + +// Arithmetic +template +Operator::type>> operator+(double left, const Subexpr2& right) +{ + return {make_subexpr>(left), right.clone()}; +} +template +Operator::type>> operator+(float left, const Subexpr2& right) +{ + return {make_subexpr>(left), right.clone()}; +} +template +Operator::type>> operator+(int left, const Subexpr2& right) +{ + return {make_subexpr>(left), right.clone()}; +} +template +Operator::type>> operator+(int64_t left, const Subexpr2& right) +{ + return {make_subexpr>(left), right.clone()}; +} +template +Operator::type>> operator-(double left, const Subexpr2& right) +{ + return {make_subexpr>(left), right.clone()}; +} +template +Operator::type>> operator-(float left, const Subexpr2& right) +{ + return {make_subexpr>(left), right.clone()}; +} +template +Operator::type>> operator-(int left, const Subexpr2& right) +{ + return {make_subexpr>(left), right.clone()}; +} +template +Operator::type>> operator-(int64_t left, const Subexpr2& right) +{ + return {make_subexpr>(left), right.clone()}; +} +template +Operator::type>> operator*(double left, const Subexpr2& right) +{ + return {make_subexpr>(left), right.clone()}; +} +template +Operator::type>> operator*(float left, const Subexpr2& right) +{ + return {make_subexpr>(left), right.clone()}; +} +template +Operator::type>> operator*(int left, const Subexpr2& right) +{ + return {make_subexpr>(left), right.clone()}; +} +template +Operator::type>> operator*(int64_t left, const Subexpr2& right) +{ + return {make_subexpr>(left), right.clone()}; +} +template +Operator::type>> operator/(double left, const Subexpr2& right) +{ + return {make_subexpr>(left), right.clone()}; +} +template +Operator::type>> operator/(float left, const Subexpr2& right) +{ + return {make_subexpr>(left), right.clone()}; +} +template +Operator::type>> operator/(int left, const Subexpr2& right) +{ + return {make_subexpr>(left), right.clone()}; +} +template +Operator::type>> operator/(int64_t left, const Subexpr2& right) +{ + return {make_subexpr>(left), right.clone()}; +} + +// Unary operators +template +UnaryOperator> power(const Subexpr2& left) +{ + return {left.clone()}; +} + +// Classes used for LinkMap (see below). +struct LinkMapFunction { + // Your consume() method is given key within the linked-to table as argument, and you must return whether or + // not you want the LinkMapFunction to exit (return false) or continue (return true) harvesting the link tree + // for the current main table object (it will be a link tree if you have multiple type_LinkList columns + // in a link()->link() query. + virtual bool consume(ObjKey) = 0; +}; + +struct FindNullLinks : public LinkMapFunction { + bool consume(ObjKey) override + { + m_has_link = true; + return false; // we've found a key, so this can't be a null-link, so exit link harvesting + } + + bool m_has_link = false; +}; + +struct MakeLinkVector : public LinkMapFunction { + MakeLinkVector(std::vector& result) + : m_links(result) + { + } + + bool consume(ObjKey key) override + { + m_links.push_back(key); + return true; // continue evaluation + } + std::vector& m_links; +}; + +struct UnaryLinkResult : public LinkMapFunction { + bool consume(ObjKey key) override + { + m_result = key; + return false; // exit search, only one result ever expected + } + ObjKey m_result; +}; + +struct CountLinks : public LinkMapFunction { + bool consume(ObjKey) override + { + m_link_count++; + return true; + } + + size_t result() const + { + return m_link_count; + } + + size_t m_link_count = 0; +}; + +struct CountBacklinks : public LinkMapFunction { + CountBacklinks(ConstTableRef t) + : m_table(t) + { + } + + bool consume(ObjKey key) override + { + m_link_count += m_table.unchecked_ptr()->get_object(key).get_backlink_count(); + return true; + } + + size_t result() const + { + return m_link_count; + } + + ConstTableRef m_table; + size_t m_link_count = 0; +}; + + +/* +The LinkMap and LinkMapFunction classes are used for query conditions on links themselves (contrary to conditions on +the value payload they point at). + +MapLink::map_links() takes a row index of the link array as argument and follows any link chain stated in the query +(through the link()->link() methods) until the final payload table is reached, and then applies LinkMapFunction on +the linked-to key(s). + +If all link columns are type_Link, then LinkMapFunction is only invoked for a single key. If one or more +columns are type_LinkList, then it may result in multiple keys. + +The reason we use this map pattern is that we can exit the link-tree-traversal as early as possible, e.g. when we've +found the first link that points to key '5'. Other solutions could be a std::vector harvest_all_links(), or an +iterator pattern. First solution can't exit, second solution requires internal state. +*/ +class LinkMap { +public: + LinkMap() = default; + LinkMap(ConstTableRef table, std::vector columns) + : m_link_column_keys(std::move(columns)) + { + set_base_table(table); + } + + LinkMap(LinkMap const& other) + { + m_link_column_keys = other.m_link_column_keys; + m_tables = other.m_tables; + m_link_types = other.m_link_types; + m_only_unary_links = other.m_only_unary_links; + } + + size_t get_nb_hops() const + { + return m_link_column_keys.size(); + } + + bool has_links() const + { + return m_link_column_keys.size() > 0; + } + + void set_base_table(ConstTableRef table); + + void set_cluster(const Cluster* cluster) + { + Allocator& alloc = get_base_table()->get_alloc(); + m_array_ptr = nullptr; + switch (m_link_types[0]) { + case col_type_Link: + m_array_ptr = LeafPtr(new (&m_storage.m_list) ArrayKey(alloc)); + break; + case col_type_LinkList: + m_array_ptr = LeafPtr(new (&m_storage.m_linklist) ArrayList(alloc)); + break; + case col_type_BackLink: + m_array_ptr = LeafPtr(new (&m_storage.m_backlink) ArrayBacklink(alloc)); + break; + default: + break; + } + // m_tables[0]->report_invalid_key(m_link_column_keys[0]); + cluster->init_leaf(m_link_column_keys[0], m_array_ptr.get()); + m_leaf_ptr = m_array_ptr.get(); + } + + void collect_dependencies(std::vector& tables) const; + + virtual std::string description(util::serializer::SerialisationState& state) const; + + ObjKey get_unary_link_or_not_found(size_t index) const + { + REALM_ASSERT(m_only_unary_links); + UnaryLinkResult res; + map_links(index, res); + return res.m_result; + } + + std::vector get_links(size_t index) const + { + std::vector res; + get_links(index, res); + return res; + } + + std::vector get_origin_ndxs(ObjKey key, size_t column = 0) const; + + size_t count_links(size_t row) const + { + CountLinks counter; + map_links(row, counter); + return counter.result(); + } + + size_t count_all_backlinks(size_t row) const + { + CountBacklinks counter(get_target_table()); + map_links(row, counter); + return counter.result(); + } + + void map_links(size_t row, LinkMapFunction& lm) const + { + map_links(0, row, lm); + } + + bool only_unary_links() const + { + return m_only_unary_links; + } + + ConstTableRef get_base_table() const + { + return m_tables.empty() ? nullptr : m_tables[0]; + } + + ConstTableRef get_target_table() const + { + REALM_ASSERT(!m_tables.empty()); + return m_tables.back(); + } + + bool links_exist() const + { + return !m_link_column_keys.empty(); + } + +private: + void map_links(size_t column, ObjKey key, LinkMapFunction& lm) const; + void map_links(size_t column, size_t row, LinkMapFunction& lm) const; + + void get_links(size_t row, std::vector& result) const + { + MakeLinkVector mlv = MakeLinkVector(result); + map_links(row, mlv); + } + + mutable std::vector m_link_column_keys; + std::vector m_link_types; + std::vector m_tables; + bool m_only_unary_links = true; + // Leaf cache + using LeafPtr = std::unique_ptr; + union Storage { + typename std::aligned_storage::type m_list; + typename std::aligned_storage::type m_linklist; + typename std::aligned_storage::type m_backlink; + }; + Storage m_storage; + LeafPtr m_array_ptr; + const ArrayPayload* m_leaf_ptr = nullptr; + + template + friend Query compare(const Subexpr2&, const ConstObj&); +}; + +template +Query string_compare(const Subexpr2& left, T right, bool case_insensitive); +template +Query string_compare(const Subexpr2& left, const Subexpr2& right, bool case_insensitive); + +template +Value make_value_for_link(bool only_unary_links, size_t size) +{ + Value value; + if (only_unary_links) { + REALM_ASSERT(size <= 1); + value.init(false, 1); + value.m_storage.set_null(0); + } + else { + value.init(true, size); + } + return value; +} + + +// If we add a new Realm type T and quickly want Query support for it, then simply inherit from it like +// `template <> class Columns : public SimpleQuerySupport` and you're done. Any operators of the set +// { ==, >=, <=, !=, >, < } that are supported by T will be supported by the "query expression syntax" +// automatically. NOTE: This method of Query support will be slow because it goes through Table::get. +// To get faster Query support, either add SequentialGetter support (faster) or create a query_engine.hpp +// node for it (super fast). + +template +class SimpleQuerySupport : public Subexpr2 { +public: + SimpleQuerySupport(ColKey column, ConstTableRef table, std::vector links = {}, + ExpressionComparisonType type = ExpressionComparisonType::Any) + : m_link_map(table, std::move(links)) + , m_column_key(column) + , m_comparison_type(type) + { + } + + bool is_nullable() const noexcept + { + return m_column_key.get_attrs().test(col_attr_Nullable); + } + + ConstTableRef get_base_table() const override + { + return m_link_map.get_base_table(); + } + + void set_base_table(ConstTableRef table) override + { + if (table != get_base_table()) { + m_link_map.set_base_table(table); + } + } + + void set_cluster(const Cluster* cluster) override + { + m_array_ptr = nullptr; + m_leaf_ptr = nullptr; + if (links_exist()) { + m_link_map.set_cluster(cluster); + } + else { + // Create new Leaf + m_array_ptr = LeafPtr(new (&m_leaf_cache_storage) LeafType(m_link_map.get_base_table()->get_alloc())); + cluster->init_leaf(m_column_key, m_array_ptr.get()); + m_leaf_ptr = m_array_ptr.get(); + } + } + + bool has_search_index() const override + { + auto target_table = m_link_map.get_target_table(); + return target_table->get_primary_key_column() == m_column_key || target_table->has_search_index(m_column_key); + } + + std::vector find_all(Mixed value) const override + { + std::vector ret; + std::vector result; + + if (value.is_null() && !m_column_key.is_nullable()) { + return ret; + } + + if (m_link_map.get_target_table()->get_primary_key_column() == m_column_key) { + // Only one object with a given key would be possible + if (auto k = m_link_map.get_target_table()->find_primary_key(value)) + result.push_back(k); + } + else { + StringIndex* index = m_link_map.get_target_table()->get_search_index(m_column_key); + REALM_ASSERT(index); + if (value.is_null()) { + index->find_all(result, realm::null{}); + } + else { + T val = value.get(); + index->find_all(result, val); + } + } + + for (ObjKey k : result) { + auto ndxs = m_link_map.get_origin_ndxs(k); + ret.insert(ret.end(), ndxs.begin(), ndxs.end()); + } + + return ret; + } + + void collect_dependencies(std::vector& tables) const override + { + m_link_map.collect_dependencies(tables); + } + + void evaluate(size_t index, ValueBase& destination) override + { + if (links_exist()) { + REALM_ASSERT(m_leaf_ptr == nullptr); + + if (m_link_map.only_unary_links()) { + Value d; + d.init(false, 1); + d.m_storage.set_null(0); + auto link_translation_key = this->m_link_map.get_unary_link_or_not_found(index); + if (link_translation_key) { + ConstObj obj = m_link_map.get_target_table()->get_object(link_translation_key); + if constexpr (std::is_same_v) { + auto opt_val = obj.get>(m_column_key); + if (opt_val) { + d.m_storage.set(0, *opt_val); + } + else { + d.m_storage.set_null(0); + } + } + else { + d.m_storage.set(0, obj.get(m_column_key)); + } + } + destination.import(d); + } + else { + std::vector links = m_link_map.get_links(index); + Value v = make_value_for_link(false /*only_unary_links*/, links.size()); + for (size_t t = 0; t < links.size(); t++) { + ConstObj obj = m_link_map.get_target_table()->get_object(links[t]); + if constexpr (std::is_same_v) { + auto opt_val = obj.get>(m_column_key); + if (opt_val) { + v.m_storage.set(t, *opt_val); + } + else { + v.m_storage.set_null(t); + } + } + else { + v.m_storage.set(t, obj.get(m_column_key)); + } + } + destination.import(v); + } + } + else { + REALM_ASSERT(m_leaf_ptr != nullptr); + Value d(false /*not from link list*/, destination.m_values); + // Not a link column + for (size_t t = 0; t < destination.m_values && index + t < m_leaf_ptr->size(); t++) { + if (m_leaf_ptr->is_null(index + t)) { + d.m_storage.set_null(t); + } + else { + d.m_storage.set(t, T(m_leaf_ptr->get(index + t))); + } + } + destination.import(d); + } + } + + void evaluate(ObjKey key, ValueBase& destination) override + { + Value& d = static_cast&>(destination); + d.m_storage.set(0, m_link_map.get_target_table()->get_object(key).template get(m_column_key)); + } + + bool links_exist() const + { + return m_link_map.has_links(); + } + + bool only_unary_links() const + { + return m_link_map.only_unary_links(); + } + + LinkMap get_link_map() const + { + return m_link_map; + } + + virtual std::string description(util::serializer::SerialisationState& state) const override + { + return state.describe_expression_type(m_comparison_type) + state.describe_columns(m_link_map, m_column_key); + } + + virtual ExpressionComparisonType get_comparison_type() const override + { + return m_comparison_type; + } + + std::unique_ptr clone() const override + { + return make_subexpr>(static_cast&>(*this)); + } + + SimpleQuerySupport(SimpleQuerySupport const& other) + : Subexpr2(other) + , m_link_map(other.m_link_map) + , m_column_key(other.m_column_key) + , m_comparison_type(other.m_comparison_type) + { + } + + ColKey column_key() const + { + return m_column_key; + } + + SizeOperator size() + { + return SizeOperator(this->clone()); + } + +private: + LinkMap m_link_map; + + // Column key of payload column of m_table + mutable ColKey m_column_key; + + // Leaf cache + using LeafType = typename ColumnTypeTraits::cluster_leaf_type; + using LeafCacheStorage = typename std::aligned_storage::type; + using LeafPtr = std::unique_ptr; + LeafCacheStorage m_leaf_cache_storage; + LeafPtr m_array_ptr; + LeafType* m_leaf_ptr = nullptr; + ExpressionComparisonType m_comparison_type; +}; + + +template <> +class Columns : public SimpleQuerySupport { + using SimpleQuerySupport::SimpleQuerySupport; +}; + +template <> +class Columns : public SimpleQuerySupport { + using SimpleQuerySupport::SimpleQuerySupport; +}; + +template <> +class Columns : public SimpleQuerySupport { + using SimpleQuerySupport::SimpleQuerySupport; +}; + +template <> +class Columns : public SimpleQuerySupport { + using SimpleQuerySupport::SimpleQuerySupport; +}; + +template <> +class Columns : public SimpleQuerySupport { +public: + Columns(ColKey column, ConstTableRef table, std::vector links = {}, + ExpressionComparisonType type = ExpressionComparisonType::Any) + : SimpleQuerySupport(column, table, links, type) + { + } + + Columns(Columns const& other) + : SimpleQuerySupport(other) + { + } + + Columns(Columns&& other) noexcept + : SimpleQuerySupport(other) + { + } + using SimpleQuerySupport::size; +}; + +template +Query string_compare(const Subexpr2& left, T right, bool case_sensitive) +{ + StringData sd(right); + if (case_sensitive) + return create(sd, left); + else + return create(sd, left); +} + +template +Query string_compare(const Subexpr2& left, const Subexpr2& right, bool case_sensitive) +{ + if (case_sensitive) + return make_expression>(right.clone(), left.clone()); + else + return make_expression>(right.clone(), left.clone()); +} + +template +Query binary_compare(const Subexpr2& left, T right, bool case_sensitive) +{ + BinaryData data(right); + if (case_sensitive) + return create(data, left); + else + return create(data, left); +} + +template +Query binary_compare(const Subexpr2& left, const Subexpr2& right, bool case_sensitive) +{ + if (case_sensitive) + return make_expression>(right.clone(), left.clone()); + else + return make_expression>(right.clone(), left.clone()); +} + + +// Columns == Columns +inline Query operator==(const Columns& left, const Columns& right) +{ + return string_compare(left, right, true); +} + +// Columns != Columns +inline Query operator!=(const Columns& left, const Columns& right) +{ + return string_compare(left, right, true); +} + +// String == Columns +template +Query operator==(T left, const Columns& right) +{ + return operator==(right, left); +} + +// String != Columns +template +Query operator!=(T left, const Columns& right) +{ + return operator!=(right, left); +} + +// Columns == String +template +Query operator==(const Columns& left, T right) +{ + return string_compare(left, right, true); +} + +// Columns != String +template +Query operator!=(const Columns& left, T right) +{ + return string_compare(left, right, true); +} + + +inline Query operator==(const Columns& left, BinaryData right) +{ + return create(right, left); +} + +inline Query operator==(BinaryData left, const Columns& right) +{ + return create(left, right); +} + +inline Query operator!=(const Columns& left, BinaryData right) +{ + return create(right, left); +} + +inline Query operator!=(BinaryData left, const Columns& right) +{ + return create(left, right); +} + +inline Query operator==(const Columns& left, realm::null) +{ + return create(BinaryData(), left); +} + +inline Query operator==(realm::null, const Columns& right) +{ + return create(BinaryData(), right); +} + +inline Query operator!=(const Columns& left, realm::null) +{ + return create(BinaryData(), left); +} + +inline Query operator!=(realm::null, const Columns& right) +{ + return create(BinaryData(), right); +} + + +// This class is intended to perform queries on the *pointers* of links, contrary to performing queries on *payload* +// in linked-to tables. Queries can be "find first link that points at row X" or "find first null-link". Currently +// only "find first null link" and "find first non-null link" is supported. More will be added later. When we add +// more, I propose to remove the template argument from this class and instead template it by +// a criteria-class (like the FindNullLinks class below in find_first()) in some generalized fashion. +template +class UnaryLinkCompare : public Expression { +public: + UnaryLinkCompare(const LinkMap& lm) + : m_link_map(lm) + { + } + + void set_base_table(ConstTableRef table) override + { + m_link_map.set_base_table(table); + } + + void set_cluster(const Cluster* cluster) override + { + m_link_map.set_cluster(cluster); + } + + void collect_dependencies(std::vector& tables) const override + { + m_link_map.collect_dependencies(tables); + } + + // Return main table of query (table on which table->where()... is invoked). Note that this is not the same as + // any linked-to payload tables + ConstTableRef get_base_table() const override + { + return m_link_map.get_base_table(); + } + + size_t find_first(size_t start, size_t end) const override + { + for (; start < end;) { + FindNullLinks fnl; + m_link_map.map_links(start, fnl); + if (fnl.m_has_link == has_links) + return start; + + start++; + } + + return not_found; + } + + virtual std::string description(util::serializer::SerialisationState& state) const override + { + return state.describe_columns(m_link_map, ColKey()) + (has_links ? " != NULL" : " == NULL"); + } + + std::unique_ptr clone() const override + { + return std::unique_ptr(new UnaryLinkCompare(*this)); + } + +private: + UnaryLinkCompare(const UnaryLinkCompare& other) + : Expression(other) + , m_link_map(other.m_link_map) + { + } + + mutable LinkMap m_link_map; +}; + +class LinkCount : public Subexpr2 { +public: + LinkCount(const LinkMap& link_map) + : m_link_map(link_map) + { + } + LinkCount(LinkCount const& other) + : Subexpr2(other) + , m_link_map(other.m_link_map) + { + } + + std::unique_ptr clone() const override + { + return make_subexpr(*this); + } + + ConstTableRef get_base_table() const override + { + return m_link_map.get_base_table(); + } + + void set_base_table(ConstTableRef table) override + { + m_link_map.set_base_table(table); + } + + void set_cluster(const Cluster* cluster) override + { + m_link_map.set_cluster(cluster); + } + + void collect_dependencies(std::vector& tables) const override + { + m_link_map.collect_dependencies(tables); + } + + void evaluate(size_t index, ValueBase& destination) override + { + size_t count = m_link_map.count_links(index); + destination.import(Value(false, 1, count)); + } + + virtual std::string description(util::serializer::SerialisationState& state) const override + { + return state.describe_columns(m_link_map, ColKey()) + util::serializer::value_separator + "@count"; + } + +private: + LinkMap m_link_map; +}; + +// Gives a count of all backlinks across all columns for the specified row. +// The unused template parameter is a hack to avoid a circular dependency between table.hpp and query_expression.hpp. +template +class BacklinkCount : public Subexpr2 { +public: + BacklinkCount(const LinkMap& link_map) + : m_link_map(link_map) + { + } + BacklinkCount(LinkMap&& link_map) + : m_link_map(std::move(link_map)) + { + } + BacklinkCount(ConstTableRef table, std::vector links = {}) + : m_link_map(table, std::move(links)) + { + } + BacklinkCount(BacklinkCount const& other) + : Subexpr2(other) + , m_link_map(other.m_link_map) + { + } + + std::unique_ptr clone() const override + { + return make_subexpr>(*this); + } + + ConstTableRef get_base_table() const override + { + return m_link_map.get_base_table(); + } + + void set_base_table(ConstTableRef table) override + { + m_link_map.set_base_table(table); + } + + void set_cluster(const Cluster* cluster) override + { + if (m_link_map.has_links()) { + m_link_map.set_cluster(cluster); + } + else { + m_keys = cluster->get_key_array(); + m_offset = cluster->get_offset(); + } + } + + void collect_dependencies(std::vector& tables) const override + { + m_link_map.collect_dependencies(tables); + } + + void evaluate(size_t index, ValueBase& destination) override + { + size_t count; + if (m_link_map.has_links()) { + count = m_link_map.count_all_backlinks(index); + } + else { + ObjKey key(m_keys->get(index) + m_offset); + ConstObj obj = m_link_map.get_base_table()->get_object(key); + count = obj.get_backlink_count(); + } + destination.import(Value(false, 1, count)); + } + + virtual std::string description(util::serializer::SerialisationState& state) const override + { + std::string s; + if (m_link_map.links_exist()) { + s += state.describe_columns(m_link_map, ColKey()) + util::serializer::value_separator; + } + s += "@links.@count"; + return s; + } + +private: + const ClusterKeyArray* m_keys = nullptr; + uint64_t m_offset = 0; + LinkMap m_link_map; +}; + +template +class SizeOperator : public Subexpr2 { +public: + SizeOperator(std::unique_ptr left) + : m_expr(std::move(left)) + { + } + + SizeOperator(const SizeOperator& other) + : m_expr(other.m_expr->clone()) + { + } + + // See comment in base class + void set_base_table(ConstTableRef table) override + { + m_expr->set_base_table(table); + } + + void set_cluster(const Cluster* cluster) override + { + m_expr->set_cluster(cluster); + } + + // Recursively fetch tables of columns in expression tree. Used when user first builds a stand-alone expression + // and binds it to a Query at a later time + ConstTableRef get_base_table() const override + { + return m_expr->get_base_table(); + } + + // destination = operator(left) + void evaluate(size_t index, ValueBase& destination) override + { + REALM_ASSERT_DEBUG(dynamic_cast*>(&destination) != nullptr); + Value* d = static_cast*>(&destination); + REALM_ASSERT(d); + + Value v; + m_expr->evaluate(index, v); + + size_t sz = v.m_values; + d->init(v.m_from_link_list, sz); + + for (size_t i = 0; i < sz; i++) { + auto elem = v.m_storage.get(i); + if (!elem) { + d->m_storage.set_null(i); + } + else { + d->m_storage.set(i, elem->size()); + } + } + } + + std::string description(util::serializer::SerialisationState& state) const override + { + if (m_expr) { + return m_expr->description(state) + util::serializer::value_separator + "@size"; + } + return "@size"; + } + + std::unique_ptr clone() const override + { + return std::unique_ptr(new SizeOperator(*this)); + } + +private: + std::unique_ptr m_expr; +}; + +class KeyValue : public Subexpr2 { +public: + KeyValue(ObjKey key) + : m_key(key) + { + } + + void set_base_table(ConstTableRef) override {} + + ConstTableRef get_base_table() const override + { + return nullptr; + } + + void evaluate(size_t, ValueBase& destination) override + { + // Destination must be of Key type. It only makes sense to + // compare keys with keys + REALM_ASSERT_DEBUG(dynamic_cast*>(&destination)); + auto d = static_cast*>(&destination); + d->init(false, 1, m_key); + } + + virtual std::string description(util::serializer::SerialisationState&) const override + { + return util::serializer::print_value(m_key); + } + + std::unique_ptr clone() const override + { + return std::unique_ptr(new KeyValue(*this)); + } + +private: + KeyValue(const KeyValue& source) + : m_key(source.m_key) + { + } + + ObjKey m_key; +}; + +template +class SubColumns; + +// This is for LinkList and BackLink too since they're declared as typedefs of Link. +template <> +class Columns : public Subexpr2 { +public: + Columns(const Columns& other) + : Subexpr2(other) + , m_link_map(other.m_link_map) + , m_comparison_type(other.m_comparison_type) + { + } + + Query is_null() + { + if (m_link_map.get_nb_hops() > 1) + throw util::runtime_error("Combining link() and is_null() is currently not supported"); + // Todo, it may be useful to support the above, but we would need to figure out an intuitive behaviour + return make_expression>(m_link_map); + } + + Query is_not_null() + { + if (m_link_map.get_nb_hops() > 1) + throw util::runtime_error("Combining link() and is_not_null() is currently not supported"); + // Todo, it may be useful to support the above, but we would need to figure out an intuitive behaviour + return make_expression>(m_link_map); + } + + LinkCount count() const + { + return LinkCount(m_link_map); + } + + template + BacklinkCount backlink_count() const + { + return BacklinkCount(m_link_map); + } + + template + SubColumns column(ColKey column_key) const + { + // no need to pass along m_comparison_type because the only operations supported from + // the subsequent SubColumns are aggregate operations such as sum, min, max, avg where + // having + REALM_ASSERT_DEBUG(m_comparison_type == ExpressionComparisonType::Any); + return SubColumns(Columns(column_key, m_link_map.get_target_table()), m_link_map); + } + + const LinkMap& link_map() const + { + return m_link_map; + } + + ConstTableRef get_base_table() const override + { + return m_link_map.get_base_table(); + } + + void set_base_table(ConstTableRef table) override + { + m_link_map.set_base_table(table); + } + + void set_cluster(const Cluster* cluster) override + { + REALM_ASSERT(m_link_map.has_links()); + m_link_map.set_cluster(cluster); + } + + void collect_dependencies(std::vector& tables) const override + { + m_link_map.collect_dependencies(tables); + } + + std::string description(util::serializer::SerialisationState& state) const override + { + return state.describe_expression_type(m_comparison_type) + state.describe_columns(m_link_map, ColKey()); + } + + virtual ExpressionComparisonType get_comparison_type() const override + { + return m_comparison_type; + } + + std::unique_ptr clone() const override + { + return std::unique_ptr(new Columns(*this)); + } + + void evaluate(size_t index, ValueBase& destination) override; + +private: + LinkMap m_link_map; + ExpressionComparisonType m_comparison_type; + friend class Table; + friend class LinkChain; + + Columns(ColKey column_key, ConstTableRef table, const std::vector& links = {}, + ExpressionComparisonType type = ExpressionComparisonType::Any) + : m_link_map(table, links) + , m_comparison_type(type) + { + static_cast(column_key); + } +}; + +template +class ListColumns; +template +class ListColumnAggregate; +namespace aggregate_operations { +template +class Minimum; +template +class Maximum; +template +class Sum; +template +class Average; +} + +class ColumnListBase { +public: + ColumnListBase(ColKey column_key, ConstTableRef table, const std::vector& links, + ExpressionComparisonType type = ExpressionComparisonType::Any) + : m_column_key(column_key) + , m_link_map(table, links) + , m_comparison_type(type) + { + } + + ColumnListBase(const ColumnListBase& other) + : m_column_key(other.m_column_key) + , m_link_map(other.m_link_map) + , m_comparison_type(other.m_comparison_type) + { + } + + void set_cluster(const Cluster* cluster); + + void get_lists(size_t index, Value& destination, size_t nb_elements); + + std::string description(util::serializer::SerialisationState& state) const + { + return state.describe_expression_type(m_comparison_type) + state.describe_columns(m_link_map, m_column_key); + } + + bool links_exist() const + { + return m_link_map.has_links(); + } + + mutable ColKey m_column_key; + LinkMap m_link_map; + // Leaf cache + using LeafCacheStorage = typename std::aligned_storage::type; + using LeafPtr = std::unique_ptr; + LeafCacheStorage m_leaf_cache_storage; + LeafPtr m_array_ptr; + ArrayList* m_leaf_ptr = nullptr; + ExpressionComparisonType m_comparison_type = ExpressionComparisonType::Any; +}; + +template +class ColumnListSize; + +template +class ColumnListElementLength; + +template +class Columns> : public Subexpr2, public ColumnListBase { +public: + Columns(const Columns>& other) + : Subexpr2(other) + , ColumnListBase(other) + , m_is_nullable_storage(this->m_column_key.get_attrs().test(col_attr_Nullable)) + { + } + + std::unique_ptr clone() const override + { + return make_subexpr>>(*this); + } + + ConstTableRef get_base_table() const override + { + return m_link_map.get_base_table(); + } + + void set_base_table(ConstTableRef table) override + { + m_link_map.set_base_table(table); + } + + void set_cluster(const Cluster* cluster) override + { + ColumnListBase::set_cluster(cluster); + } + + void collect_dependencies(std::vector& tables) const override + { + m_link_map.collect_dependencies(tables); + } + + void evaluate(size_t index, ValueBase& destination) override + { + if constexpr (std::is_same_v || std::is_same_v || std::is_same_v) { + if (m_is_nullable_storage) { + evaluate>(index, destination); + return; + } + } + evaluate(index, destination); + } + + virtual std::string description(util::serializer::SerialisationState& state) const override + { + return ColumnListBase::description(state); + } + + virtual ExpressionComparisonType get_comparison_type() const override + { + return ColumnListBase::m_comparison_type; + } + + SizeOperator size(); + + ColumnListElementLength element_lengths() const + { + return {*this}; + } + + ListColumnAggregate> min() const + { + return {m_column_key, *this}; + } + + ListColumnAggregate> max() const + { + return {m_column_key, *this}; + } + + ListColumnAggregate> sum() const + { + return {m_column_key, *this}; + } + + ListColumnAggregate> average() const + { + return {m_column_key, *this}; + } + const bool m_is_nullable_storage; + +private: + friend class Table; + friend class LinkChain; + + template + void evaluate(size_t index, ValueBase& destination) + { + Allocator& alloc = get_base_table()->get_alloc(); + Value list_refs; + get_lists(index, list_refs, 1); + const bool is_from_list = true; + + std::vector values; + for (size_t i = 0; i < list_refs.m_values; i++) { + ref_type list_ref = list_refs.m_storage[i]; + if (list_ref) { + BPlusTree list(alloc); + list.init_from_ref(list_ref); + size_t s = list.size(); + for (size_t j = 0; j < s; j++) { + values.push_back(list.get(j)); + } + } + } + Value v; + v.init(is_from_list, values); + destination.import(v); + } + + Columns(ColKey column_key, ConstTableRef table, const std::vector& links = {}, + ExpressionComparisonType type = ExpressionComparisonType::Any) + : ColumnListBase(column_key, table, links, type) + , m_is_nullable_storage(this->m_column_key.get_attrs().test(col_attr_Nullable)) + { + } +}; + +template +class ColumnListSize : public Columns> { +public: + ColumnListSize(const Columns>& other) + : Columns>(other) + { + } + void evaluate(size_t index, ValueBase& destination) override + { + if constexpr (std::is_same_v || std::is_same_v || std::is_same_v) { + if (this->m_is_nullable_storage) { + evaluate>(index, destination); + return; + } + } + evaluate(index, destination); + } + + std::unique_ptr clone() const override + { + return std::unique_ptr(new ColumnListSize(*this)); + } + +private: + template + void evaluate(size_t index, ValueBase& destination) + { + REALM_ASSERT_DEBUG(dynamic_cast*>(&destination) != nullptr); + Value* d = static_cast*>(&destination); + + Allocator& alloc = this->get_base_table()->get_alloc(); + Value list_refs; + this->get_lists(index, list_refs, 1); + d->init(list_refs.m_from_link_list, list_refs.m_values); + for (size_t i = 0; i < list_refs.m_values; i++) { + ref_type list_ref = list_refs.m_storage[i]; + if (list_ref) { + BPlusTree list(alloc); + list.init_from_ref(list_ref); + size_t s = list.size(); + d->m_storage.set(i, SizeOfList(s)); + } + else { + d->m_storage.set(i, SizeOfList(0)); + } + } + } +}; + + +template +class ColumnListElementLength : public Subexpr2 { +public: + ColumnListElementLength(const Columns>& source) + : m_list(source) + { + } + void evaluate(size_t index, ValueBase& destination) override + { + Allocator& alloc = m_list.get_base_table()->get_alloc(); + Value list_refs; + m_list.get_lists(index, list_refs, 1); + std::vector sizes; + for (size_t i = 0; i < list_refs.m_values; i++) { + ref_type list_ref = list_refs.m_storage[i]; + if (list_ref) { + BPlusTree list(alloc); + list.init_from_ref(list_ref); + const size_t list_size = list.size(); + sizes.reserve(sizes.size() + list_size); + for (size_t j = 0; j < list_size; j++) { + sizes.push_back(list.get(j).size()); + } + } + } + constexpr bool is_from_list = true; + Value values; + values.init(is_from_list, sizes); + destination.import(values); + } + ConstTableRef get_base_table() const override + { + return m_list.get_base_table(); + } + + void set_base_table(ConstTableRef table) override + { + m_list.set_base_table(table); + } + + void set_cluster(const Cluster* cluster) override + { + m_list.set_cluster(cluster); + } + + void collect_dependencies(std::vector& tables) const override + { + m_list.collect_dependencies(tables); + } + + std::unique_ptr clone() const override + { + return std::unique_ptr(new ColumnListElementLength(*this)); + } + + std::string description(util::serializer::SerialisationState& state) const override + { + return m_list.description(state) + util::serializer::value_separator + "length"; + } + + virtual ExpressionComparisonType get_comparison_type() const override + { + return m_list.get_comparison_type(); + } + +private: + Columns> m_list; +}; + + +template +SizeOperator Columns>::size() +{ + std::unique_ptr ptr(new ColumnListSize(*this)); + return SizeOperator(std::move(ptr)); +} + +template +class ListColumnAggregate : public Subexpr2 { +public: + using R = typename Operation::ResultType; + + ListColumnAggregate(ColKey column_key, Columns> column) + : m_column_key(column_key) + , m_list(std::move(column)) + { + } + + ListColumnAggregate(const ListColumnAggregate& other) + : m_column_key(other.m_column_key) + , m_list(other.m_list) + { + } + + std::unique_ptr clone() const override + { + return make_subexpr(*this); + } + + ConstTableRef get_base_table() const override + { + return m_list.get_base_table(); + } + + void set_base_table(ConstTableRef table) override + { + m_list.set_base_table(table); + } + + void set_cluster(const Cluster* cluster) override + { + m_list.set_cluster(cluster); + } + + void collect_dependencies(std::vector& tables) const override + { + m_list.collect_dependencies(tables); + } + + void evaluate(size_t index, ValueBase& destination) override + { + if constexpr (std::is_same_v || std::is_same_v || std::is_same_v) { + if (m_list.m_is_nullable_storage) { + evaluate>(index, destination); + return; + } + } + evaluate(index, destination); + } + + virtual std::string description(util::serializer::SerialisationState& state) const override + { + return m_list.description(state) + util::serializer::value_separator + Operation::description(); + } + +private: + template + void evaluate(size_t index, ValueBase& destination) + { + Allocator& alloc = get_base_table()->get_alloc(); + Value list_refs; + m_list.get_lists(index, list_refs, 1); + REALM_ASSERT_DEBUG(list_refs.m_values > 0 || list_refs.m_from_link_list); + size_t sz = list_refs.m_values; + // The result is an aggregate value for each table + auto v = make_value_for_link(!list_refs.m_from_link_list, sz); + for (unsigned i = 0; i < sz; i++) { + auto list_ref = list_refs.m_storage[i]; + Operation op; + if (list_ref) { + BPlusTree list(alloc); + list.init_from_ref(list_ref); + size_t s = list.size(); + for (unsigned j = 0; j < s; j++) { + op.accumulate(list.get(j)); + } + } + if (op.is_null()) { + v.m_storage.set_null(i); + } + else { + v.m_storage.set(i, op.result()); + } + } + destination.import(v); + } + ColKey m_column_key; + Columns> m_list; +}; + +template +Query compare(const Subexpr2& left, const ConstObj& obj) +{ + static_assert(std::is_same_v || std::is_same_v, + "Links can only be compared for equality."); + const Columns* column = dynamic_cast*>(&left); + if (column) { + const LinkMap& link_map = column->link_map(); + REALM_ASSERT(link_map.get_target_table()->get_key() == obj.get_table()->get_key()); +#ifdef REALM_OLDQUERY_FALLBACK + if (link_map.get_nb_hops() == 1) { + // We can fall back to Query::links_to for != and == operations on links, but only + // for == on link lists. This is because negating query.links_to() is equivalent to + // to "ALL linklist != row" rather than the "ANY linklist != row" semantics we're after. + if (link_map.m_link_types[0] == col_type_Link || + (link_map.m_link_types[0] == col_type_LinkList && std::is_same_v)) { + ConstTableRef t = column->get_base_table(); + Query query(t); + + if (std::is_same_v) { + // Negate the following `links_to`. + query.Not(); + } + query.links_to(link_map.m_link_column_keys[0], obj.get_key()); + return query; + } + } +#endif + } + return make_expression>(left.clone(), make_subexpr(obj.get_key())); +} + +inline Query operator==(const Subexpr2& left, const ConstObj& row) +{ + return compare(left, row); +} +inline Query operator!=(const Subexpr2& left, const ConstObj& row) +{ + return compare(left, row); +} +inline Query operator==(const ConstObj& row, const Subexpr2& right) +{ + return compare(right, row); +} +inline Query operator!=(const ConstObj& row, const Subexpr2& right) +{ + return compare(right, row); +} + +template +Query compare(const Subexpr2& left, null) +{ + static_assert(std::is_same_v || std::is_same_v, + "Links can only be compared for equality."); + return make_expression>(left.clone(), make_subexpr(ObjKey{})); +} + +inline Query operator==(const Subexpr2& left, null) +{ + return compare(left, null()); +} +inline Query operator!=(const Subexpr2& left, null) +{ + return compare(left, null()); +} +inline Query operator==(null, const Subexpr2& right) +{ + return compare(right, null()); +} +inline Query operator!=(null, const Subexpr2& right) +{ + return compare(right, null()); +} + + +template +class Columns : public Subexpr2 { +public: + using LeafType = typename ColumnTypeTraits::cluster_leaf_type; + + Columns(ColKey column, ConstTableRef table, std::vector links = {}, + ExpressionComparisonType type = ExpressionComparisonType::Any) + : m_link_map(table, std::move(links)) + , m_column_key(column) + , m_nullable(m_link_map.get_target_table()->is_nullable(m_column_key)) + , m_comparison_type(type) + { + } + + Columns(const Columns& other) + : m_link_map(other.m_link_map) + , m_column_key(other.m_column_key) + , m_nullable(other.m_nullable) + , m_comparison_type(other.m_comparison_type) + { + } + + Columns& operator=(const Columns& other) + { + if (this != &other) { + m_link_map = other.m_link_map; + m_column_key = other.m_column_key; + m_nullable = other.m_nullable; + m_comparison_type = other.m_comparison_type; + } + return *this; + } + + std::unique_ptr clone() const override + { + return make_subexpr>(*this); + } + + // See comment in base class + void set_base_table(ConstTableRef table) override + { + if (table == get_base_table()) + return; + + m_link_map.set_base_table(table); + m_nullable = m_link_map.get_target_table()->is_nullable(m_column_key); + } + + void set_cluster(const Cluster* cluster) override + { + m_array_ptr = nullptr; + m_leaf_ptr = nullptr; + if (links_exist()) { + m_link_map.set_cluster(cluster); + } + else { + // Create new Leaf + m_array_ptr = LeafPtr(new (&m_leaf_cache_storage) LeafType(get_base_table()->get_alloc())); + cluster->init_leaf(m_column_key, m_array_ptr.get()); + m_leaf_ptr = m_array_ptr.get(); + } + } + + bool has_search_index() const override + { + return m_link_map.get_target_table()->has_search_index(m_column_key); + } + + std::vector find_all(Mixed value) const override + { + std::vector ret; + std::vector result; + + if (value.is_null() && !m_nullable) { + return ret; + } + + if (m_link_map.get_target_table()->get_primary_key_column() == m_column_key) { + // Only one object with a given key would be possible + if (auto k = m_link_map.get_target_table()->find_primary_key(value)) + result.push_back(k); + } + else { + StringIndex* index = m_link_map.get_target_table()->get_search_index(m_column_key); + REALM_ASSERT(index); + + if (value.is_null()) { + index->find_all(result, realm::null{}); + } + else { + T val = value.get(); + index->find_all(result, val); + } + } + + for (auto k : result) { + auto ndxs = m_link_map.get_origin_ndxs(k); + ret.insert(ret.end(), ndxs.begin(), ndxs.end()); + } + + return ret; + } + + void collect_dependencies(std::vector& tables) const override + { + m_link_map.collect_dependencies(tables); + } + + // Recursively fetch tables of columns in expression tree. Used when user first builds a stand-alone expression + // and binds it to a Query at a later time + ConstTableRef get_base_table() const override + { + return m_link_map.get_base_table(); + } + + template + void evaluate_internal(size_t index, ValueBase& destination) + { + using U = typename LeafType2::value_type; + + if (links_exist()) { + REALM_ASSERT(m_leaf_ptr == nullptr); + // LinkList with more than 0 values. Create Value with payload for all fields + std::vector links = m_link_map.get_links(index); + auto v = make_value_for_link::type>(m_link_map.only_unary_links(), + links.size()); + + for (size_t t = 0; t < links.size(); t++) { + ConstObj obj = m_link_map.get_target_table()->get_object(links[t]); + if (obj.is_null(m_column_key)) + v.m_storage.set_null(t); + else + v.m_storage.set(t, obj.get(m_column_key)); + } + destination.import(v); + } + else { + REALM_ASSERT(m_leaf_ptr != nullptr); + auto leaf = static_cast(m_leaf_ptr); + // Not a Link column + size_t colsize = leaf->size(); + + // Now load `ValueBase::chunk_size` rows from from the leaf into m_storage. If it's an integer + // leaf, then it contains the method get_chunk() which copies these values in a super fast way (first + // case of the `if` below. Otherwise, copy the values one by one in a for-loop (the `else` case). + if (std::is_same_v && index + ValueBase::chunk_size <= colsize) { + Value v(false, ValueBase::chunk_size); + + // If you want to modify 'chunk_size' then update Array::get_chunk() + REALM_ASSERT_3(ValueBase::chunk_size, ==, 8); + + auto leaf_2 = static_cast(leaf); + leaf_2->get_chunk(index, v.m_storage.m_first); + + destination.import(v); + } + else { + size_t rows = colsize - index; + if (rows > ValueBase::chunk_size) + rows = ValueBase::chunk_size; + Value::type> v(false, rows); + + for (size_t t = 0; t < rows; t++) + v.m_storage.set(t, leaf->get(index + t)); + + destination.import(v); + } + } + } + + virtual std::string description(util::serializer::SerialisationState& state) const override + { + return state.describe_expression_type(m_comparison_type) + state.describe_columns(m_link_map, m_column_key); + } + + // Load values from Column into destination + void evaluate(size_t index, ValueBase& destination) override + { + if (m_nullable && std::is_same_v) { + evaluate_internal(index, destination); + } + else if (m_nullable && std::is_same_v) { + evaluate_internal(index, destination); + } + else { + evaluate_internal(index, destination); + } + } + + void evaluate(ObjKey key, ValueBase& destination) override + { + auto table = m_link_map.get_target_table(); + auto obj = table.unchecked_ptr()->get_object(key); + if (m_nullable && std::is_same_v) { + Value v(false, 1); + v.m_storage.set(0, obj.template get>(m_column_key)); + destination.import(v); + } + else if (m_nullable && std::is_same_v) { + Value v(false, 1); + v.m_storage.set(0, obj.template get>(m_column_key)); + destination.import(v); + } + else { + Value::type> v(false, 1); + T val = obj.template get(m_column_key); + v.m_storage.set(0, val); + destination.import(v); + } + } + + bool links_exist() const + { + return m_link_map.has_links(); + } + + bool only_unary_links() const + { + return m_link_map.only_unary_links(); + } + + bool is_nullable() const + { + return m_nullable; + } + + LinkMap get_link_map() const + { + return m_link_map; + } + + ColKey column_key() const noexcept + { + return m_column_key; + } + + virtual ExpressionComparisonType get_comparison_type() const override + { + return m_comparison_type; + } + +private: + LinkMap m_link_map; + + // Leaf cache + using LeafCacheStorage = typename std::aligned_storage::type; + using LeafPtr = std::unique_ptr; + LeafCacheStorage m_leaf_cache_storage; + LeafPtr m_array_ptr; + const ArrayPayload* m_leaf_ptr = nullptr; + + // Column index of payload column of m_table + mutable ColKey m_column_key; + + // set to false by default for stand-alone Columns declaration that are not yet associated with any table + // or column. Call init() to update it or use a constructor that takes table + column index as argument. + bool m_nullable = false; + ExpressionComparisonType m_comparison_type = ExpressionComparisonType::Any; +}; + +template +class SubColumnAggregate; + +template +class SubColumns : public Subexpr { +public: + SubColumns(Columns&& column, const LinkMap& link_map) + : m_column(std::move(column)) + , m_link_map(link_map) + { + } + + DataType get_type() const final + { + return ColumnTypeTraits::id; + } + + std::unique_ptr clone() const override + { + return make_subexpr>(*this); + } + + ConstTableRef get_base_table() const override + { + return m_link_map.get_base_table(); + } + + void set_base_table(ConstTableRef table) override + { + m_link_map.set_base_table(table); + m_column.set_base_table(m_link_map.get_target_table()); + } + + void collect_dependencies(std::vector& tables) const override + { + m_link_map.collect_dependencies(tables); + } + + void evaluate(size_t, ValueBase&) override + { + // SubColumns can only be used in an expression in conjunction with its aggregate methods. + REALM_ASSERT(false); + } + + virtual std::string description(util::serializer::SerialisationState&) const override + { + return ""; // by itself there are no conditions, see SubColumnAggregate + } + + SubColumnAggregate> min() const + { + return {m_column, m_link_map}; + } + + SubColumnAggregate> max() const + { + return {m_column, m_link_map}; + } + + SubColumnAggregate> sum() const + { + return {m_column, m_link_map}; + } + + SubColumnAggregate> average() const + { + return {m_column, m_link_map}; + } + +private: + Columns m_column; + LinkMap m_link_map; +}; + +template +class SubColumnAggregate : public Subexpr2 { +public: + SubColumnAggregate(const Columns& column, const LinkMap& link_map) + : m_column(column) + , m_link_map(link_map) + { + } + SubColumnAggregate(SubColumnAggregate const& other) + : m_column(other.m_column) + , m_link_map(other.m_link_map) + { + } + + std::unique_ptr clone() const override + { + return make_subexpr(*this); + } + + ConstTableRef get_base_table() const override + { + return m_link_map.get_base_table(); + } + + void set_base_table(ConstTableRef table) override + { + m_link_map.set_base_table(table); + m_column.set_base_table(m_link_map.get_target_table()); + } + + void set_cluster(const Cluster* cluster) override + { + m_link_map.set_cluster(cluster); + } + + void collect_dependencies(std::vector& tables) const override + { + m_link_map.collect_dependencies(tables); + } + + void evaluate(size_t index, ValueBase& destination) override + { + std::vector keys = m_link_map.get_links(index); + std::sort(keys.begin(), keys.end()); + + Operation op; + for (auto key : keys) { + Value value(false, 1); + m_column.evaluate(key, value); + size_t value_index = 0; + const auto& value_storage = value.m_storage; + if (!value_storage.is_null(value_index)) { + op.accumulate(value_storage[value_index]); + } + } + if (op.is_null()) { + destination.import(Value(false, 1, null())); + } + else { + destination.import(Value(false, 1, op.result())); + } + } + + virtual std::string description(util::serializer::SerialisationState& state) const override + { + util::serializer::SerialisationState empty_state; + return state.describe_columns(m_link_map, ColKey()) + util::serializer::value_separator + + Operation::description() + util::serializer::value_separator + m_column.description(empty_state); + } + +private: + Columns m_column; + LinkMap m_link_map; +}; + +class SubQueryCount : public Subexpr2 { +public: + SubQueryCount(const Query& q, const LinkMap& link_map) + : m_query(q) + , m_link_map(link_map) + { + REALM_ASSERT(q.produces_results_in_table_order()); + REALM_ASSERT(m_query.get_table() == m_link_map.get_target_table()); + } + + ConstTableRef get_base_table() const override + { + return m_link_map.get_base_table(); + } + + void set_base_table(ConstTableRef table) override + { + m_link_map.set_base_table(table); + m_query.set_table(m_link_map.get_target_table().cast_away_const()); + } + + void set_cluster(const Cluster* cluster) override + { + m_link_map.set_cluster(cluster); + } + + void collect_dependencies(std::vector& tables) const override + { + m_link_map.collect_dependencies(tables); + } + + void evaluate(size_t index, ValueBase& destination) override + { + std::vector links = m_link_map.get_links(index); + // std::sort(links.begin(), links.end()); + m_query.init(); + + size_t count = std::accumulate(links.begin(), links.end(), size_t(0), [this](size_t running_count, ObjKey k) { + ConstObj obj = m_link_map.get_target_table()->get_object(k); + return running_count + m_query.eval_object(obj); + }); + + destination.import(Value(false, 1, size_t(count))); + } + + virtual std::string description(util::serializer::SerialisationState& state) const override + { + REALM_ASSERT(m_link_map.get_base_table() != nullptr); + std::string target = state.describe_columns(m_link_map, ColKey()); + std::string var_name = state.get_variable_name(m_link_map.get_base_table()); + state.subquery_prefix_list.push_back(var_name); + std::string desc = "SUBQUERY(" + target + ", " + var_name + ", " + m_query.get_description(state) + ")" + + util::serializer::value_separator + "@count"; + state.subquery_prefix_list.pop_back(); + return desc; + } + + std::unique_ptr clone() const override + { + return make_subexpr(*this); + } + +private: + Query m_query; + LinkMap m_link_map; +}; + +// The unused template parameter is a hack to avoid a circular dependency between table.hpp and query_expression.hpp. +template +class SubQuery { +public: + SubQuery(Columns link_column, Query query) + : m_query(std::move(query)) + , m_link_map(link_column.link_map()) + { + REALM_ASSERT(m_link_map.get_target_table() == m_query.get_table()); + } + + SubQueryCount count() const + { + return SubQueryCount(m_query, m_link_map); + } + +private: + Query m_query; + LinkMap m_link_map; +}; + +namespace aggregate_operations { +template +class BaseAggregateOperation { + static_assert(realm::is_any::value, + "Numeric aggregates can only be used with subcolumns of numeric types"); + +public: + using ResultType = R; + + void accumulate(T value) + { + m_count++; + m_result = Derived::apply(m_result, value); + } + + void accumulate(util::Optional value) + { + if (value) { + m_count++; + m_result = Derived::apply(m_result, *value); + } + } + + bool is_null() const + { + return m_count == 0; + } + ResultType result() const + { + return m_result; + } + +protected: + size_t m_count = 0; + ResultType m_result = Derived::initial_value(); +}; + +template +class Minimum : public BaseAggregateOperation> { +public: + static T initial_value() + { + return std::numeric_limits::max(); + } + static T apply(T a, T b) + { + return std::min(a, b); + } + static std::string description() + { + return "@min"; + } +}; + +template <> +class Minimum : public BaseAggregateOperation> { +public: + static Decimal128 initial_value() + { + return Decimal128("+inf"); + } + static Decimal128 apply(Decimal128 a, Decimal128 b) + { + return std::min(a, b); + } + static std::string description() + { + return "@min"; + } +}; + +template +class Maximum : public BaseAggregateOperation> { +public: + static T initial_value() + { + return std::numeric_limits::lowest(); + } + static T apply(T a, T b) + { + return std::max(a, b); + } + static std::string description() + { + return "@max"; + } +}; + +template <> +class Maximum : public BaseAggregateOperation> { +public: + static Decimal128 initial_value() + { + return Decimal128("-inf"); + } + static Decimal128 apply(Decimal128 a, Decimal128 b) + { + return std::max(a, b); + } + static std::string description() + { + return "@max"; + } +}; + +template +class Sum : public BaseAggregateOperation> { +public: + static T initial_value() + { + return T(); + } + static T apply(T a, T b) + { + return a + b; + } + bool is_null() const + { + return false; + } + static std::string description() + { + return "@sum"; + } +}; + +template +class Average : public BaseAggregateOperation, double> { + using Base = BaseAggregateOperation, double>; + +public: + static double initial_value() + { + return 0; + } + static double apply(double a, T b) + { + return a + b; + } + double result() const + { + return Base::m_result / Base::m_count; + } + static std::string description() + { + return "@avg"; + } +}; + +template <> +class Average : public BaseAggregateOperation, Decimal128> { + using Base = BaseAggregateOperation, Decimal128>; + +public: + static Decimal128 initial_value() + { + return Decimal128(0); + } + static Decimal128 apply(Decimal128 a, Decimal128 b) + { + return a + b; + } + Decimal128 result() const + { + return Decimal128(Base::m_result) / Base::m_count; + } + static std::string description() + { + return "@avg"; + } +}; +} + +template +class UnaryOperator : public Subexpr2 { +public: + UnaryOperator(std::unique_ptr left) + : m_left(std::move(left)) + { + } + + UnaryOperator(const UnaryOperator& other) + : m_left(other.m_left->clone()) + { + } + + UnaryOperator& operator=(const UnaryOperator& other) + { + if (this != &other) { + m_left = other.m_left->clone(); + } + return *this; + } + + UnaryOperator(UnaryOperator&&) noexcept = default; + UnaryOperator& operator=(UnaryOperator&&) noexcept = default; + + // See comment in base class + void set_base_table(ConstTableRef table) override + { + m_left->set_base_table(table); + } + + void set_cluster(const Cluster* cluster) override + { + m_left->set_cluster(cluster); + } + + void collect_dependencies(std::vector& tables) const override + { + m_left->collect_dependencies(tables); + } + + // Recursively fetch tables of columns in expression tree. Used when user first builds a stand-alone expression + // and binds it to a Query at a later time + ConstTableRef get_base_table() const override + { + return m_left->get_base_table(); + } + + // destination = operator(left) + void evaluate(size_t index, ValueBase& destination) override + { + Value result; + Value left; + m_left->evaluate(index, left); + result.template fun(&left); + destination.import(result); + } + + virtual std::string description(util::serializer::SerialisationState& state) const override + { + if (m_left) { + return m_left->description(state); + } + return ""; + } + + std::unique_ptr clone() const override + { + return make_subexpr(*this); + } + +private: + typedef typename oper::type T; + std::unique_ptr m_left; +}; + + +template +class Operator : public Subexpr2 { +public: + Operator(std::unique_ptr left, std::unique_ptr right) + : m_left(std::move(left)) + , m_right(std::move(right)) + { + } + + Operator(const Operator& other) + : m_left(other.m_left->clone()) + , m_right(other.m_right->clone()) + { + } + + Operator& operator=(const Operator& other) + { + if (this != &other) { + m_left = other.m_left->clone(); + m_right = other.m_right->clone(); + } + return *this; + } + + Operator(Operator&&) noexcept = default; + Operator& operator=(Operator&&) noexcept = default; + + // See comment in base class + void set_base_table(ConstTableRef table) override + { + m_left->set_base_table(table); + m_right->set_base_table(table); + } + + void set_cluster(const Cluster* cluster) override + { + m_left->set_cluster(cluster); + m_right->set_cluster(cluster); + } + + // Recursively fetch tables of columns in expression tree. Used when user first builds a stand-alone expression + // and + // binds it to a Query at a later time + ConstTableRef get_base_table() const override + { + ConstTableRef l = m_left->get_base_table(); + ConstTableRef r = m_right->get_base_table(); + + // Queries do not support multiple different tables; all tables must be the same. + REALM_ASSERT(l == nullptr || r == nullptr || l == r); + + // nullptr pointer means expression which isn't yet associated with any table, or is a Value + return bool(l) ? l : r; + } + + // destination = operator(left, right) + void evaluate(size_t index, ValueBase& destination) override + { + Value result; + Value left; + Value right; + m_left->evaluate(index, left); + m_right->evaluate(index, right); + result.template fun(&left, &right); + destination.import(result); + } + + virtual std::string description(util::serializer::SerialisationState& state) const override + { + std::string s; + if (m_left) { + s += m_left->description(state); + } + s += (" " + oper::description() + " "); + if (m_right) { + s += m_right->description(state); + } + return s; + } + + std::unique_ptr clone() const override + { + return make_subexpr(*this); + } + +private: + typedef typename oper::type T; + std::unique_ptr m_left; + std::unique_ptr m_right; +}; + +namespace { +template +inline Mixed get_mixed(const Value& val) +{ + return Mixed(val.m_storage[0]); +} + +template <> +inline Mixed get_mixed(const Value& val) +{ + return Mixed(int64_t(val.m_storage[0])); +} +} // namespace + +template +class Compare : public Expression { +public: + Compare(std::unique_ptr left, std::unique_ptr right) + : m_left(std::move(left)) + , m_right(std::move(right)) + { + m_left_is_const = m_left->has_constant_evaluation(); + if (m_left_is_const) { + m_left->evaluate(-1 /*unused*/, m_left_value); + } + } + + // See comment in base class + void set_base_table(ConstTableRef table) override + { + m_left->set_base_table(table); + m_right->set_base_table(table); + } + + void set_cluster(const Cluster* cluster) override + { + if (m_has_matches) { + m_cluster = cluster; + } + else { + m_left->set_cluster(cluster); + m_right->set_cluster(cluster); + } + } + + double init() override + { + double dT = m_left_is_const ? 10.0 : 50.0; + if (std::is_same_v && m_left_is_const && m_right->has_search_index() && + m_right->get_comparison_type() == ExpressionComparisonType::Any) { + if (m_left_value.m_storage.is_null(0)) { + m_matches = m_right->find_all(Mixed()); + } + else { + Mixed m = get_mixed(m_left_value); + if (m_right->get_type() != m.get_type()) { + // If the type we are looking for is not the same type as the target + // column, we cannot use the index + return dT; + } + m_matches = m_right->find_all(m); + } + // Sort + std::sort(m_matches.begin(), m_matches.end()); + // Remove all duplicates + m_matches.erase(std::unique(m_matches.begin(), m_matches.end()), m_matches.end()); + + m_has_matches = true; + m_index_get = 0; + m_index_end = m_matches.size(); + dT = 0; + } + + return dT; + } + + // Recursively fetch tables of columns in expression tree. Used when user first builds a stand-alone expression + // and binds it to a Query at a later time + ConstTableRef get_base_table() const override + { + ConstTableRef l = m_left->get_base_table(); + ConstTableRef r = m_right->get_base_table(); + + // All main tables in each subexpression of a query (table.columns() or table.link()) must be the same. + REALM_ASSERT(l == nullptr || r == nullptr || l == r); + + // nullptr pointer means expression which isn't yet associated with any table, or is a Value + return (l) ? l : r; + } + + void collect_dependencies(std::vector& tables) const override + { + m_left->collect_dependencies(tables); + m_right->collect_dependencies(tables); + } + + size_t find_first(size_t start, size_t end) const override + { + if (m_has_matches) { + if (m_index_end == 0 || start >= end) + return not_found; + + ObjKey first_key = m_cluster->get_real_key(start); + ObjKey actual_key; + + // Sequential lookup optimization: when the query isn't constrained + // to a LnkLst we'll get find_first() requests in ascending order, + // so we can do a simple linear scan. + if (m_index_get < m_index_end && m_matches[m_index_get] <= first_key) { + actual_key = m_matches[m_index_get]; + // skip through keys which are in "earlier" leafs than the one selected by start..end: + while (first_key > actual_key) { + m_index_get++; + if (m_index_get == m_index_end) + return not_found; + actual_key = m_matches[m_index_get]; + } + } + // Otherwise if we get requests out of order we have to do a more + // expensive binary search + else { + auto it = std::lower_bound(m_matches.begin(), m_matches.end(), first_key); + if (it == m_matches.end()) + return not_found; + actual_key = *it; + } + + // if actual key is bigger than last key, it is not in this leaf + ObjKey last_key = start + 1 == end ? first_key : m_cluster->get_real_key(end - 1); + if (actual_key > last_key) + return not_found; + + // key is known to be in this leaf, so find key whithin leaf keys + return m_cluster->lower_bound_key(ObjKey(actual_key.value - m_cluster->get_offset())); + } + + size_t match; + Value right; + const ExpressionComparisonType right_cmp_type = m_right->get_comparison_type(); + if (m_left_is_const) { + for (; start < end;) { + m_right->evaluate(start, right); + match = Value::template compare_const(&m_left_value, &right, right_cmp_type); + if (match != not_found && match + start < end) + return start + match; + + size_t rows = (m_left_value.m_from_link_list || right.m_from_link_list) + ? 1 + : minimum(right.m_values, m_left_value.m_values); + start += rows; + } + } + else { + Value left; + const ExpressionComparisonType left_cmp_type = m_left->get_comparison_type(); + for (; start < end;) { + m_left->evaluate(start, left); + m_right->evaluate(start, right); + match = Value::template compare(&left, &right, left_cmp_type, right_cmp_type); + if (match != not_found && match + start < end) + return start + match; + + size_t rows = + (left.m_from_link_list || right.m_from_link_list) ? 1 : minimum(right.m_values, left.m_values); + start += rows; + } + } + + return not_found; // no match + } + + virtual std::string description(util::serializer::SerialisationState& state) const override + { + if (realm::is_any_v) { + // these string conditions have the arguments reversed but the order is important + // operations ==, and != can be reversed because the produce the same results both ways + return util::serializer::print_value(m_right->description(state) + " " + TCond::description() + " " + + m_left->description(state)); + } + return util::serializer::print_value(m_left->description(state) + " " + TCond::description() + " " + + m_right->description(state)); + } + + std::unique_ptr clone() const override + { + return std::unique_ptr(new Compare(*this)); + } + +private: + Compare(const Compare& other) + : m_left(other.m_left->clone()) + , m_right(other.m_right->clone()) + , m_left_is_const(other.m_left_is_const) + { + if (m_left_is_const) { + m_left->evaluate(-1 /*unused*/, m_left_value); + } + } + + std::unique_ptr m_left; + std::unique_ptr m_right; + const Cluster* m_cluster; + bool m_left_is_const; + Value m_left_value; + bool m_has_matches = false; + std::vector m_matches; + mutable size_t m_index_get = 0; + size_t m_index_end = 0; +}; +} +#endif // REALM_QUERY_EXPRESSION_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/realm_nmmintrin.h b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/realm_nmmintrin.h new file mode 100644 index 0000000..645fe35 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/realm_nmmintrin.h @@ -0,0 +1,180 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_NMMINTRIN_H +#define REALM_NMMINTRIN_H + +/* + We must support runtime detection of CPU support of SSE when distributing Realm as a closed source library. + + This is a problem on gcc and llvm: To use SSE intrinsics we need to pass -msse on the command line (to get offered + __builtin_ accessors used by intrinsics functions). However, the -msse flag allows gcc to emit SSE instructions + in its code generation/optimization. This is unwanted because the binary would crash on non-SSE CPUs. + + Since there exists no flag in gcc that enables intrinsics but probits SSE in code generation, we define our + own intrinsics to be assembled by the back end assembler and omit passing -msse to gcc. +*/ + +#if !defined(_MSC_VER) && defined(REALM_COMPILER_SSE) + +#include // SSE2 (using __m128i) + +namespace realm { + +#if 0 +#ifdef REALM_COMPILER_AVX +typedef float __m256 __attribute__((__vector_size__(32), __may_alias__)); +typedef double __m256d __attribute__((__vector_size__(32), __may_alias__)); + +const int _CMP_EQ_OQ = 0x00; // Equal (ordered, non-signaling) +const int _CMP_NEQ_OQ = 0x0c; // Not-equal (ordered, non-signaling) +const int _CMP_LT_OQ = 0x11; // Less-than (ordered, non-signaling) +const int _CMP_LE_OQ = 0x12; // Less-than-or-equal (ordered, non-signaling) +const int _CMP_GE_OQ = 0x1d; // Greater-than-or-equal (ordered, non-signaling) +const int _CMP_GT_OQ = 0x1e; // Greater-than (ordered, non-signaling) + + +template +static int movemask_cmp_ps(__m256* y1, __m256* y2) +{ + int ret; + __asm__("vmovaps %0, %%ymm0" : : "m"(*y1) : "%xmm0" ); + __asm__("vmovaps %0, %%ymm1" : : "m"(*y2) : "%xmm1" ); + __asm__("vcmpps %0, %%ymm0, %%ymm1, %%ymm0" : : "I"(op) : "%xmm0" ); + __asm__("vmovmskps %%ymm0, %0" : "=r"(ret) : : ); + return ret; +} + +template +static inline int movemask_cmp_pd(__m256d* y1, __m256d* y2) +{ + int ret; + __asm__("vmovapd %0, %%ymm0" : : "m"(*y1) : "%xmm0" ); + __asm__("vmovapd %0, %%ymm1" : : "m"(*y2) : "%xmm1" ); + __asm__("vcmppd %0, %%ymm0, %%ymm1, %%ymm0" : : "I"(op) : "%xmm0" ); + __asm__("vmovmskpd %%ymm0, %0" : "=r"(ret) : : ); + return ret; +} + + + +static inline int movemask_cmp_ps(__m256* y1, __m256* y2, int op) +{ + // todo, use constexpr; + if (op == _CMP_EQ_OQ) + return movemask_cmp_ps<_CMP_NEQ_OQ>(y1, y2); + else if (op == _CMP_NEQ_OQ) + return movemask_cmp_ps<_CMP_NEQ_OQ>(y1, y2); + else if (op == _CMP_LT_OQ) + return movemask_cmp_ps<_CMP_LT_OQ>(y1, y2); + else if (op == _CMP_LE_OQ) + return movemask_cmp_ps<_CMP_LE_OQ>(y1, y2); + else if (op == _CMP_GE_OQ) + return movemask_cmp_ps<_CMP_GE_OQ>(y1, y2); + else if (op == _CMP_GT_OQ) + return movemask_cmp_ps<_CMP_GT_OQ>(y1, y2); + + REALM_ASSERT(false); + return 0; +} + +static inline int movemask_cmp_pd(__m256d* y1, __m256d* y2, int op) +{ + // todo, use constexpr; + if (op == _CMP_EQ_OQ) + return movemask_cmp_pd<_CMP_NEQ_OQ>(y1, y2); + else if (op == _CMP_NEQ_OQ) + return movemask_cmp_pd<_CMP_NEQ_OQ>(y1, y2); + else if (op == _CMP_LT_OQ) + return movemask_cmp_pd<_CMP_LT_OQ>(y1, y2); + else if (op == _CMP_LE_OQ) + return movemask_cmp_pd<_CMP_LE_OQ>(y1, y2); + else if (op == _CMP_GE_OQ) + return movemask_cmp_pd<_CMP_GE_OQ>(y1, y2); + else if (op == _CMP_GT_OQ) + return movemask_cmp_pd<_CMP_GT_OQ>(y1, y2); + + REALM_ASSERT(false); + return 0; +} + + +#endif +#endif + +// Instructions introduced by SSE 3 and 4.2 +static inline __m128i _mm_cmpgt_epi64(__m128i xmm1, __m128i xmm2) +{ + __asm__("pcmpgtq %1, %0" : "+x" (xmm1) : "xm" (xmm2)); + return xmm1; +} + +static inline __m128i _mm_cmpeq_epi64(__m128i xmm1, __m128i xmm2) +{ + __asm__("pcmpeqq %1, %0" : "+x" (xmm1) : "xm" (xmm2)); + return xmm1; +} + +static inline __m128i __attribute__((always_inline)) _mm_min_epi8(__m128i xmm1, __m128i xmm2) +{ + __asm__("pminsb %1, %0" : "+x" (xmm1) : "xm" (xmm2)); + return xmm1; +} + +static inline __m128i __attribute__((always_inline)) _mm_max_epi8(__m128i xmm1, __m128i xmm2) +{ + __asm__("pmaxsb %1, %0" : "+x" (xmm1) : "xm" (xmm2)); + return xmm1; +} + +static inline __m128i __attribute__((always_inline)) _mm_max_epi32(__m128i xmm1, __m128i xmm2) +{ + __asm__("pmaxsd %1, %0" : "+x" (xmm1) : "xm" (xmm2)); + return xmm1; +} + +static inline __m128i __attribute__((always_inline)) _mm_min_epi32(__m128i xmm1, __m128i xmm2) +{ + __asm__("pminsd %1, %0" : "+x" (xmm1) : "xm" (xmm2)); + return xmm1; +} + +static inline __m128i __attribute__((always_inline)) _mm_cvtepi8_epi16(__m128i xmm2) +{ + __m128i xmm1; + __asm__("pmovsxbw %1, %0" : "=x" (xmm1) : "xm" (xmm2) : "xmm1"); + return xmm1; +} +static inline __m128i __attribute__((always_inline)) _mm_cvtepi16_epi32(__m128i xmm2) +{ + __m128i xmm1; + asm("pmovsxwd %1, %0" : "=x" (xmm1) : "xm" (xmm2)); + return xmm1; +} + +static inline __m128i __attribute__((always_inline)) _mm_cvtepi32_epi64(__m128i xmm2) +{ + __m128i xmm1; + __asm__("pmovsxdq %1, %0" : "=x" (xmm1) : "xm" (xmm2)); + return xmm1; +} + +} // namespace realm + +#endif // !defined(_MSC_VER) && defined(REALM_COMPILER_SSE) +#endif diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/replication.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/replication.hpp new file mode 100644 index 0000000..85a61c3 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/replication.hpp @@ -0,0 +1,572 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_REPLICATION_HPP +#define REALM_REPLICATION_HPP + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace realm { +namespace util { +class Logger; +} + +// FIXME: Be careful about the possibility of one modification function being called by another where both do +// transaction logging. + +/// Replication is enabled by passing an instance of an implementation of this +/// class to the DB constructor. +class Replication : public _impl::TransactLogConvenientEncoder { +public: + // Be sure to keep this type aligned with what is actually used in DB. + using version_type = _impl::History::version_type; + using InputStream = _impl::NoCopyInputStream; + class TransactLogApplier; + class Interrupted; // Exception + class SimpleIndexTranslator; + + virtual std::string get_database_path() const = 0; + + /// Called during construction of the associated DB object. + /// + /// \param db The associated DB object. + virtual void initialize(DB& db) = 0; + + + /// Called by the associated DB object when a session is + /// initiated. A *session* is a sequence of temporally overlapping + /// accesses to a specific Realm file, where each access consists of a + /// DB object through which the Realm file is open. Session + /// initiation occurs during the first opening of the Realm file within such + /// a session. + /// + /// Session initiation fails if this function throws. + /// + /// \param version The current version of the associated Realm. + /// + /// The default implementation does nothing. + virtual void initiate_session(version_type version) = 0; + + /// Called by the associated DB object when a session is + /// terminated. See initiate_session() for the definition of a + /// session. Session termination occurs upon closing the Realm through the + /// last DB object within the session. + /// + /// The default implementation does nothing. + virtual void terminate_session() noexcept = 0; + + /// \defgroup replication_transactions + //@{ + + /// From the point of view of the Replication class, a transaction is + /// initiated when, and only when the associated Transaction object calls + /// initiate_transact() and the call is successful. The associated + /// Transaction object must terminate every initiated transaction either by + /// calling finalize_commit() or by calling abort_transact(). It may only + /// call finalize_commit(), however, after calling prepare_commit(), and + /// only when prepare_commit() succeeds. If prepare_commit() fails (i.e., + /// throws) abort_transact() must still be called. + /// + /// The associated Transaction object is supposed to terminate a transaction + /// as soon as possible, and is required to terminate it before attempting + /// to initiate a new one. + /// + /// initiate_transact() is called by the associated Transaction object as + /// part of the initiation of a transaction, and at a time where the caller + /// has acquired exclusive write access to the local Realm. The Replication + /// implementation is allowed to perform "precursor transactions" on the + /// local Realm at this time. During the initiated transaction, the + /// associated DB object must inform the Replication object of all + /// modifying operations by calling set_value() and friends. + /// + /// FIXME: There is currently no way for implementations to perform + /// precursor transactions, since a regular transaction would cause a dead + /// lock when it tries to acquire a write lock. Consider giving access to + /// special non-locking precursor transactions via an extra argument to this + /// function. + /// + /// prepare_commit() serves as the first phase of a two-phase commit. This + /// function is called by the associated Transaction object immediately + /// before the commit operation on the local Realm. The associated + /// Transaction object will then, as the second phase, either call + /// finalize_commit() or abort_transact() depending on whether the commit + /// operation succeeded or not. The Replication implementation is allowed to + /// modify the Realm via the associated Transaction object at this time + /// (important to in-Realm histories). + /// + /// initiate_transact() and prepare_commit() are allowed to block the + /// calling thread if, for example, they need to communicate over the + /// network. If a calling thread is blocked in one of these functions, it + /// must be possible to interrupt the blocking operation by having another + /// thread call interrupt(). The contract is as follows: When interrupt() is + /// called, then any execution of initiate_transact() or prepare_commit(), + /// initiated before the interruption, must complete without blocking, or + /// the execution must be aborted by throwing an Interrupted exception. If + /// initiate_transact() or prepare_commit() throws Interrupted, it counts as + /// a failed operation. + /// + /// finalize_commit() is called by the associated Transaction object + /// immediately after a successful commit operation on the local Realm. This + /// happens at a time where modification of the Realm is no longer possible + /// via the associated Transaction object. In the case of in-Realm + /// histories, the changes are automatically finalized as part of the commit + /// operation performed by the caller prior to the invocation of + /// finalize_commit(), so in that case, finalize_commit() might not need to + /// do anything. + /// + /// abort_transact() is called by the associated Transaction object to + /// terminate a transaction without committing. That is, any transaction + /// that is not terminated by finalize_commit() is terminated by + /// abort_transact(). This could be due to an explicit rollback, or due to a + /// failed commit attempt. + /// + /// Note that finalize_commit() and abort_transact() are not allowed to + /// throw. + /// + /// \param current_version The version of the snapshot that the current + /// transaction is based on. + /// + /// \param history_updated Pass true only when the history has already been + /// updated to reflect the currently bound snapshot, such as when + /// _impl::History::update_early_from_top_ref() was called during the + /// transition from a read transaction to the current write transaction. + /// + /// \throw Interrupted Thrown by initiate_transact() and prepare_commit() if + /// a blocking operation was interrupted. + + void initiate_transact(Group& group, version_type current_version, bool history_updated); + /// \param current_version The version of the snapshot that the current + /// transaction is based on. + /// \return prepare_commit() returns the version of the new snapshot + /// produced by the transaction. + version_type prepare_commit(version_type current_version); + void finalize_commit() noexcept; + void abort_transact() noexcept; + + //@} + + /// Get the list of uncommitted changes accumulated so far in the current + /// write transaction. + /// + /// The callee retains ownership of the referenced memory. The ownership is + /// not handed over to the caller. + /// + /// This function may be called only during a write transaction (prior to + /// initiation of commit operation). In that case, the caller may assume that the + /// returned memory reference stays valid for the remainder of the transaction (up + /// until initiation of the commit operation). + virtual BinaryData get_uncommitted_changes() const noexcept = 0; + + /// Interrupt any blocking call to a function in this class. This function + /// may be called asyncronously from any thread, but it may not be called + /// from a system signal handler. + /// + /// Some of the public function members of this class may block, but only + /// when it it is explicitely stated in the documention for those functions. + /// + /// FIXME: Currently we do not state blocking behaviour for all the + /// functions that can block. + /// + /// After any function has returned with an interruption indication, the + /// only functions that may safely be called are abort_transact() and the + /// destructor. If a client, after having received an interruption + /// indication, calls abort_transact() and then clear_interrupt(), it may + /// resume normal operation through this Replication object. + void interrupt() noexcept; + + /// May be called by a client to reset this Replication object after an + /// interrupted transaction. It is not an error to call this function in a + /// situation where no interruption has occured. + void clear_interrupt() noexcept; + + /// CAUTION: These values are stored in Realm files, so value reassignment + /// is not allowed. + enum HistoryType { + /// No history available. No support for either continuous transactions + /// or inter-client synchronization. + hist_None = 0, + + /// Out-of-Realm history supporting continuous transactions. + /// + /// NOTE: This history type is no longer in use. The value needs to stay + /// reserved in case someone tries to open an old Realm file. + hist_OutOfRealm = 1, + + /// In-Realm history supporting continuous transactions + /// (make_in_realm_history()). + hist_InRealm = 2, + + /// In-Realm history supporting continuous transactions and client-side + /// synchronization protocol (realm::sync::ClientHistory). + hist_SyncClient = 3, + + /// In-Realm history supporting continuous transactions and server-side + /// synchronization protocol (realm::_impl::ServerHistory). + hist_SyncServer = 4 + }; + + /// Returns the type of history maintained by this Replication + /// implementation, or \ref hist_None if no history is maintained by it. + /// + /// This type is used to ensure that all session participants agree on + /// history type, and that the Realm file contains a compatible type of + /// history, at the beginning of a new session. + /// + /// As a special case, if there is no top array (Group::m_top) at the + /// beginning of a new session, then the history type is still undecided and + /// all history types (as returned by get_history_type()) are threfore + /// allowed for the session initiator. Note that this case only arises if + /// there was no preceding session, or if no transaction was sucessfully + /// committed during any of the preceding sessions. As soon as a transaction + /// is successfully committed, the Realm contains at least a top array, and + /// from that point on, the history type is generally fixed, although still + /// subject to certain allowed changes (as mentioned below). + /// + /// For the sake of backwards compatibility with older Realm files that does + /// not store any history type, the following rule shall apply: + /// + /// - If the top array of a Realm file (Group::m_top) does not contain a + /// history type, because it is too short, it shall be understood as + /// implicitly storing the type \ref hist_None. + /// + /// Note: In what follows, the meaning of *preceding session* is: The last + /// preceding session that modified the Realm by sucessfully committing a + /// new snapshot. + /// + /// It shall be allowed to switch to a \ref hist_InRealm history if the + /// stored history type is \ref hist_None. This can be done simply by adding + /// a new history to the Realm file. This is possible because histories of + /// this type a transient in nature, and need not survive from one session + /// to the next. + /// + /// On the other hand, as soon as a history of type \ref hist_InRealm is + /// added to a Realm file, that history type is binding for all subsequent + /// sessions. In theory, this constraint is not necessary, and a later + /// switch to \ref hist_None would be possible because of the transient + /// nature of it, however, because the \ref hist_InRealm history remains in + /// the Realm file, there are practical complications, and for that reason, + /// such switching shall not be supported. + /// + /// The \ref hist_SyncClient history type can only be used if the stored + /// history type is also \ref hist_SyncClient, or when there is no top array + /// yet. Likewise, the \ref hist_SyncServer history type can only be used if + /// the stored history type is also \ref hist_SyncServer, or when there is + /// no top array yet. Additionally, when the stored history type is \ref + /// hist_SyncClient or \ref hist_SyncServer, then all subsequent sessions + /// must have the same type. These restrictions apply because such a history + /// needs to be maintained persistently across sessions. + /// + /// In general, if there is no stored history type (no top array) at the + /// beginning of a new session, or if the stored type disagrees with what is + /// returned by get_history_type() (which is possible due to particular + /// allowed changes of history type), the actual history type (as returned + /// by get_history_type()) used during that session, must be stored in the + /// Realm during the first successfully committed transaction in that + /// session. But note that there is still no need to expand the top array to + /// store the history type \ref hist_None, due to the rule mentioned above. + /// + /// This function must return \ref hist_None when, and only when + /// get_history() returns null. + virtual HistoryType get_history_type() const noexcept = 0; + + /// Returns the schema version of the history maintained by this Replication + /// implementation, or 0 if no history is maintained by it. All session + /// participants must agree on history schema version. + /// + /// Must return 0 if get_history_type() returns \ref hist_None. + virtual int get_history_schema_version() const noexcept = 0; + + /// Implementation may assume that this function is only ever called with a + /// stored schema version that is less than what was returned by + /// get_history_schema_version(). + virtual bool is_upgradable_history_schema(int stored_schema_version) const noexcept = 0; + + /// The implementation may assume that this function is only ever called if + /// is_upgradable_history_schema() was called with the same stored schema + /// version, and returned true. This implies that the specified stored + /// schema version is always strictly less than what was returned by + /// get_history_schema_version(). + virtual void upgrade_history_schema(int stored_schema_version) = 0; + + /// Returns an object that gives access to the history of changesets + /// used by writers. All writers can share the same object as all write + /// transactions are serialized. + /// + /// This function must return null when, and only when get_history_type() + /// returns \ref hist_None. + virtual _impl::History* _get_history_write() = 0; + + /// Returns an object that gives access to the history of changesets in a + /// way that allows for continuous transactions to work. All readers must + /// get their own exclusive object as readers are not blocking each other. + /// (Group::advance_transact() in particular). + /// + /// This function must return null when, and only when get_history_type() + /// returns \ref hist_None. + virtual std::unique_ptr<_impl::History> _create_history_read() = 0; + + /// Returns false by default, but must return true if, and only if this + /// history object represents a session participant that is a sync + /// agent. This is used to enforce the "maximum one sync agent per session" + /// constraint. + virtual bool is_sync_agent() const noexcept; + + template + void set(const Table*, ColKey col_key, ObjKey key, T value, _impl::Instruction variant); + + ~Replication() override; + +protected: + DB* m_db = nullptr; + Replication(_impl::TransactLogStream& stream); + + void register_db(DB* owner) + { + m_db = owner; + } + + //@{ + + /// do_initiate_transact() is called by initiate_transact(), and likewise + /// for do_prepare_commit), do_finalize_commit(), and do_abort_transact(). + /// + /// With respect to exception safety, the Replication implementation has two + /// options: It can prepare to accept the accumulated changeset in + /// do_prepapre_commit() by allocating all required resources, and delay the + /// actual acceptance to do_finalize_commit(), which requires that the final + /// acceptance can be done without any risk of failure. Alternatively, the + /// Replication implementation can fully accept the changeset in + /// do_prepapre_commit() (allowing for failure), and then discard that + /// changeset during the next invocation of do_initiate_transact() if + /// `current_version` indicates that the previous transaction failed. + + virtual void do_initiate_transact(Group& group, version_type current_version, bool history_updated) = 0; + virtual version_type do_prepare_commit(version_type orig_version) = 0; + virtual void do_finalize_commit() noexcept = 0; + virtual void do_abort_transact() noexcept = 0; + + //@} + + + virtual void do_interrupt() noexcept = 0; + + virtual void do_clear_interrupt() noexcept = 0; + + friend class _impl::TransactReverser; + friend class DB; +}; + +class Replication::Interrupted : public std::exception { +public: + const char* what() const noexcept override + { + return "Interrupted"; + } +}; + + +class TrivialReplication : public Replication { +public: + ~TrivialReplication() noexcept + { + } + + std::string get_database_path() const override; + +protected: + typedef Replication::version_type version_type; + + TrivialReplication(const std::string& database_file); + + virtual version_type prepare_changeset(const char* data, size_t size, version_type orig_version) = 0; + virtual void finalize_changeset() noexcept = 0; + + BinaryData get_uncommitted_changes() const noexcept override; + + void initialize(DB&) override; + void do_initiate_transact(Group& group, version_type, bool) override; + version_type do_prepare_commit(version_type orig_version) override; + void do_finalize_commit() noexcept override; + void do_abort_transact() noexcept override; + void do_interrupt() noexcept override; + void do_clear_interrupt() noexcept override; + +private: + const std::string m_database_file; + _impl::TransactLogBufferStream m_stream; + + size_t transact_log_size(); +}; + + +// Implementation: + +inline Replication::Replication(_impl::TransactLogStream& stream) + : _impl::TransactLogConvenientEncoder(stream) +{ +} + +inline void Replication::initiate_transact(Group& group, version_type current_version, bool history_updated) +{ + if (auto hist = _get_history_write()) { + hist->set_group(&group, history_updated); + } + do_initiate_transact(group, current_version, history_updated); + reset_selection_caches(); +} + +inline Replication::version_type Replication::prepare_commit(version_type orig_version) +{ + return do_prepare_commit(orig_version); +} + +inline void Replication::finalize_commit() noexcept +{ + do_finalize_commit(); +} + +inline void Replication::abort_transact() noexcept +{ + do_abort_transact(); +} + +inline void Replication::interrupt() noexcept +{ + do_interrupt(); +} + +inline void Replication::clear_interrupt() noexcept +{ + do_clear_interrupt(); +} + +inline bool Replication::is_sync_agent() const noexcept +{ + return false; +} + +template <> +inline void Replication::set(const Table* table, ColKey col_key, ObjKey key, StringData value, + _impl::Instruction variant) +{ + set_string(table, col_key, key, value, variant); +} + +template <> +inline void Replication::set(const Table* table, ColKey col_key, ObjKey key, BinaryData value, + _impl::Instruction variant) +{ + set_binary(table, col_key, key, value, variant); +} + +template <> +inline void Replication::set(const Table* table, ColKey col_key, ObjKey key, Timestamp value, + _impl::Instruction variant) +{ + if (value.is_null()) { + set_null(table, col_key, key, variant); + } + else { + set_timestamp(table, col_key, key, value, variant); + } +} + +template <> +inline void Replication::set(const Table* table, ColKey col_key, ObjKey key, ObjectId value, + _impl::Instruction variant) +{ + set_object_id(table, col_key, key, value, variant); +} + +template <> +inline void Replication::set(const Table* table, ColKey col_key, ObjKey key, bool value, _impl::Instruction variant) +{ + set_bool(table, col_key, key, value, variant); +} + +template <> +inline void Replication::set(const Table* table, ColKey col_key, ObjKey key, float value, _impl::Instruction variant) +{ + set_float(table, col_key, key, value, variant); +} + +template <> +inline void Replication::set(const Table* table, ColKey col_key, ObjKey key, double value, _impl::Instruction variant) +{ + set_double(table, col_key, key, value, variant); +} + +template <> +inline void Replication::set(const Table* table, ColKey col_key, ObjKey key, Decimal128 value, + _impl::Instruction variant) +{ + if (value.is_null()) { + set_null(table, col_key, key, variant); + } + else { + set_decimal(table, col_key, key, value, variant); + } +} + +template <> +inline void Replication::set(const Table* table, ColKey col_key, ObjKey key, ObjKey target_key, + _impl::Instruction variant) +{ + if (target_key) { + set_link(table, col_key, key, target_key, variant); + } + else { + nullify_link(table, col_key, key); + } +} + +template <> +void Replication::set(const Table* table, ColKey col_key, ObjKey key, Mixed value, _impl::Instruction variant); + +inline TrivialReplication::TrivialReplication(const std::string& database_file) + : Replication(m_stream) + , m_database_file(database_file) +{ +} + +inline BinaryData TrivialReplication::get_uncommitted_changes() const noexcept +{ + const char* data = m_stream.get_data(); + size_t size = write_position() - data; + return BinaryData(data, size); +} + +inline size_t TrivialReplication::transact_log_size() +{ + return write_position() - m_stream.get_data(); +} + +} // namespace realm + +#endif // REALM_REPLICATION_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sort_descriptor.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sort_descriptor.hpp new file mode 100644 index 0000000..874ec92 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sort_descriptor.hpp @@ -0,0 +1,341 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_SORT_DESCRIPTOR_HPP +#define REALM_SORT_DESCRIPTOR_HPP + +#include +#include +#include +#include + +namespace realm { + +class SortDescriptor; +class ConstTableRef; +class Group; + +enum class DescriptorType { Sort, Distinct, Limit, Include }; + +struct LinkPathPart { + // Constructor for forward links + LinkPathPart(ColKey col_key) + : column_key(col_key) + { + } + // Constructor for backward links. Source table must be a valid table. + LinkPathPart(ColKey col_key, ConstTableRef source); + // Each step in the path can be a forward or a backward link. + // In case of a backlink, the column_key indicates the origin link column + // (the forward link column in the origin table), not the backlink column + // itself. + ColKey column_key; + // "from" is omitted to indicate forward links, if it is valid then + // this path describes a backlink originating from the column from[column_key] + TableKey from; +}; + +class BaseDescriptor { +public: + struct IndexPair { + IndexPair(ObjKey k, size_t i) + : key_for_object(k) + , index_in_view(i) + { + } + bool operator<(const IndexPair& other) const + { + return index_in_view < other.index_in_view; + } + ObjKey key_for_object; + size_t index_in_view; + Mixed cached_value; + }; + class IndexPairs : public std::vector { + public: + size_t m_removed_by_limit = 0; + }; + class Sorter { + public: + Sorter(std::vector> const& columns, std::vector const& ascending, + Table const& root_table, const IndexPairs& indexes); + Sorter() + { + } + + bool operator()(IndexPair i, IndexPair j, bool total_ordering = true) const; + + bool has_links() const + { + return std::any_of(m_columns.begin(), m_columns.end(), + [](auto&& col) { return !col.translated_keys.empty(); }); + } + + bool any_is_null(IndexPair i) const + { + return std::any_of(m_columns.begin(), m_columns.end(), [=](auto&& col) { + return col.is_null.empty() ? false : col.is_null[i.index_in_view]; + }); + } + void cache_first_column(IndexPairs& v); + + private: + struct SortColumn { + SortColumn(const Table* t, ColKey c, bool a) + : table(t) + , col_key(c) + , ascending(a) + { + } + std::vector is_null; + std::vector translated_keys; + + const Table* table; + ColKey col_key; + bool ascending; + }; + std::vector m_columns; + friend class ObjList; + }; + + BaseDescriptor() = default; + virtual ~BaseDescriptor() = default; + virtual bool is_valid() const noexcept = 0; + virtual std::string get_description(ConstTableRef attached_table) const = 0; + virtual std::unique_ptr clone() const = 0; + virtual DescriptorType get_type() const = 0; + virtual void collect_dependencies(const Table* table, std::vector& table_keys) const = 0; + virtual Sorter sorter(Table const& table, const IndexPairs& indexes) const = 0; + // Do what you have to do + virtual void execute(IndexPairs& v, const Sorter& predicate, const BaseDescriptor* next) const = 0; +}; + + +// ColumnsDescriptor encapsulates a reference to a set of columns (possibly over +// links), which is used to indicate the criteria columns for sort and distinct. +class ColumnsDescriptor : public BaseDescriptor { +public: + ColumnsDescriptor() = default; + + // Create a descriptor for the given columns on the given table. + // Each vector in `column_keys` represents a chain of columns, where + // all but the last are Link columns (n.b.: LinkList and Backlink are not + // supported), and the final is any column type that can be sorted on. + // `column_keys` must be non-empty, and each vector within it must also + // be non-empty. + ColumnsDescriptor(std::vector> column_keys); + + // returns whether this descriptor is valid and can be used for sort or distinct + bool is_valid() const noexcept override + { + return !m_column_keys.empty(); + } + void collect_dependencies(const Table* table, std::vector& table_keys) const override; + +protected: + std::vector> m_column_keys; +}; + +class DistinctDescriptor : public ColumnsDescriptor { +public: + DistinctDescriptor() = default; + DistinctDescriptor(std::vector> column_keys) + : ColumnsDescriptor(column_keys) + { + } + + std::unique_ptr clone() const override; + + DescriptorType get_type() const override + { + return DescriptorType::Distinct; + } + + Sorter sorter(Table const& table, const IndexPairs& indexes) const override; + void execute(IndexPairs& v, const Sorter& predicate, const BaseDescriptor* next) const override; + + std::string get_description(ConstTableRef attached_table) const override; +}; + + +class SortDescriptor : public ColumnsDescriptor { +public: + // Create a sort descriptor for the given columns on the given table. + // See ColumnsDescriptor for restrictions on `column_keys`. + // The sort order can be specified by using `ascending` which must either be + // empty or have one entry for each column index chain. + SortDescriptor(std::vector> column_indices, std::vector ascending = {}); + SortDescriptor() = default; + ~SortDescriptor() = default; + std::unique_ptr clone() const override; + + DescriptorType get_type() const override + { + return DescriptorType::Sort; + } + + util::Optional is_ascending(size_t ndx) const + { + if (ndx < m_ascending.size()) { + return util::Optional(m_ascending[ndx]); + } + return util::none; + } + + enum class MergeMode { + /// If another sort has just been applied, merge before it, so it takes primary precedence + /// this is used for time based scenarios where building the last applied sort is the most important + /// default historical behaviour + append, + /// If another sort has just been applied, merge after it to take secondary precedence + /// this is used to construct sorts in a builder pattern where the first applied sort remains the most + /// important + prepend, + /// Replace this sort descriptor with another + replace + }; + + void merge(SortDescriptor&& other, MergeMode mode); + + Sorter sorter(Table const& table, const IndexPairs& indexes) const override; + + void execute(IndexPairs& v, const Sorter& predicate, const BaseDescriptor* next) const override; + + std::string get_description(ConstTableRef attached_table) const override; + +private: + std::vector m_ascending; +}; + +class LimitDescriptor : public BaseDescriptor { +public: + LimitDescriptor(size_t limit) + : m_limit(limit) + { + } + LimitDescriptor() = default; + ~LimitDescriptor() = default; + + bool is_valid() const noexcept override + { + return m_limit != size_t(-1); + } + std::string get_description(ConstTableRef attached_table) const override; + std::unique_ptr clone() const override; + size_t get_limit() const noexcept + { + return m_limit; + } + + DescriptorType get_type() const override + { + return DescriptorType::Limit; + } + + Sorter sorter(Table const&, const IndexPairs&) const override + { + return Sorter(); + } + + void collect_dependencies(const Table*, std::vector&) const override + { + } + void execute(IndexPairs& v, const Sorter& predicate, const BaseDescriptor* next) const override; + +private: + size_t m_limit = size_t(-1); +}; + +class IncludeDescriptor : public ColumnsDescriptor { +public: + IncludeDescriptor() = default; + // This constructor may throw an InvalidPathError exception if the path is not valid. + // A valid path consists of any number of connected link/list/backlink paths and always ends with a backlink + // column. + IncludeDescriptor(ConstTableRef table, const std::vector>& link_paths); + ~IncludeDescriptor() = default; + std::string get_description(ConstTableRef attached_table) const override; + std::unique_ptr clone() const override; + DescriptorType get_type() const override + { + return DescriptorType::Include; + } + void append(const IncludeDescriptor& other); + void report_included_backlinks( + ConstTableRef origin, ObjKey object, + util::FunctionRef&)> reporter) const; + + Sorter sorter(Table const&, const IndexPairs&) const override + { + return Sorter(); + } + + void collect_dependencies(const Table*, std::vector&) const override + { + } + void execute(IndexPairs& v, const Sorter& predicate, const BaseDescriptor* next) const override; + +private: + std::vector> m_backlink_sources; // stores a default TableKey for non-backlink columns +}; + + +class DescriptorOrdering { +public: + DescriptorOrdering() = default; + DescriptorOrdering(const DescriptorOrdering&); + DescriptorOrdering(DescriptorOrdering&&) = default; + DescriptorOrdering& operator=(const DescriptorOrdering&); + DescriptorOrdering& operator=(DescriptorOrdering&&) = default; + + void append_sort(SortDescriptor sort, SortDescriptor::MergeMode mode = SortDescriptor::MergeMode::prepend); + void append_distinct(DistinctDescriptor distinct); + void append_limit(LimitDescriptor limit); + void append_include(IncludeDescriptor include); + realm::util::Optional get_min_limit() const; + /// Remove all LIMIT statements from this descriptor ordering, returning the + /// minimum LIMIT value that existed. If there was no LIMIT statement, + /// returns `none`. + util::Optional remove_all_limits(); + bool will_limit_to_zero() const; + DescriptorType get_type(size_t index) const; + bool is_empty() const + { + return m_descriptors.empty(); + } + size_t size() const + { + return m_descriptors.size(); + } + const BaseDescriptor* operator[](size_t ndx) const; + bool will_apply_sort() const; + bool will_apply_distinct() const; + bool will_apply_limit() const; + bool will_apply_include() const; + std::string get_description(ConstTableRef target_table) const; + IncludeDescriptor compile_included_backlinks() const; + void collect_dependencies(const Table* table); + void get_versions(const Group* group, TableVersions& versions) const; + +private: + std::vector> m_descriptors; + std::vector m_dependencies; +}; +} + +#endif /* REALM_SORT_DESCRIPTOR_HPP */ diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/spec.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/spec.hpp new file mode 100644 index 0000000..0ebf4fb --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/spec.hpp @@ -0,0 +1,268 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_SPEC_HPP +#define REALM_SPEC_HPP + +#include +#include +#include +#include +#include +#include + +namespace realm { + +class Table; +class Group; + +class Spec { +public: + ~Spec() noexcept; + + Allocator& get_alloc() const noexcept; + + // insert column at index + void insert_column(size_t column_ndx, ColKey column_key, ColumnType type, StringData name, + int attr = col_attr_None); + ColKey get_key(size_t column_ndx) const; + void rename_column(size_t column_ndx, StringData new_name); + + /// Erase the column at the specified index. + /// + /// This function is guaranteed to *never* throw if the spec is + /// used in a non-transactional context, or if the spec has + /// already been successfully modified within the current write + /// transaction. + void erase_column(size_t column_ndx); + + // Column info + size_t get_column_count() const noexcept; + size_t get_public_column_count() const noexcept; + DataType get_public_column_type(size_t column_ndx) const noexcept; + ColumnType get_column_type(size_t column_ndx) const noexcept; + StringData get_column_name(size_t column_ndx) const noexcept; + + /// Returns size_t(-1) if the specified column is not found. + size_t get_column_index(StringData name) const noexcept; + + // Column Attributes + ColumnAttrMask get_column_attr(size_t column_ndx) const noexcept; + + // Auto Enumerated string columns + void upgrade_string_to_enum(size_t column_ndx, ref_type keys_ref); + size_t _get_enumkeys_ndx(size_t column_ndx) const noexcept; + bool is_string_enum_type(size_t column_ndx) const noexcept; + ref_type get_enumkeys_ref(size_t column_ndx, ArrayParent*& keys_parent) noexcept; + + //@{ + /// Compare two table specs for equality. + bool operator==(const Spec&) const noexcept; + bool operator!=(const Spec&) const noexcept; + //@} + + void detach() noexcept; + void destroy() noexcept; + + size_t get_ndx_in_parent() const noexcept; + void set_ndx_in_parent(size_t) noexcept; + + void verify() const; + +private: + // Underlying array structure. + // + // `m_subspecs` contains one entry for each subtable column, one entry for + // each link or link list columns, two entries for each backlink column, and + // zero entries for all other column types. For subtable columns the entry + // is a ref pointing to the subtable spec, for link and link list columns it + // is the group-level table index of the target table, and for backlink + // columns the first entry is the group-level table index of the origin + // table, and the second entry is the index of the origin column in the + // origin table. + Array m_top; + Array m_types; // 1st slot in m_top + ArrayStringShort m_names; // 2nd slot in m_top + Array m_attr; // 3rd slot in m_top + Array m_oldsubspecs; // 4th slot in m_top + Array m_enumkeys; // 5th slot in m_top + Array m_keys; // 6th slot in m_top + size_t m_num_public_columns; + + Spec(Allocator&) noexcept; // Unattached + + bool init(ref_type) noexcept; + void init(MemRef) noexcept; + void update_internals() noexcept; + + // Returns true in case the ref has changed. + bool init_from_parent() noexcept; + + ref_type get_ref() const noexcept; + + /// Called in the context of Group::commit() to ensure that + /// attached table accessors stay valid across a commit. Please + /// note that this works only for non-transactional commits. Table + /// accessors obtained during a transaction are always detached + /// when the transaction ends. + bool update_from_parent(size_t old_baseline) noexcept; + + void set_parent(ArrayParent*, size_t ndx_in_parent) noexcept; + + void set_column_attr(size_t column_ndx, ColumnAttrMask attr); + + // Migration + bool convert_column_attributes(); + bool convert_column_keys(TableKey table_key); + void fix_column_keys(TableKey table_key); + bool has_subspec() + { + return m_oldsubspecs.is_attached(); + } + void destroy_subspec() + { + m_oldsubspecs.destroy(); + m_top.set(3, 0); + } + TableKey get_opposite_link_table_key(size_t column_ndx) const noexcept; + size_t get_origin_column_ndx(size_t backlink_col_ndx) const noexcept; + ColKey find_backlink_column(TableKey origin_table_key, size_t spec_ndx) const noexcept; + + + // Generate a column key only from state in the spec. + ColKey update_colkey(ColKey existing_key, size_t spec_ndx, TableKey table_key); + /// Construct an empty spec and return just the reference to the + /// underlying memory. + static MemRef create_empty_spec(Allocator&); + + size_t get_subspec_ndx(size_t column_ndx) const noexcept; + + friend class Group; + friend class Table; +}; + +// Implementation: + +inline Allocator& Spec::get_alloc() const noexcept +{ + return m_top.get_alloc(); +} + +// Uninitialized Spec (call init() to init) +inline Spec::Spec(Allocator& alloc) noexcept + : m_top(alloc) + , m_types(alloc) + , m_names(alloc) + , m_attr(alloc) + , m_oldsubspecs(alloc) + , m_enumkeys(alloc) + , m_keys(alloc) +{ +} + +inline bool Spec::init_from_parent() noexcept +{ + ref_type ref = m_top.get_ref_from_parent(); + return init(ref); +} + +inline void Spec::destroy() noexcept +{ + m_top.destroy_deep(); +} + +inline size_t Spec::get_ndx_in_parent() const noexcept +{ + return m_top.get_ndx_in_parent(); +} + +inline void Spec::set_ndx_in_parent(size_t ndx) noexcept +{ + m_top.set_ndx_in_parent(ndx); +} + +inline ref_type Spec::get_ref() const noexcept +{ + return m_top.get_ref(); +} + +inline void Spec::set_parent(ArrayParent* parent, size_t ndx_in_parent) noexcept +{ + m_top.set_parent(parent, ndx_in_parent); +} + +inline void Spec::rename_column(size_t column_ndx, StringData new_name) +{ + REALM_ASSERT(column_ndx < m_types.size()); + m_names.set(column_ndx, new_name); +} + +inline size_t Spec::get_column_count() const noexcept +{ + // This is the total count of columns, including backlinks (not public) + return m_types.size(); +} + +inline size_t Spec::get_public_column_count() const noexcept +{ + return m_num_public_columns; +} + +inline ColumnType Spec::get_column_type(size_t ndx) const noexcept +{ + REALM_ASSERT(ndx < get_column_count()); + ColumnType type = ColumnType(m_types.get(ndx)); + return type; +} + +inline ColumnAttrMask Spec::get_column_attr(size_t ndx) const noexcept +{ + REALM_ASSERT(ndx < get_column_count()); + return ColumnAttrMask(m_attr.get(ndx)); +} + +inline void Spec::set_column_attr(size_t column_ndx, ColumnAttrMask attr) +{ + REALM_ASSERT(column_ndx < get_column_count()); + + // At this point we only allow one attr at a time + // so setting it will overwrite existing. In the future + // we will allow combinations. + m_attr.set(column_ndx, attr.m_value); + + update_internals(); +} + +inline StringData Spec::get_column_name(size_t ndx) const noexcept +{ + return m_names.get(ndx); +} + +inline size_t Spec::get_column_index(StringData name) const noexcept +{ + return m_names.find_first(name); +} + +inline bool Spec::operator!=(const Spec& s) const noexcept +{ + return !(*this == s); +} + +} // namespace realm + +#endif // REALM_SPEC_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/string_data.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/string_data.hpp new file mode 100644 index 0000000..75da9d1 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/string_data.hpp @@ -0,0 +1,413 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_STRING_HPP +#define REALM_STRING_HPP + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace realm { + +/// Selects CityHash64 on 64-bit platforms, and Murmur2 on 32-bit platforms. +/// This is what libc++ does, and it is a good general choice for a +/// non-cryptographic hash function (suitable for std::unordered_map etc.). +size_t murmur2_or_cityhash(const unsigned char* data, size_t len) noexcept; + +uint_least32_t murmur2_32(const unsigned char* data, size_t len) noexcept; +uint_least64_t cityhash_64(const unsigned char* data, size_t len) noexcept; + + +/// A reference to a chunk of character data. +/// +/// An instance of this class can be thought of as a type tag on a region of +/// memory. It does not own the referenced memory, nor does it in any other way +/// attempt to manage the lifetime of it. +/// +/// A null character inside the referenced region is considered a part of the +/// string by Realm. +/// +/// For compatibility with C-style strings, when a string is stored in a Realm +/// database, it is always followed by a terminating null character, regardless +/// of whether the string itself has internal null characters. This means that +/// when a StringData object is extracted from Realm, the referenced region is +/// guaranteed to be followed immediately by an extra null character, but that +/// null character is not inside the referenced region. Therefore, all of the +/// following forms are guaranteed to return a pointer to a null-terminated +/// string: +/// +/// \code{.cpp} +/// +/// group.get_table_name(...).data() +/// table.get_column_name().data() +/// table.get_string(...).data() +/// table.get_mixed(...).get_string().data() +/// +/// \endcode +/// +/// Note that in general, no assumptions can be made about what follows a string +/// that is referenced by a StringData object, or whether anything follows it at +/// all. In particular, the receiver of a StringData object cannot assume that +/// the referenced string is followed by a null character unless there is an +/// externally provided guarantee. +/// +/// This class makes it possible to distinguish between a 'null' reference and a +/// reference to the empty string (see is_null()). +/// +/// \sa BinaryData +/// \sa Mixed +class StringData { +public: + /// Construct a null reference. + StringData() noexcept; + + StringData(int) = delete; + + /// If \a external_data is 'null', \a data_size must be zero. + StringData(const char* external_data, size_t data_size) noexcept; + + template + StringData(const std::basic_string&); + + template + operator std::basic_string() const; + + template + StringData(const util::Optional>&); + + StringData(const null&) noexcept; + + /// Initialize from a zero terminated C style string. Pass null to construct + /// a null reference. + StringData(const char* c_str) noexcept; + + char operator[](size_t i) const noexcept; + + const char* data() const noexcept; + size_t size() const noexcept; + + /// Is this a null reference? + /// + /// An instance of StringData is a null reference when, and only when the + /// stored size is zero (size()) and the stored pointer is the null pointer + /// (data()). + /// + /// In the case of the empty string, the stored size is still zero, but the + /// stored pointer is **not** the null pointer. It could for example point + /// to the empty string literal. Note that the actual value of the pointer + /// is immaterial in this case (as long as it is not zero), because when the + /// size is zero, it is an error to dereference the pointer. + /// + /// Conversion of a StringData object to `bool` yields the logical negation + /// of the result of calling this function. In other words, a StringData + /// object is converted to true if it is not the null reference, otherwise + /// it is converted to false. + bool is_null() const noexcept; + + friend bool operator==(const StringData&, const StringData&) noexcept; + friend bool operator!=(const StringData&, const StringData&) noexcept; + + //@{ + /// Trivial bytewise lexicographical comparison. + friend bool operator<(const StringData&, const StringData&) noexcept; + friend bool operator>(const StringData&, const StringData&) noexcept; + friend bool operator<=(const StringData&, const StringData&) noexcept; + friend bool operator>=(const StringData&, const StringData&) noexcept; + //@} + + bool begins_with(StringData) const noexcept; + bool ends_with(StringData) const noexcept; + bool contains(StringData) const noexcept; + bool contains(StringData d, const std::array &charmap) const noexcept; + + // Wildcard matching ('?' for single char, '*' for zero or more chars) + // case insensitive version in unicode.hpp + bool like(StringData) const noexcept; + + //@{ + /// Undefined behavior if \a n, \a i, or i+n is greater than + /// size(). + StringData prefix(size_t n) const noexcept; + StringData suffix(size_t n) const noexcept; + StringData substr(size_t i, size_t n) const noexcept; + StringData substr(size_t i) const noexcept; + //@} + + template + friend std::basic_ostream& operator<<(std::basic_ostream&, const StringData&); + + explicit operator bool() const noexcept; + + /// If the StringData is NULL, the hash is 0. Otherwise, the function + /// `murmur2_or_cityhash()` is called on the data. + size_t hash() const noexcept; + +private: + const char* m_data; + size_t m_size; + + static bool matchlike(const StringData& text, const StringData& pattern) noexcept; + static bool matchlike_ins(const StringData& text, const StringData& pattern_upper, + const StringData& pattern_lower) noexcept; + + friend bool string_like_ins(StringData, StringData) noexcept; + friend bool string_like_ins(StringData, StringData, StringData) noexcept; +}; + + +// Implementation: + +inline StringData::StringData() noexcept + : m_data(nullptr) + , m_size(0) +{ +} + +inline StringData::StringData(const char* external_data, size_t data_size) noexcept + : m_data(external_data) + , m_size(data_size) +{ + REALM_ASSERT_DEBUG(external_data || data_size == 0); +} + +template +inline StringData::StringData(const std::basic_string& s) + : m_data(s.data()) + , m_size(s.size()) +{ +} + +template +inline StringData::operator std::basic_string() const +{ + return std::basic_string(m_data, m_size); +} + +template +inline StringData::StringData(const util::Optional>& s) + : m_data(s ? s->data() : nullptr) + , m_size(s ? s->size() : 0) +{ +} + +inline StringData::StringData(const null&) noexcept + : m_data(nullptr) + , m_size(0) +{ +} + +inline StringData::StringData(const char* c_str) noexcept + : m_data(c_str) + , m_size(0) +{ + if (c_str) + m_size = std::char_traits::length(c_str); +} + +inline char StringData::operator[](size_t i) const noexcept +{ + return m_data[i]; +} + +inline const char* StringData::data() const noexcept +{ + return m_data; +} + +inline size_t StringData::size() const noexcept +{ + return m_size; +} + +inline bool StringData::is_null() const noexcept +{ + return !m_data; +} + +inline bool operator==(const StringData& a, const StringData& b) noexcept +{ + return a.m_size == b.m_size && a.is_null() == b.is_null() && safe_equal(a.m_data, a.m_data + a.m_size, b.m_data); +} + +inline bool operator!=(const StringData& a, const StringData& b) noexcept +{ + return !(a == b); +} + +inline bool operator<(const StringData& a, const StringData& b) noexcept +{ + if (a.is_null() && !b.is_null()) { + // Null strings are smaller than all other strings, and not + // equal to empty strings. + return true; + } + return std::lexicographical_compare(a.m_data, a.m_data + a.m_size, b.m_data, b.m_data + b.m_size); +} + +inline bool operator>(const StringData& a, const StringData& b) noexcept +{ + return b < a; +} + +inline bool operator<=(const StringData& a, const StringData& b) noexcept +{ + return !(b < a); +} + +inline bool operator>=(const StringData& a, const StringData& b) noexcept +{ + return !(a < b); +} + +inline bool StringData::begins_with(StringData d) const noexcept +{ + if (is_null() && !d.is_null()) + return false; + return d.m_size <= m_size && safe_equal(m_data, m_data + d.m_size, d.m_data); +} + +inline bool StringData::ends_with(StringData d) const noexcept +{ + if (is_null() && !d.is_null()) + return false; + return d.m_size <= m_size && safe_equal(m_data + m_size - d.m_size, m_data + m_size, d.m_data); +} + +inline bool StringData::contains(StringData d) const noexcept +{ + if (is_null() && !d.is_null()) + return false; + + return d.m_size == 0 || std::search(m_data, m_data + m_size, d.m_data, d.m_data + d.m_size) != m_data + m_size; +} + +/// This method takes an array that maps chars to distance that can be moved (and zero for chars not in needle), +/// allowing the method to apply Boyer-Moore for quick substring search +/// The map is calculated in the StringNode class (so it can be reused across searches) +inline bool StringData::contains(StringData d, const std::array &charmap) const noexcept +{ + if (is_null() && !d.is_null()) + return false; + + size_t needle_size = d.size(); + if (needle_size == 0) + return true; + + // Prepare vars to avoid lookups in loop + size_t last_char_pos = d.size()-1; + unsigned char lastChar = d[last_char_pos]; + + // Do Boyer-Moore search + size_t p = last_char_pos; + while (p < m_size) { + unsigned char c = m_data[p]; // Get candidate for last char + + if (c == lastChar) { + StringData candidate = substr(p-needle_size+1, needle_size); + if (candidate == d) + return true; // text found! + } + + // If we don't have a match, see how far we can move char_pos + if (charmap[c] == 0) + p += needle_size; // char was not present in search string + else + p += charmap[c]; + } + + return false; +} + +inline bool StringData::like(StringData d) const noexcept +{ + if (is_null() || d.is_null()) { + return (is_null() && d.is_null()); + } + + return matchlike(*this, d); +} + +inline StringData StringData::prefix(size_t n) const noexcept +{ + return substr(0, n); +} + +inline StringData StringData::suffix(size_t n) const noexcept +{ + return substr(m_size - n); +} + +inline StringData StringData::substr(size_t i, size_t n) const noexcept +{ + return StringData(m_data + i, n); +} + +inline StringData StringData::substr(size_t i) const noexcept +{ + return substr(i, m_size - i); +} + +template +inline std::basic_ostream& operator<<(std::basic_ostream& out, const StringData& d) +{ + if (d.is_null()) { + out << ""; + } + else { + for (const char* i = d.m_data; i != d.m_data + d.m_size; ++i) + out << *i; + } + return out; +} + +inline StringData::operator bool() const noexcept +{ + return !is_null(); +} + +inline size_t StringData::hash() const noexcept +{ + if (is_null()) + return 0; + auto unsigned_data = reinterpret_cast(m_data); + return murmur2_or_cityhash(unsigned_data, m_size); +} + +} // namespace realm + +namespace std { +template <> +struct hash<::realm::StringData> { + inline size_t operator()(const ::realm::StringData& str) const noexcept + { + return str.hash(); + } +}; +} // namespace std + +#endif // REALM_STRING_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/changeset.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/changeset.hpp new file mode 100644 index 0000000..338b692 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/changeset.hpp @@ -0,0 +1,623 @@ + +#ifndef REALM_SYNC_CHANGESET_HPP +#define REALM_SYNC_CHANGESET_HPP + +#include +#include +#include +#include + +#include + +namespace realm { +namespace sync { + +using InternStrings = util::metered::vector; + +struct BadChangesetError : ExceptionWithBacktrace { + using ExceptionWithBacktrace::ExceptionWithBacktrace; +}; + +struct Changeset { + struct Range; + using timestamp_type = uint_fast64_t; + using file_ident_type = uint_fast64_t; + using version_type = uint_fast64_t; // FIXME: Get from `History`. + using StringBuffer = util::BasicStringBuffer; + + Changeset(); + struct share_buffers_tag { + }; + Changeset(const Changeset&, share_buffers_tag); + Changeset(Changeset&&) = default; + Changeset& operator=(Changeset&&) = default; + Changeset(const Changeset&) = delete; + Changeset& operator=(const Changeset&) = delete; + + InternString intern_string(StringData); // Slow! + InternString find_string(StringData) const noexcept; // Slow! + StringData string_data() const noexcept; + + StringBuffer& string_buffer() noexcept; + const StringBuffer& string_buffer() const noexcept; + const InternStrings& interned_strings() const noexcept; + InternStrings& interned_strings() noexcept; + + StringBufferRange get_intern_string(InternString) const noexcept; + util::Optional try_get_intern_string(InternString) const noexcept; + util::Optional try_get_string(StringBufferRange) const noexcept; + util::Optional try_get_string(InternString) const noexcept; + StringData get_string(StringBufferRange) const noexcept; + StringData get_string(InternString) const noexcept; + StringBufferRange append_string(StringData); + + PrimaryKey get_key(const Instruction::PrimaryKey& value) const noexcept; + std::ostream& print_value(std::ostream& os, const Instruction::Payload& value) const noexcept; + std::ostream& print_path(std::ostream& os, const Instruction::Path& value) const noexcept; + + /// Mark the changeset as "dirty" (i.e. modified by the merge algorithm). + void set_dirty(bool dirty = true) noexcept; + + /// Whether or not the changeset is "dirty" (i.e. has been modified by the + /// merge algorithm). + bool is_dirty() const noexcept; + + // Interface to imitate std::vector: + template + struct IteratorImpl; + using iterator = IteratorImpl; + using const_iterator = IteratorImpl; + using value_type = Instruction; + iterator begin() noexcept; + iterator end() noexcept; + const_iterator begin() const noexcept; + const_iterator end() const noexcept; + const_iterator cbegin() const noexcept; + const_iterator cend() const noexcept; + bool empty() const noexcept; + + /// Size of the Changeset, not counting tombstones. + /// + /// FIXME: This is an O(n) operation. + size_t size() const noexcept; + + void clear() noexcept; + + //@{ + /// Insert instructions, invalidating all iterators. + iterator insert(const_iterator pos, Instruction); + template + iterator insert(const_iterator pos, InputIt begin, InputIt end); + //@} + + /// Erase an instruction, invalidating all iterators. + iterator erase(const_iterator); + + /// Insert an instruction at the end, invalidating all iterators. + void push_back(const Instruction&); + + //@{ + /// Insert instructions at \a position without invalidating other + /// iterators. + /// + /// Only iterators created before any call to `insert_stable()` may be + /// considered stable across calls to `insert_stable()`. In addition, + /// "iterator stability" has a very specific meaning here: Other copies of + /// \a position in the program will point to the newly inserted elements + /// after calling `insert_stable()`, rather than point to the value at the + /// position prior to insertion. This is different from, say, a tree + /// structure, where iterator stability signifies the property that + /// iterators keep pointing to the same element after insertion before or + /// after that position. + /// + /// For the purpose of supporting `ChangesetIndex`, and the OT merge + /// algorithm, these semantics are acceptable, since prepended instructions + /// can never create new object or table references. + iterator insert_stable(const_iterator position, Instruction); + template + iterator insert_stable(const_iterator position, InputIt begin, InputIt end); + //@} + + /// Erase instruction at \a position without invalidating other iterators. + /// If erasing the object would invalidate other iterators, it is turned + /// into a tombstone instead, and subsequent derefencing of the iterator + /// will return `nullptr`. An iterator pointing to a tombstone remains valid + /// and can be incremented. + /// + /// Only iterators created before any call to `insert_stable()` may be + /// considered stable across calls to `erase_stable()`. If other copies of + /// \a position exist in the program, they will either point to the + /// subsequent element if that element was previously inserted with + /// `insert_stable()`, or otherwise it will be turned into a tombstone. + iterator erase_stable(const_iterator position); + +#if REALM_DEBUG + struct Reflector; + struct Printer; + void verify() const; + void print(std::ostream&) const; + void print() const; // prints to std::err +#endif + + /// The version that this changeset produced. Note: This may not be the + /// version produced by this changeset on the client on which this changeset + /// originated, but may for instance be the version produced on the server + /// after receiving and re-sending this changeset to another client. + /// + /// FIXME: The explanation above is confusing. The truth is that if this + /// changeset was received by a client from the server, then \a version is + /// the version that was produced on the server by this changeset. + /// + /// FIXME: This property, as well as \a last_integrated_remote_version, \a + /// origin_timestamp, and \a origin_file_ident should probably be removed + /// from this class, as they are not a logical part of a changeset, and also + /// are difficult to document without knowing more about what context the + /// changeset object occurs. Also, functions such as + /// InstructionApplier::apply() that a changeset as argument, but do not + /// care about those properties. + version_type version = 0; + + /// On clients, the last integrated server version. On the server, this is + /// the last integrated client version. + /// + /// FIXME: The explanation above is confusing. The truth is that if this + /// changeset was received by a client from the server, then \a + /// last_integrated_remote_version is the last client version that was + /// integrated by the server at the server version referencened by \a + /// version. + version_type last_integrated_remote_version = 0; + + /// Timestamp at origin when the original untransformed changeset was + /// produced. + timestamp_type origin_timestamp = 0; + + /// The identifier of the file in the context of which the original + /// untransformed changeset was produced. + file_ident_type origin_file_ident = 0; + + /// Compare for exact equality, including that interned strings have the + /// same integer values, and there is the same number of interned strings, + /// same topology of tombstones, etc. + bool operator==(const Changeset& that) const noexcept; + bool operator!=(const Changeset& that) const noexcept; + +private: + util::metered::vector m_instructions; + std::shared_ptr m_string_buffer; + std::shared_ptr m_strings; + bool m_is_dirty = false; + + iterator const_iterator_to_iterator(const_iterator); +}; + +std::ostream& operator<<(std::ostream&, const Changeset& changeset); + +/// An iterator type that hides the implementation details of the support for +/// iterator stability. +/// +/// A `Changeset::iterator` is composed of an +/// `std::vector::iterator` and a `size_t` representing +/// the index into the current `InstructionContainer`. If that container is +/// empty, and the position is zero, the iterator is pointing to a tombstone. +template +struct Changeset::IteratorImpl { + using list_type = util::metered::vector; + using inner_iterator_type = std::conditional_t; + + // reference_type is a pointer because we have no way to create a reference + // to a tombstone instruction. Alternatively, it could have been + // `util::Optional`, but that runs into other issues. + using reference_type = std::conditional_t; + + using pointer_type = std::conditional_t; + using difference_type = std::ptrdiff_t; + + IteratorImpl() + : m_pos(0) + { + } + template + IteratorImpl(const IteratorImpl& other, std::enable_if_t* = nullptr) + : m_inner(other.m_inner) + , m_pos(other.m_pos) + { + } + IteratorImpl(inner_iterator_type inner, size_t pos = 0) + : m_inner(inner) + , m_pos(pos) + { + } + + inline IteratorImpl& operator++() + { + ++m_pos; + if (m_pos >= m_inner->size()) { + ++m_inner; + m_pos = 0; + } + return *this; + } + + IteratorImpl operator++(int) + { + auto copy = *this; + ++(*this); + return copy; + } + + IteratorImpl& operator--() + { + if (m_pos == 0) { + --m_inner; + m_pos = m_inner->size(); + if (m_pos != 0) + --m_pos; + } + else { + --m_pos; + } + return *this; + } + + IteratorImpl operator--(int) + { + auto copy = *this; + --(*this); + return copy; + } + + reference_type operator*() const + { + if (m_inner->size()) { + return &m_inner->at(m_pos); + } + // It was a tombstone. + return nullptr; + } + + pointer_type operator->() const + { + if (m_inner->size()) { + return &m_inner->at(m_pos); + } + // It was a tombstone. + return nullptr; + } + + bool operator==(const IteratorImpl& other) const + { + return m_inner == other.m_inner && m_pos == other.m_pos; + } + + bool operator!=(const IteratorImpl& other) const + { + return !(*this == other); + } + + bool operator<(const IteratorImpl& other) const + { + if (m_inner == other.m_inner) + return m_pos < other.m_pos; + return m_inner < other.m_inner; + } + + bool operator<=(const IteratorImpl& other) const + { + if (m_inner == other.m_inner) + return m_pos <= other.m_pos; + return m_inner < other.m_inner; + } + + bool operator>(const IteratorImpl& other) const + { + if (m_inner == other.m_inner) + return m_pos > other.m_pos; + return m_inner > other.m_inner; + } + + bool operator>=(const IteratorImpl& other) const + { + if (m_inner == other.m_inner) + return m_pos >= other.m_pos; + return m_inner > other.m_inner; + } + + inner_iterator_type m_inner; + size_t m_pos; +}; + +struct Changeset::Range { + iterator begin; + iterator end; +}; + +#if REALM_DEBUG +struct Changeset::Reflector { + struct Tracer { + virtual void name(StringData) = 0; + virtual void field(StringData, InternString) = 0; + virtual void field(StringData, Instruction::Payload::Type) = 0; + virtual void field(StringData, const Instruction::PrimaryKey&) = 0; + virtual void field(StringData, const Instruction::Payload&) = 0; + virtual void field(StringData, const Instruction::Path&) = 0; + virtual void field(StringData, uint32_t) = 0; + virtual void set_changeset(const Changeset*) = 0; + virtual void after_each() {} + virtual void before_each() {} + }; + + Reflector(Tracer& tracer, const Changeset& changeset) + : m_tracer(tracer) + , m_changeset(changeset) + { + } + + void visit_all() const; + +private: + Tracer& m_tracer; + const Changeset& m_changeset; + + void table_instr(const Instruction::TableInstruction&) const; + void object_instr(const Instruction::ObjectInstruction&) const; + void path_instr(const Instruction::PathInstruction&) const; + + friend struct Instruction; +#define REALM_DEFINE_REFLECTOR_VISITOR(X) void operator()(const Instruction::X&) const; + REALM_FOR_EACH_INSTRUCTION_TYPE(REALM_DEFINE_REFLECTOR_VISITOR) +#undef REALM_DEFINE_REFLECTOR_VISITOR +}; + +struct Changeset::Printer : Changeset::Reflector::Tracer { + explicit Printer(std::ostream& os) + : m_out(os) + { + } + + // ChangesetReflector::Tracer interface: + void name(StringData) final; + void field(StringData, InternString) final; + void field(StringData, Instruction::Payload::Type) final; + void field(StringData, const Instruction::PrimaryKey&) final; + void field(StringData, const Instruction::Payload&) final; + void field(StringData, const Instruction::Path&) final; + void field(StringData, uint32_t) final; + void set_changeset(const Changeset* changeset) final + { + m_changeset = changeset; + } + void after_each() final; + +private: + std::ostream& m_out; + bool m_first = true; + const Changeset* m_changeset = nullptr; + void pad_or_ellipsis(StringData, int width) const; + void print_field(StringData name, std::string value); + + std::string primary_key_to_string(const Instruction::PrimaryKey&); +}; +#endif // REALM_DEBUG + + +/// Implementation: + +inline Changeset::iterator Changeset::begin() noexcept +{ + return m_instructions.begin(); +} + +inline Changeset::iterator Changeset::end() noexcept +{ + return m_instructions.end(); +} + +inline Changeset::const_iterator Changeset::begin() const noexcept +{ + return m_instructions.begin(); +} + +inline Changeset::const_iterator Changeset::end() const noexcept +{ + return m_instructions.end(); +} + +inline Changeset::const_iterator Changeset::cbegin() const noexcept +{ + return m_instructions.cbegin(); +} + +inline Changeset::const_iterator Changeset::cend() const noexcept +{ + return m_instructions.end(); +} + +inline bool Changeset::empty() const noexcept +{ + return size() == 0; +} + +inline size_t Changeset::size() const noexcept +{ + size_t sum = 0; + for (auto& x : m_instructions) + sum += x.size(); + return sum; +} + +inline void Changeset::clear() noexcept +{ + m_instructions.clear(); +} + +inline util::Optional Changeset::try_get_intern_string(InternString string) const noexcept +{ + if (string.value >= m_strings->size()) + return util::none; + return (*m_strings)[string.value]; +} + +inline StringBufferRange Changeset::get_intern_string(InternString string) const noexcept +{ + auto str = try_get_intern_string(string); + REALM_ASSERT(str); + return *str; +} + +inline InternStrings& Changeset::interned_strings() noexcept +{ + return *m_strings; +} + +inline const InternStrings& Changeset::interned_strings() const noexcept +{ + return *m_strings; +} + +inline auto Changeset::string_buffer() noexcept -> StringBuffer& +{ + return *m_string_buffer; +} + +inline auto Changeset::string_buffer() const noexcept -> const StringBuffer& +{ + return *m_string_buffer; +} + +inline util::Optional Changeset::try_get_string(StringBufferRange range) const noexcept +{ + if (range.offset > m_string_buffer->size()) + return util::none; + if (range.offset + range.size > m_string_buffer->size()) + return util::none; + return StringData{m_string_buffer->data() + range.offset, range.size}; +} + +inline util::Optional Changeset::try_get_string(InternString str) const noexcept +{ + if (auto range = try_get_intern_string(str)) { + return try_get_string(*range); + } + return util::none; +} + +inline StringData Changeset::get_string(StringBufferRange range) const noexcept +{ + auto string = try_get_string(range); + REALM_ASSERT(string); + return *string; +} + +inline StringData Changeset::get_string(InternString string) const noexcept +{ + return get_string(get_intern_string(string)); +} + +inline StringData Changeset::string_data() const noexcept +{ + return StringData{m_string_buffer->data(), m_string_buffer->size()}; +} + +inline StringBufferRange Changeset::append_string(StringData string) +{ + m_string_buffer->reserve(1024); // we expect more strings + size_t offset = m_string_buffer->size(); + m_string_buffer->append(string.data(), string.size()); + return StringBufferRange{uint32_t(offset), uint32_t(string.size())}; +} + +inline bool Changeset::is_dirty() const noexcept +{ + return m_is_dirty; +} + +inline void Changeset::set_dirty(bool dirty) noexcept +{ + m_is_dirty = dirty; +} + +inline Changeset::iterator Changeset::insert(const_iterator pos, Instruction instr) +{ + Instruction* p = &instr; + return insert(pos, p, p + 1); +} + +template +inline Changeset::iterator Changeset::insert(const_iterator pos, InputIt begin, InputIt end) +{ + if (pos.m_pos == 0) + return m_instructions.insert(pos.m_inner, begin, end); + return insert_stable(pos, begin, end); +} + +inline Changeset::iterator Changeset::erase(const_iterator pos) +{ + if (pos.m_inner->size() <= 1) + return m_instructions.erase(pos.m_inner); + return erase_stable(pos); +} + +inline Changeset::iterator Changeset::insert_stable(const_iterator pos, Instruction instr) +{ + Instruction* p = &instr; + return insert_stable(pos, p, p + 1); +} + +template +inline Changeset::iterator Changeset::insert_stable(const_iterator cpos, InputIt begin, InputIt end) +{ + iterator pos = const_iterator_to_iterator(cpos); + size_t i = 0; + for (auto it = begin; it != end; ++it, ++i) { + pos.m_inner->insert(pos.m_pos + i, *it); + } + return pos; +} + +inline Changeset::iterator Changeset::erase_stable(const_iterator cpos) +{ + auto pos = const_iterator_to_iterator(cpos); + auto begin = m_instructions.begin(); + auto end = m_instructions.end(); + REALM_ASSERT(pos.m_inner >= begin); + REALM_ASSERT(pos.m_inner < end); + pos.m_inner->erase(pos.m_pos); + if (pos.m_pos >= pos.m_inner->size()) { + do { + ++pos.m_inner; + } while (pos.m_inner != end && pos.m_inner->is_empty()); + pos.m_pos = 0; + } + return pos; +} + +inline void Changeset::push_back(const Instruction& instr) +{ + m_instructions.emplace_back(instr); +} + +inline auto Changeset::const_iterator_to_iterator(const_iterator cpos) -> iterator +{ + size_t offset = cpos.m_inner - m_instructions.cbegin(); + return iterator{m_instructions.begin() + offset, cpos.m_pos}; +} + +inline bool Changeset::operator!=(const Changeset& that) const noexcept +{ + return !(*this == that); +} + +} // namespace sync +} // namespace realm + +namespace std { + +template +struct iterator_traits> { + using difference_type = std::ptrdiff_t; + using iterator_category = std::bidirectional_iterator_tag; +}; + +} // namespace std + +#endif // REALM_SYNC_CHANGESET_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/changeset_cooker.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/changeset_cooker.hpp new file mode 100644 index 0000000..d911bbb --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/changeset_cooker.hpp @@ -0,0 +1,20 @@ + +#include + +#ifndef REALM_SYNC_CHANGESET_COOKER_HPP +#define REALM_SYNC_CHANGESET_COOKER_HPP + +namespace realm { +namespace sync { + +/// Copy raw changesets unmodified. +class TrivialChangesetCooker : public ClientReplication::ChangesetCooker { +public: + bool cook_changeset(const Group&, const char* changeset, std::size_t changeset_size, + util::AppendBuffer&) override; +}; + +} // namespace sync +} // namespace realm + +#endif // REALM_SYNC_CHANGESET_COOKER_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/changeset_encoder.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/changeset_encoder.hpp new file mode 100644 index 0000000..a2bc2b0 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/changeset_encoder.hpp @@ -0,0 +1,114 @@ + +#ifndef REALM_SYNC_CHANGESET_ENCODER_HPP +#define REALM_SYNC_CHANGESET_ENCODER_HPP + +#include +#include +#include + +namespace realm { +namespace sync { + +struct ChangesetEncoder : InstructionHandler { + using Buffer = util::AppendBuffer; + + Buffer release() noexcept; + void reset() noexcept; + const Buffer& buffer() const noexcept; + InternString intern_string(StringData); + + void set_intern_string(uint32_t index, StringBufferRange) override; + // FIXME: This doesn't copy the input, but the drawback is that there can + // only be a single StringBufferRange per instruction. Luckily, no + // instructions exist that require two or more. + StringBufferRange add_string_range(StringData) override; + void operator()(const Instruction&) override; + +#define REALM_DEFINE_INSTRUCTION_HANDLER(X) void operator()(const Instruction::X&); + REALM_FOR_EACH_INSTRUCTION_TYPE(REALM_DEFINE_INSTRUCTION_HANDLER) +#undef REALM_DEFINE_INSTRUCTION_HANDLER + + void encode_single(const Changeset& log); + +protected: + template + static void encode(E& encoder, const Instruction&); + + StringData get_string(StringBufferRange) const noexcept; + +private: + template + void append(Instruction::Type t, Args&&...); + template + void append_path_instr(Instruction::Type t, const Instruction::PathInstruction&, Args&&...); + void append_string(StringBufferRange); // does not intern the string + void append_bytes(const void*, size_t); + + template + void append_int(T); + void append_value(const Instruction::PrimaryKey&); + void append_value(const Instruction::Payload&); + void append_value(const Instruction::Payload::Link&); + void append_value(Instruction::Payload::Type); + void append_value(const Instruction::Path&); + void append_value(DataType); + void append_value(bool); + void append_value(uint8_t); + void append_value(int64_t); + void append_value(uint32_t); + void append_value(uint64_t); + void append_value(float); + void append_value(double); + void append_value(InternString); + void append_value(GlobalKey); + void append_value(Timestamp); + void append_value(ObjectId); + void append_value(Decimal128); + + Buffer m_buffer; + util::metered::map m_intern_strings_rev; + StringData m_string_range; +}; + +template +void encode_changeset(const Changeset&, util::AppendBuffer& out_buffer); + + +// Implementation + +inline auto ChangesetEncoder::buffer() const noexcept -> const Buffer& +{ + return m_buffer; +} + +inline void ChangesetEncoder::operator()(const Instruction& instr) +{ + encode(*this, instr); // Throws +} + +template +inline void ChangesetEncoder::encode(E& encoder, const Instruction& instr) +{ + instr.visit(encoder); // Throws +} + +inline StringData ChangesetEncoder::get_string(StringBufferRange range) const noexcept +{ + const char* data = m_string_range.data() + range.offset; + std::size_t size = std::size_t(range.size); + return StringData{data, size}; +} + +template +void encode_changeset(const Changeset& changeset, util::AppendBuffer& out_buffer) +{ + ChangesetEncoder encoder; + encoder.encode_single(changeset); // Throws + auto& buffer = encoder.buffer(); + out_buffer.append(buffer.data(), buffer.size()); // Throws +} + +} // namespace sync +} // namespace realm + +#endif // REALM_SYNC_CHANGESET_ENCODER_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/changeset_parser.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/changeset_parser.hpp new file mode 100644 index 0000000..9c21bab --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/changeset_parser.hpp @@ -0,0 +1,29 @@ + +#ifndef REALM_SYNC_CHANGESET_PARSER_HPP +#define REALM_SYNC_CHANGESET_PARSER_HPP + +#include +#include + +namespace realm { +namespace sync { + +struct ChangesetParser { + /// Throws BadChangesetError if parsing fails. + /// + /// FIXME: Consider using std::error_code instead of throwing exceptions on + /// parse errors. + void parse(_impl::NoCopyInputStream&, InstructionHandler&); + +private: + struct State; +}; + +void parse_changeset(_impl::NoCopyInputStream&, Changeset& out_log); +void parse_changeset(_impl::InputStream&, Changeset& out_log); + + +} // namespace sync +} // namespace realm + +#endif // REALM_SYNC_CHANGESET_PARSER_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/client.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/client.hpp new file mode 100644 index 0000000..c3e7001 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/client.hpp @@ -0,0 +1,1240 @@ +#ifndef REALM_SYNC_CLIENT_HPP +#define REALM_SYNC_CLIENT_HPP + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace realm { +namespace sync { + + +class Client { +public: + enum class Error; + + enum class ReconnectMode { + /// This is the mode that should always be used in production. In this + /// mode the client uses a scheme for determining a reconnect delay that + /// prevents it from creating too many connection requests in a short + /// amount of time (i.e., a server hammering protection mechanism). + normal, + + /// For testing purposes only. + /// + /// Never reconnect automatically after the connection is closed due to + /// an error. Allow immediate reconnect if the connection was closed + /// voluntarily (e.g., due to sessions being abandoned). + /// + /// In this mode, Client::cancel_reconnect_delay() and + /// Session::cancel_reconnect_delay() can still be used to trigger + /// another reconnection attempt (with no delay) after an error has + /// caused the connection to be closed. + testing + }; + + using port_type = util::network::Endpoint::port_type; + using RoundtripTimeHandler = void(milliseconds_type roundtrip_time); + + static constexpr milliseconds_type default_connect_timeout = 120000; // 2 minutes + static constexpr milliseconds_type default_connection_linger_time = 30000; // 30 seconds + static constexpr milliseconds_type default_ping_keepalive_period = 60000; // 1 minute + static constexpr milliseconds_type default_pong_keepalive_timeout = 120000; // 2 minutes + static constexpr milliseconds_type default_fast_reconnect_limit = 60000; // 1 minute + + struct Config { + Config() {} + + /// An optional custom platform description to be sent to server as part + /// of a user agent description (HTTP `User-Agent` header). + /// + /// If left empty, the platform description will be whatever is returned + /// by util::get_platform_info(). + std::string user_agent_platform_info; + + /// Optional information about the application to be added to the user + /// agent description as sent to the server. The intention is that the + /// application describes itself using the following (rough) syntax: + /// + /// ::= ( )* + /// ::= "/" [
] + /// ::= ()+ + /// ::= ( | "." | "-" | "_")* + ///
::= + /// ::= "(" ( | )* ")" + /// + /// Where `` is a single space character, `` is a decimal + /// digit, `` is any alphanumeric character, and `` is + /// any character other than `(` and `)`. + /// + /// When multiple levels are present, the innermost layer (the one that + /// is closest to this API) should appear first. + /// + /// Example: + /// + /// RealmJS/2.13.0 RealmStudio/2.9.0 + /// + /// Note: The user agent description is not intended for machine + /// interpretation, but should still follow the specified syntax such + /// that it remains easily interpretable by human beings. + std::string user_agent_application_info; + + /// The maximum number of Realm files that will be kept open + /// concurrently by this client. The client keeps a cache of open Realm + /// files for efficiency reasons. + long max_open_files = 256; + + /// An optional logger to be used by the client. If no logger is + /// specified, the client will use an instance of util::StderrLogger + /// with the log level threshold set to util::Logger::Level::info. The + /// client does not require a thread-safe logger, and it guarantees that + /// all logging happens either on behalf of the constructor or on behalf + /// of the invocation of run(). + util::Logger* logger = nullptr; + + /// Use ports 80 and 443 by default instead of 7800 and 7801 + /// respectively. Ideally, these default ports should have been made + /// available via a different URI scheme instead (http/https or ws/wss). + bool enable_default_port_hack = true; + + /// For testing purposes only. + ReconnectMode reconnect_mode = ReconnectMode::normal; + + /// Create a separate connection for each session. For testing purposes + /// only. + /// + /// FIXME: This setting needs to be true for now, due to limitations in + /// the load balancer. + bool one_connection_per_session = true; + + /// Do not access the local file system. Sessions will act as if + /// initiated on behalf of an empty (or nonexisting) local Realm + /// file. Received DOWNLOAD messages will be accepted, but otherwise + /// ignored. No UPLOAD messages will be generated. For testing purposes + /// only. + /// + /// Many operations, such as serialized transactions, are not suppored + /// in this mode. + bool dry_run = false; + + /// The default changeset cooker to be used by new sessions. Can be + /// overridden by Session::Config::changeset_cooker. + /// + /// \sa make_client_replication(), TrivialChangesetCooker. + std::shared_ptr changeset_cooker; + + /// The maximum number of milliseconds to allow for a connection to + /// become fully established. This includes the time to resolve the + /// network address, the TCP connect operation, the SSL handshake, and + /// the WebSocket handshake. + milliseconds_type connect_timeout = default_connect_timeout; + + /// The number of milliseconds to keep a connection open after all + /// sessions have been abandoned (or suspended by errors). + /// + /// The purpose of this linger time is to avoid close/reopen cycles + /// during short periods of time where there are no sessions interested + /// in using the connection. + /// + /// If the connection gets closed due to an error before the linger time + /// expires, the connection will be kept closed until there are sessions + /// willing to use it again. + milliseconds_type connection_linger_time = default_connection_linger_time; + + /// The client will send PING messages periodically to allow the server + /// to detect dead connections (heartbeat). This parameter specifies the + /// time, in milliseconds, between these PING messages. When scheduling + /// the next PING message, the client will deduct a small random amount + /// from the specified value to help spread the load on the server from + /// many clients. + milliseconds_type ping_keepalive_period = default_ping_keepalive_period; + + /// Whenever the server receives a PING message, it is supposed to + /// respond with a PONG messsage to allow the client to detect dead + /// connections (heartbeat). This parameter specifies the time, in + /// milliseconds, that the client will wait for the PONG response + /// message before it assumes that the connection is dead, and + /// terminates it. + milliseconds_type pong_keepalive_timeout = default_pong_keepalive_timeout; + + /// The maximum amount of time, in milliseconds, since the loss of a + /// prior connection, for a new connection to be considered a *fast + /// reconnect*. + /// + /// In general, when a client establishes a connection to the server, + /// the uploading process remains suspended until the initial + /// downloading process completes (as if by invocation of + /// Session::async_wait_for_download_completion()). However, to avoid + /// unnecessary latency in change propagation during ongoing + /// application-level activity, if the new connection is established + /// less than a certain amount of time (`fast_reconnect_limit`) since + /// the client was previously connected to the server, then the + /// uploading process will be activated immediately. + /// + /// For now, the purpose of the general delaying of the activation of + /// the uploading process, is to increase the chance of multiple initial + /// transactions on the client-side, to be uploaded to, and processed by + /// the server as a single unit. In the longer run, the intention is + /// that the client should upload transformed (from reciprocal history), + /// rather than original changesets when applicable to reduce the need + /// for changeset to be transformed on both sides. The delaying of the + /// upload process will increase the number of cases where this is + /// possible. + /// + /// FIXME: Currently, the time between connections is not tracked across + /// sessions, so if the application closes its session, and opens a new + /// one immediately afterwards, the activation of the upload process + /// will be delayed unconditionally. + milliseconds_type fast_reconnect_limit = default_fast_reconnect_limit; + + /// Set to true to completely disable delaying of the upload process. In + /// this mode, the upload process will be activated immediately, and the + /// value of `fast_reconnect_limit` is ignored. + /// + /// For testing purposes only. + bool disable_upload_activation_delay = false; + + /// If `disable_upload_compaction` is true, every changeset will be + /// compacted before it is uploaded to the server. Compaction will + /// reduce the size of a changeset if the same field is set multiple + /// times or if newly created objects are deleted within the same + /// transaction. Log compaction increeses CPU usage and memory + /// consumption. + bool disable_upload_compaction = false; + + /// Set the `TCP_NODELAY` option on all TCP/IP sockets. This disables + /// the Nagle algorithm. Disabling it, can in some cases be used to + /// decrease latencies, but possibly at the expense of scalability. Be + /// sure to research the subject before you enable this option. + bool tcp_no_delay = false; + + /// The specified function will be called whenever a PONG message is + /// received on any connection. The round-trip time in milliseconds will + /// be pased to the function. The specified function will always be + /// called by the client's event loop thread, i.e., the thread that + /// calls `Client::run()`. This feature is mainly for testing purposes. + std::function roundtrip_time_handler; + + /// Disable sync to disk (fsync(), msync()) for all realm files managed + /// by this client. + /// + /// Testing/debugging feature. Should never be enabled in production. + bool disable_sync_to_disk = false; + }; + + /// \throw util::EventLoop::Implementation::NotAvailable if no event loop + /// implementation was specified, and + /// util::EventLoop::Implementation::get_default() throws it. + Client(Config = {}); + Client(Client&&) noexcept; + ~Client() noexcept; + + /// Run the internal event-loop of the client. At most one thread may + /// execute run() at any given time. The call will not return until somebody + /// calls stop(). + void run(); + + /// See run(). + /// + /// Thread-safe. + void stop() noexcept; + + /// \brief Cancel current or next reconnect delay for all servers. + /// + /// This corresponds to calling Session::cancel_reconnect_delay() on all + /// bound sessions, but will also cancel reconnect delays applying to + /// servers for which there are currently no bound sessions. + /// + /// Thread-safe. + void cancel_reconnect_delay(); + + /// \brief Wait for session termination to complete. + /// + /// Wait for termination of all sessions whose termination was initiated + /// prior this call (the completion condition), or until the client's event + /// loop thread exits from Client::run(), whichever happens + /// first. Termination of a session can be initiated implicitly (e.g., via + /// destruction of the session object), or explicitly by Session::detach(). + /// + /// Note: After session termination (when this function returns true) no + /// session specific callback function can be called or continue to execute, + /// and the client is guaranteed to no longer have a Realm file open on + /// behalf of the terminated session. + /// + /// CAUTION: If run() returns while a wait operation is in progress, this + /// waiting function will return immediately, even if the completion + /// condition is not yet satisfied. The completion condition is guaranteed + /// to be satisfied only when these functions return true. If it returns + /// false, session specific callback functions may still be executing or get + /// called, and the associated Realm files may still not have been closed. + /// + /// If a new wait operation is initiated while another wait operation is in + /// progress by another thread, the waiting period of fist operation may, or + /// may not get extended. The application must not assume either. + /// + /// Note: Session termination does not imply that the client has received an + /// UNBOUND message from the server (see the protocol specification). This + /// may happen later. + /// + /// \return True only if the completion condition was satisfied. False if + /// the client's event loop thread exited from Client::run() in which case + /// the completion condition may, or may not have been satisfied. + /// + /// Note: These functions are fully thread-safe. That is, they may be called + /// by any thread, and by multiple threads concurrently. + bool wait_for_session_terminations_or_client_stopped(); + + /// Returns false if the specified URL is invalid. + bool decompose_server_url(const std::string& url, ProtocolEnvelope& protocol, std::string& address, + port_type& port, std::string& path) const; + +private: + class Impl; + std::unique_ptr m_impl; + friend class Session; +}; + + +class BadServerUrl; // Exception + + +/// \brief Client-side representation of a Realm file synchronization session. +/// +/// A synchronization session deals with precisely one local Realm file. To +/// synchronize multiple local Realm files, you need multiple sessions. +/// +/// A session object is always associated with a particular client object (\ref +/// Client). The application must ensure that the destruction of the associated +/// client object never happens before the destruction of the session +/// object. The consequences of a violation are unspecified. +/// +/// A session object is always associated with a particular local Realm file, +/// however, a session object does not represent a session until it is bound to +/// a server side Realm, i.e., until bind() is called. From the point of view of +/// the thread that calls bind(), the session starts precisely when the +/// execution of bind() starts, i.e., before bind() returns. +/// +/// At most one session is allowed to exist for a particular local Realm file +/// (file system inode) at any point in time. Multiple session objects may +/// coexists for a single file, as long as bind() has been called on at most one +/// of them. Additionally, two bound session objects for the same file are +/// allowed to exist at different times, if they have no overlap in time (in +/// their bound state), as long as they are associated with the same client +/// object, or with two different client objects that do not overlap in +/// time. This means, in particular, that it is an error to create two bound +/// session objects for the same local Realm file, it they are associated with +/// two different client objects that overlap in time, even if the session +/// objects do not overlap in time (in their bound state). It is the +/// responsibility of the application to ensure that these rules are adhered +/// to. The consequences of a violation are unspecified. +/// +/// Thread-safety: It is safe for multiple threads to construct, use (with some +/// exceptions), and destroy session objects concurrently, regardless of whether +/// those session objects are associated with the same, or with different Client +/// objects. Please note that some of the public member functions are fully +/// thread-safe, while others are not. +/// +/// Callback semantics: All session specific callback functions will be executed +/// by the event loop thread, i.e., the thread that calls Client::run(). No +/// callback function will be called before Session::bind() is called. Callback +/// functions that are specified prior to calling bind() (e.g., any passed to +/// set_progress_handler()) may start to execute before bind() returns, as long +/// as some thread is executing Client::run(). Likewise, completion handlers, +/// such as those passed to async_wait_for_sync_completion() may start to +/// execute before the submitting function returns. All session specific +/// callback functions (including completion handlers) are guaranteed to no +/// longer be executing when session termination completes, and they are +/// guaranteed to not be called after session termination completes. Termination +/// is an event that completes asynchronously with respect to the application, +/// but is initiated by calling detach(), or implicitely by destroying a session +/// object. After having initiated one or more session terminations, the +/// application can wait for those terminations to complete by calling +/// Client::wait_for_session_terminations_or_client_stopped(). Since callback +/// functinos are always executed by the event loop thread, they are also +/// guaranteed to not be executing after Client::run() has returned. +class Session { +public: + using port_type = util::network::Endpoint::port_type; + using SyncTransactCallback = void(VersionID old_version, VersionID new_version); + using ProgressHandler = void(std::uint_fast64_t downloaded_bytes, std::uint_fast64_t downloadable_bytes, + std::uint_fast64_t uploaded_bytes, std::uint_fast64_t uploadable_bytes, + std::uint_fast64_t progress_version, std::uint_fast64_t snapshot_version); + using WaitOperCompletionHandler = std::function; + using SSLVerifyCallback = bool(const std::string& server_address, port_type server_port, const char* pem_data, + size_t pem_size, int preverify_ok, int depth); + + struct Config { + Config() {} + + /// server_address is the fully qualified host name, or IP address of + /// the server. + std::string server_address = "localhost"; + + /// server_port is the port at which the server listens. If server_port + /// is zero, the default port for the specified protocol is used. See + /// ProtocolEnvelope for information on default ports. + port_type server_port = 0; + + /// realm_identifier is the virtual path by which the server identifies the + /// Realm. + /// When connecting to the mock C++ server, this path must always be an + /// absolute path, and must therefore always contain a leading slash (`/`). + /// Furthermore, each segment of the virtual path must consist of one or + /// more characters that are either alpha-numeric or in (`_`, `-`, `.`), + /// and each segment is not allowed to equal `.` or `..`, and must not end + /// with `.realm`, `.realm.lock`, or `.realm.management`. These rules are + /// necessary because the C++ server currently reserves the right to use the + /// specified path as part of the file system path of a Realm file. + /// On the MongoDB Realm-based Sync server, virtual paths are not coupled + /// to file system paths, and thus, these restrictions do not apply. + std::string realm_identifier = ""; + + /// The protocol used for communicating with the server. See + /// ProtocolEnvelope. + ProtocolEnvelope protocol_envelope = ProtocolEnvelope::realm; + + /// service_identifier is a prefix that is prepended to the realm_identifier + /// in the HTTP GET request that initiates a sync connection. The value + /// specified here must match with the server's expectation. Changing + /// the value of service_identifier should be matched with a corresponding + /// change in the C++ mock server. + std::string service_identifier = ""; + + /// authorization_header_name is the name of the HTTP header containing + /// the Realm access token. The value of the HTTP header is "Bearer ". + /// authorization_header_name does not participate in session + /// multiplexing partitioning. + std::string authorization_header_name = "Authorization"; + + /// custom_http_headers is a map of custom HTTP headers. The keys of the map + /// are HTTP header names, and the values are the corresponding HTTP + /// header values. + /// If "Authorization" is used as a custom header name, + /// authorization_header_name must be set to anther value. + std::map custom_http_headers; + + /// Sessions can be multiplexed over the same TCP/SSL connection. + /// Sessions might share connection if they have identical server_address, + /// server_port, and protocol. multiplex_ident is a parameter that allows + /// finer control over session multiplexing. If two sessions have distinct + /// multiplex_ident, they will never share connection. The typical use of + /// multilex_ident is to give sessions with incompatible SSL requirements + /// distinct multiplex_idents. + /// multiplex_ident can be any string and the value has no meaning except + /// for partitioning the sessions. + std::string multiplex_ident; + + /// Controls whether the server certificate is verified for SSL + /// connections. It should generally be true in production. + bool verify_servers_ssl_certificate = true; + + /// ssl_trust_certificate_path is the path of a trust/anchor + /// certificate used by the client to verify the server certificate. + /// ssl_trust_certificate_path is only used if the protocol is ssl and + /// verify_servers_ssl_certificate is true. + /// + /// A server certificate is verified by first checking that the + /// certificate has a valid signature chain back to a trust/anchor + /// certificate, and secondly checking that the server_address matches + /// a host name contained in the certificate. The host name of the + /// certificate is stored in either Common Name or the Alternative + /// Subject Name (DNS section). + /// + /// If ssl_trust_certificate_path is None (default), ssl_verify_callback + /// (see below) is used if set, and the default device trust/anchor + /// store is used otherwise. + util::Optional ssl_trust_certificate_path; + + /// If Client::Config::ssl_verify_callback is set, that function is called + /// to verify the certificate, unless verify_servers_ssl_certificate is + /// false. + + /// ssl_verify_callback is used to implement custom SSL certificate + /// verification. it is only used if the protocol is SSL, + /// verify_servers_ssl_certificate is true and ssl_trust_certificate_path + /// is None. + /// + /// The signature of ssl_verify_callback is + /// + /// bool(const std::string& server_address, + /// port_type server_port, + /// const char* pem_data, + /// size_t pem_size, + /// int preverify_ok, + /// int depth); + /// + /// server address and server_port is the address and port of the server + /// that a SSL connection is being established to. They are identical to + /// the server_address and server_port set in this config file and are + /// passed for convenience. + /// pem_data is the certificate of length pem_size in + /// the PEM format. preverify_ok is OpenSSL's preverification of the + /// certificate. preverify_ok is either 0, or 1. If preverify_ok is 1, + /// OpenSSL has accepted the certificate and it will generally be safe + /// to trust that certificate. depth represents the position of the + /// certificate in the certificate chain sent by the server. depth = 0 + /// represents the actual server certificate that should contain the + /// host name(server address) of the server. The highest depth is the + /// root certificate. + /// The callback function will receive the certificates starting from + /// the root certificate and moving down the chain until it reaches the + /// server's own certificate with a host name. The depth of the last + /// certificate is 0. The depth of the first certificate is chain + /// length - 1. + /// + /// The return value of the callback function decides whether the + /// client accepts the certificate. If the return value is false, the + /// processing of the certificate chain is interrupted and the SSL + /// connection is rejected. If the return value is true, the verification + /// process continues. If the callback function returns true for all + /// presented certificates including the depth == 0 certificate, the + /// SSL connection is accepted. + /// + /// A recommended way of using the callback function is to return true + /// if preverify_ok = 1 and depth > 0, + /// always check the host name if depth = 0, + /// and use an independent verification step if preverify_ok = 0. + /// + /// Another possible way of using the callback is to collect all the + /// certificates until depth = 0, and present the entire chain for + /// independent verification. + std::function ssl_verify_callback; + + /// signed_user_token is a cryptographically signed token describing the + /// identity and access rights of the current user. + std::string signed_user_token; + + /// If not null, overrides whatever is specified by + /// Client::Config::changeset_cooker. + /// + /// The shared ownership over the cooker will be relinquished shortly + /// after the destruction of the session object as long as the event + /// loop of the client is being executed (Client::run()). + /// + /// CAUTION: ChangesetCooker::cook_changeset() of the specified cooker + /// may get called before the call to bind() returns, and it may get + /// called (or continue to execute) after the session object is + /// destroyed. Please see "Callback semantics" section under Client for + /// more on this. + /// + /// \sa make_client_replication(), TrivialChangesetCooker. + std::shared_ptr changeset_cooker; + + /// The encryption key the DB will be opened with. + util::Optional> encryption_key; + + /// ClientReset is used for both async open and client reset. If + /// client_reset is not util::none, the sync client will perform + /// async open for this session if the local Realm does not exist, and + /// client reset if the local Realm exists. If client_reset is + /// util::none, an ordinary sync session will take place. + /// + /// A session will perform async open by downloading a state Realm, and + /// some metadata, from the server, patching up the metadata part of + /// the Realm and finally move the downloaded Realm into the path of + /// the local Realm. After completion of async open, the application + /// can open and use the Realm. + /// + /// A session will perform client reset by downloading a state Realm, and + /// some metadata, from the server. After download, the state Realm will + /// be integrated into the local Realm in a write transaction. The + /// application is free to use the local realm during the entire client + /// reset. Like a DOWNLOAD message, the application will not be able + /// to perform a write transaction at the same time as the sync client + /// performs its own write transaction. Client reset is not more + /// disturbing for the application than any DOWNLOAD message. The + /// application can listen to change notifications from the client + /// reset exactly as in a DOWNLOAD message. + /// + /// The client reset will recover non-uploaded changes in the local + /// Realm if and only if 'recover_local_changes' is true. In case, + /// 'recover_local_changes' is false, the local Realm state will hence + /// be set to the server's state (server wins). + /// + /// Async open and client reset require a private directory for + /// metadata. This directory must be specified in the option + /// 'metadata_dir'. The metadata_dir must not be touched during async + /// open or client reset. The metadata_dir can safely be removed at + /// times where async open or client reset do not take place. The sync + /// client attempts to clean up metadata_dir. The metadata_dir can be + /// reused across app restarts to resume an interrupted download. It is + /// recommended to leave the metadata_dir unchanged except when it is + /// known that async open or client reset is done. + /// + /// The recommended usage of async open is to use it for the initial + /// bootstrap if Realm usage is not needed until after the server state + /// has been downloaded. + /// + /// The recommended usage of client reset is after a previous session + /// encountered an error that implies the need for a client reset. It + /// is not recommended to persist the need for a client reset. The + /// application should just attempt to synchronize in the usual fashion + /// and only after hitting an error, start a new session with a client + /// reset. In other words, if the application crashes during a client reset, + /// the application should attempt to perform ordinary synchronization + /// after restart and switch to client reset if needed. + /// + /// Error codes that imply the need for a client reset are the session + /// level error codes: + /// + /// bad_client_file_ident = 208, // Bad client file identifier (IDENT) + /// bad_server_version = 209, // Bad server version (IDENT, UPLOAD) + /// bad_client_version = 210, // Bad client version (IDENT, UPLOAD) + /// diverging_histories = 211, // Diverging histories (IDENT) + /// + /// However, other errors such as bad changeset (UPLOAD) could also be resolved + /// with a client reset. Client reset can even be used without any prior error + /// if so desired. + /// + /// After completion of async open and client reset, the sync client + /// will continue synchronizing with the server in the usual fashion. + /// + /// The progress of async open and client reset can be tracked with the + /// standard progress handler. + /// + /// Async open and client reset are done when the progress handler + /// arguments satisfy "progress_version > 0". However, if the + /// application wants to ensure that it has all data present on the + /// server, it should wait for download completion using either + /// void async_wait_for_download_completion(WaitOperCompletionHandler) + /// or + /// bool wait_for_download_complete_or_client_stopped(). + /// + /// The option 'require_recent_state_realm' is used for async open to + /// request a recent state Realm. A recent state Realm is never empty + /// (unless there is no data), and is recent in the sense that it was + /// produced by the current incarnation of the server. Recent does not + /// mean the absolutely newest possible state Realm, since that might + /// lead to too excessive work on the server. Setting + /// 'require_recent_state_realm' to true might lead to more work + /// performed by the server but it ensures that more data is downloaded + /// using async open instead of ordinary synchronization. It is + /// recommended to set 'require_recent_state_realm' to true. Client + /// reset always downloads a recent state Realm. + struct ClientReset { + std::string metadata_dir; + bool recover_local_changes = true; + bool require_recent_state_realm = true; + }; + util::Optional client_reset_config; + + struct ProxyConfig { + enum class Type { HTTP, HTTPS } type; + std::string address; + port_type port; + }; + util::Optional proxy_config; + + /// Set to true to disable the upload process for this session. This + /// includes the sending of empty UPLOAD messages. + /// + /// This feature exists exclusively for testing purposes at this time. + bool disable_upload = false; + + /// Set to true to disable sending of empty UPLOAD messages for this + /// session. + /// + /// This feature exists exclusively for testing purposes at this time. + bool disable_empty_upload = false; + + /// Set to true to cause the integration of the first received changeset + /// (in a DOWNLOAD message) to fail. + /// + /// This feature exists exclusively for testing purposes at this time. + bool simulate_integration_error = false; + }; + + /// \brief Start a new session for the specified client-side Realm. + /// + /// Note that the session is not fully activated until you call bind(). + /// Also note that if you call set_sync_transact_callback(), it must be + /// done before calling bind(). + /// + /// \param realm_path The file-system path of a local client-side Realm + /// file. + Session(Client&, std::string realm_path, Config = {}); + + /// This leaves the right-hand side session object detached. See "Thread + /// safety" section under detach(). + Session(Session&&) noexcept; + + /// Create a detached session object (see detach()). + Session() noexcept; + + /// Implies detachment. See "Thread safety" section under detach(). + ~Session() noexcept; + + /// Detach the object on the left-hand side, then "steal" the session from + /// the object on the right-hand side, if there is one. This leaves the + /// object on the right-hand side detached. See "Thread safety" section + /// under detach(). + Session& operator=(Session&&) noexcept; + + /// Detach this sesion object from the client object (Client). If the + /// session object is already detached, this function has no effect + /// (idempotency). + /// + /// Detachment initiates session termination, which is an event that takes + /// place shortly therafter in the context of the client's event loop + /// thread. + /// + /// A detached session object may be destroyed, move-assigned to, and moved + /// from. Apart from that, it is an error to call any function other than + /// detach() on a detached session object. + /// + /// Thread safety: Detachment is not a thread-safe operation. This means + /// that detach() may not be executed by two threads concurrently, and may + /// not execute concurrently with object destruction. Additionally, + /// detachment must not execute concurrently with a moving operation + /// involving the session object on the left or right-hand side. See move + /// constructor and assigment operator. + void detach() noexcept; + + /// \brief Set a function to be called when the local Realm has changed due + /// to integration of a downloaded changeset. + /// + /// Specify the callback function that will be called when one or more + /// transactions are performed to integrate downloaded changesets into the + /// client-side Realm, that is associated with this session. + /// + /// The callback function will always be called by the thread that executes + /// the event loop (Client::run()), but not until bind() is called. If the + /// callback function throws an exception, that exception will "travel" out + /// through Client::run(). + /// + /// Note: Any call to this function must have returned before bind() is + /// called. If this function is called multiple times, each call overrides + /// the previous setting. + /// + /// Note: This function is **not thread-safe**. That is, it is an error if + /// it is called while another thread is executing any member function on + /// the same Session object. + /// + /// CAUTION: The specified callback function may get called before the call + /// to bind() returns, and it may get called (or continue to execute) after + /// the session object is destroyed. Please see "Callback semantics" section + /// under Session for more on this. + void set_sync_transact_callback(std::function); + + /// \brief Set a handler to monitor the state of download and upload + /// progress. + /// + /// The handler must have signature + /// + /// void(uint_fast64_t downloaded_bytes, uint_fast64_t downloadable_bytes, + /// uint_fast64_t uploaded_bytes, uint_fast64_t uploadable_bytes, + /// uint_fast64_t progress_version); + /// + /// downloaded_bytes is the size in bytes of all downloaded changesets. + /// downloadable_bytes is equal to downloaded_bytes plus an estimate of + /// the size of the remaining server history. + /// + /// uploaded_bytes is the size in bytes of all locally produced changesets + /// that have been received and acknowledged by the server. + /// uploadable_bytes is the size in bytes of all locally produced changesets. + /// + /// Due to the nature of the merge rules, it is possible that the size of an + /// uploaded changeset uploaded from one client is not equal to the size of + /// the changesets that other clients will download. + /// + /// Typical uses of this function: + /// + /// Upload completion can be checked by + /// + /// bool upload_complete = (uploaded_bytes == uploadable_bytes); + /// + /// Download completion could be checked by + /// + /// bool download_complete = (downloaded_bytes == downloadable_bytes); + /// + /// However, download completion might never be reached because the server + /// can receive new changesets from other clients. downloadable_bytes can + /// decrease for two reasons: server side compaction and changesets of + /// local origin. Code using downloadable_bytes must not assume that it + /// is increasing. + /// + /// Upload progress can be calculated by caching an initial value of + /// uploaded_bytes from the last, or next, callback. Then + /// + /// double upload_progress = + /// (uploaded_bytes - initial_uploaded_bytes) + /// ------------------------------------------- + /// (uploadable_bytes - initial_uploaded_bytes) + /// + /// Download progress can be calculates similarly: + /// + /// double download_progress = + /// (downloaded_bytes - initial_downloaded_bytes) + /// ----------------------------------------------- + /// (downloadable_bytes - initial_downloaded_bytes) + /// + /// progress_version is 0 at the start of a session. When at least one + /// DOWNLOAD message has been received from the server, progress_version is + /// positive. progress_version can be used to ensure that the reported + /// progress contains information obtained from the server in the current + /// session. The server will send a message as soon as possible, and the + /// progress handler will eventually be called with a positive progress_version + /// unless the session is interrupted before a message from the server has + /// been received. + /// + /// The handler is called on the event loop thread.The handler after bind(), + /// after each DOWNLOAD message, and after each local transaction + /// (nonsync_transact_notify). + /// + /// set_progress_handler() is not thread safe and it must be called before + /// bind() is called. Subsequent calls to set_progress_handler() overwrite + /// the previous calls. Typically, this function is called once per session. + /// + /// CAUTION: The specified callback function may get called before the call + /// to bind() returns, and it may get called (or continue to execute) after + /// the session object is destroyed. Please see "Callback semantics" section + /// under Session for more on this. + void set_progress_handler(std::function); + + enum class ConnectionState { disconnected, connecting, connected }; + + /// \brief Information about an error causing a session to be temporarily + /// disconnected from the server. + /// + /// In general, the connection will be automatically reestablished + /// later. Whether this happens quickly, generally depends on \ref + /// is_fatal. If \ref is_fatal is true, it means that the error is deemed to + /// be of a kind that is likely to persist, and cause all future reconnect + /// attempts to fail. In that case, if another attempt is made at + /// reconnecting, the delay will be substantial (at least an hour). + /// + /// \ref error_code specifies the error that caused the connection to be + /// closed. For the list of errors reported by the server, see \ref + /// ProtocolError (or `protocol.md`). For the list of errors corresponding + /// to protocol violations that are detected by the client, see + /// Client::Error. The error may also be a system level error, or an error + /// from one of the potential intermediate protocol layers (SSL or + /// WebSocket). + /// + /// \ref detailed_message is the most detailed message available to describe + /// the error. It is generally equal to `error_code.message()`, but may also + /// be a more specific message (one that provides extra context). The + /// purpose of this message is mostly to aid in debugging. For non-debugging + /// purposes, `error_code.message()` should generally be considered + /// sufficient. + /// + /// \sa set_connection_state_change_listener(). + struct ErrorInfo { + std::error_code error_code; + bool is_fatal; + const std::string& detailed_message; + }; + + using ConnectionStateChangeListener = void(ConnectionState, const ErrorInfo*); + + /// \brief Install a connection state change listener. + /// + /// Sets a function to be called whenever the state of the underlying + /// network connection changes between "disconnected", "connecting", and + /// "connected". The initial state is always "disconnected". The next state + /// after "disconnected" is always "connecting". The next state after + /// "connecting" is either "connected" or "disconnected". The next state + /// after "connected" is always "disconnected". A switch to the + /// "disconnected" state only happens when an error occurs. + /// + /// Whenever the installed function is called, an ErrorInfo object is passed + /// when, and only when the passed state is ConnectionState::disconnected. + /// + /// When multiple sessions share a single connection, the state changes will + /// be reported for each session in turn. + /// + /// The callback function will always be called by the thread that executes + /// the event loop (Client::run()), but not until bind() is called. If the + /// callback function throws an exception, that exception will "travel" out + /// through Client::run(). + /// + /// Note: Any call to this function must have returned before bind() is + /// called. If this function is called multiple times, each call overrides + /// the previous setting. + /// + /// Note: This function is **not thread-safe**. That is, it is an error if + /// it is called while another thread is executing any member function on + /// the same Session object. + /// + /// CAUTION: The specified callback function may get called before the call + /// to bind() returns, and it may get called (or continue to execute) after + /// the session object is destroyed. Please see "Callback semantics" section + /// under Session for more on this. + void set_connection_state_change_listener(std::function); + + //@{ + /// Deprecated! Use set_connection_state_change_listener() instead. + using ErrorHandler = void(std::error_code, bool is_fatal, const std::string& detailed_message); + void set_error_handler(std::function); + //@} + + /// @{ \brief Bind this session to the specified server side Realm. + /// + /// No communication takes place on behalf of this session before the + /// session is bound, but as soon as the session becomes bound, the server + /// will start to push changes to the client, and vice versa. + /// + /// If a callback function was set using set_sync_transact_callback(), then + /// that callback function will start to be called as changesets are + /// downloaded and integrated locally. It is important to understand that + /// callback functions are executed by the event loop thread (Client::run()) + /// and the callback function may therefore be called before bind() returns. + /// + /// Note: It is an error if this function is called more than once per + /// Session object. + /// + /// Note: This function is **not thread-safe**. That is, it is an error if + /// it is called while another thread is executing any member function on + /// the same Session object. + /// + /// bind() binds this session to the specified server side Realm using the + /// parameters specified in the Session::Config object. + /// + /// The two other forms of bind() are convenience functions. + /// void bind(std::string server_address, std::string server_path, + /// std::string signed_user_token, port_type server_port = 0, + /// ProtocolEnvelope protocol = ProtocolEnvelope::realm); + /// replaces the corresponding parameters from the Session::Config object + /// before the session is bound. + /// void bind(std::string server_url, std::string signed_user_token) parses + /// the \param server_url and replaces the parameters in the Session::Config object + /// before the session is bound. + /// + /// \param server_url For example "realm://sync.realm.io/test". See + /// server_address, server_path, and server_port in Session::Config for + /// information about the individual components of the URL. See + /// ProtocolEnvelope for the list of available URL schemes and the + /// associated default ports. + /// + /// \throw BadServerUrl if the specified server URL is malformed. + void bind(); + void bind(std::string server_url, std::string signed_user_token); + void bind(std::string server_address, std::string server_path, std::string signed_user_token, + port_type server_port = 0, ProtocolEnvelope protocol = ProtocolEnvelope::realm); + /// @} + + /// \brief Refresh the access token associated with this session. + /// + /// This causes the REFRESH protocol message to be sent to the server. See + /// ProtocolEnvelope. It is an error to pass a token with a different user + /// identity than the token used to initiate the session. + /// + /// In an on-going session the application may expect the access token to + /// expire at a certain time and schedule acquisition of a fresh access + /// token (using a refresh token or by other means) in due time to provide a + /// better user experience, and seamless connectivity to the server. + /// + /// If the application does not proactively refresh an expiring token, the + /// session will eventually be disconnected. The application can detect this + /// by monitoring the connection state + /// (set_connection_state_change_listener()), and check whether the error + /// code is `ProtocolError::token_expired`. Such a session can then be + /// revived by calling refresh() with a newly acquired access token. + /// + /// Due to protocol techicalities, a race condition exists that can cause a + /// session to become, and remain disconnected after a new access token has + /// been passed to refresh(). The application can work around this race + /// condition by detecting the `ProtocolError::token_expired` error, and + /// always initiate a token renewal in this case. + /// + /// It is an error to call this function before calling `Client::bind()`. + /// + /// Note: This function is thread-safe. + /// + /// \param signed_user_token A cryptographically signed token describing the + /// identity and access rights of the current user. See ProtocolEnvelope. + void refresh(std::string signed_user_token); + + /// \brief Inform the synchronization agent about changes of local origin. + /// + /// This function must be called by the application after a transaction + /// performed on its behalf, that is, after a transaction that is not + /// performed to integrate a changeset that was downloaded from the server. + /// + /// It is an error to call this function before bind() has been called, and + /// has returned. + /// + /// Note: This function is fully thread-safe. That is, it may be called by + /// any thread, and by multiple threads concurrently. + void nonsync_transact_notify(version_type new_version); + + /// @{ \brief Wait for upload, download, or upload+download completion. + /// + /// async_wait_for_upload_completion() initiates an asynchronous wait for + /// upload to complete, async_wait_for_download_completion() initiates an + /// asynchronous wait for download to complete, and + /// async_wait_for_sync_completion() initiates an asynchronous wait for + /// upload and download to complete. + /// + /// Upload is considered complete when all non-empty changesets of local + /// origin have been uploaded to the server, and the server has acknowledged + /// reception of them. Changesets of local origin introduced after the + /// initiation of the session (after bind() is called) will generally not be + /// considered for upload unless they are announced to this client through + /// nonsync_transact_notify() prior to the initiation of the wait operation, + /// i.e., prior to the invocation of async_wait_for_upload_completion() or + /// async_wait_for_sync_completion(). Unannounced changesets may get picked + /// up, but there is no guarantee that they will be, however, if a certain + /// changeset is announced, then all previous changesets are implicitly + /// announced. Also all preexisting changesets are implicitly announced + /// when the session is initiated. + /// + /// Download is considered complete when all non-empty changesets of remote + /// origin have been downloaded from the server, and integrated into the + /// local Realm state. To know what is currently outstanding on the server, + /// the client always sends a special "marker" message to the server, and + /// waits until it has downloaded all outstanding changesets that were + /// present on the server at the time when the server received that marker + /// message. Each call to async_wait_for_download_completion() and + /// async_wait_for_sync_completion() therefore requires a full client <-> + /// server round-trip. + /// + /// If a new wait operation is initiated while another wait operation is in + /// progress by another thread, the waiting period of first operation may, + /// or may not get extended. The application must not assume either. The + /// application may assume, however, that async_wait_for_upload_completion() + /// will not affect the waiting period of + /// async_wait_for_download_completion(), and vice versa. + /// + /// It is an error to call these functions before bind() has been called, + /// and has returned. + /// + /// The specified completion handlers will always be executed by the thread + /// that executes the event loop (the thread that calls Client::run()). If + /// the handler throws an exception, that exception will "travel" out + /// through Client::run(). + /// + /// If incomplete wait operations exist when the session is terminated, + /// those wait operations will be canceled. Session termination is an event + /// that happens in the context of the client's event loop thread shortly + /// after the destruction of the session object. The std::error_code + /// argument passed to the completion handler of a canceled wait operation + /// will be `util::error::operation_aborted`. For uncanceled wait operations + /// it will be `std::error_code{}`. Note that as long as the client's event + /// loop thread is running, all completion handlers will be called + /// regardless of whether the operations get canceled or not. + /// + /// CAUTION: The specified completion handlers may get called before the + /// call to the waiting function returns, and it may get called (or continue + /// to execute) after the session object is destroyed. Please see "Callback + /// semantics" section under Session for more on this. + /// + /// Note: These functions are fully thread-safe. That is, they may be called + /// by any thread, and by multiple threads concurrently. + void async_wait_for_sync_completion(WaitOperCompletionHandler); + void async_wait_for_upload_completion(WaitOperCompletionHandler); + void async_wait_for_download_completion(WaitOperCompletionHandler); + /// @} + + /// @{ \brief Synchronous wait for upload or download completion. + /// + /// These functions are synchronous equivalents of + /// async_wait_for_upload_completion() and + /// async_wait_for_download_completion() respectively. This means that they + /// block the caller until the completion condition is satisfied, or the + /// client's event loop thread exits from Client::run(), whichever happens + /// first. + /// + /// It is an error to call these functions before bind() has been called, + /// and has returned. + /// + /// CAUTION: If Client::run() returns while a wait operation is in progress, + /// these waiting functions return immediately, even if the completion + /// condition is not yet satisfied. The completion condition is guaranteed + /// to be satisfied only when these functions return true. + /// + /// \return True only if the completion condition was satisfied. False if + /// the client's event loop thread exited from Client::run() in which case + /// the completion condition may, or may not have been satisfied. + /// + /// Note: These functions are fully thread-safe. That is, they may be called + /// by any thread, and by multiple threads concurrently. + bool wait_for_upload_complete_or_client_stopped(); + bool wait_for_download_complete_or_client_stopped(); + /// @} + + /// \brief Cancel the current or next reconnect delay for the server + /// associated with this session. + /// + /// When the network connection is severed, or an attempt to establish + /// connection fails, a certain delay will take effect before the client + /// will attempt to reestablish the connection. This delay will generally + /// grow with the number of unsuccessful reconnect attempts, and can grow to + /// over a minute. In some cases however, the application will know when it + /// is a good time to stop waiting and retry immediately. One example is + /// when a device has been offline for a while, and the operating system + /// then tells the application that network connectivity has been restored. + /// + /// Clearly, this function should not be called too often and over extended + /// periods of time, as that would effectively disable the built-in "server + /// hammering" protection. + /// + /// It is an error to call this function before bind() has been called, and + /// has returned. + /// + /// This function is fully thread-safe. That is, it may be called by any + /// thread, and by multiple threads concurrently. + void cancel_reconnect_delay(); + + /// \brief Change address of server for this session. + void override_server(std::string address, port_type); + +private: + class Impl; + Impl* m_impl = nullptr; + + void abandon() noexcept; + void async_wait_for(bool upload_completion, bool download_completion, WaitOperCompletionHandler); +}; + + +/// \brief Protocol errors discovered by the client. +/// +/// These errors will terminate the network connection (disconnect all sessions +/// associated with the affected connection), and the error will be reported to +/// the application via the connection state change listeners of the affected +/// sessions. +enum class Client::Error { + // clang-format off + connection_closed = 100, ///< Connection closed (no error) + unknown_message = 101, ///< Unknown type of input message + bad_syntax = 102, ///< Bad syntax in input message head + limits_exceeded = 103, ///< Limits exceeded in input message + bad_session_ident = 104, ///< Bad session identifier in input message + bad_message_order = 105, ///< Bad input message order + bad_client_file_ident = 106, ///< Bad client file identifier (IDENT) + bad_progress = 107, ///< Bad progress information (DOWNLOAD) + bad_changeset_header_syntax = 108, ///< Bad syntax in changeset header (DOWNLOAD) + bad_changeset_size = 109, ///< Bad changeset size in changeset header (DOWNLOAD) + bad_origin_file_ident = 110, ///< Bad origin file identifier in changeset header (DOWNLOAD) + bad_server_version = 111, ///< Bad server version in changeset header (DOWNLOAD) + bad_changeset = 112, ///< Bad changeset (DOWNLOAD) + bad_request_ident = 113, ///< Bad request identifier (MARK) + bad_error_code = 114, ///< Bad error code (ERROR), + bad_compression = 115, ///< Bad compression (DOWNLOAD) + bad_client_version = 116, ///< Bad last integrated client version in changeset header (DOWNLOAD) + ssl_server_cert_rejected = 117, ///< SSL server certificate rejected + pong_timeout = 118, ///< Timeout on reception of PONG respone message + bad_client_file_ident_salt = 119, ///< Bad client file identifier salt (IDENT) + bad_file_ident = 120, ///< Bad file identifier (ALLOC) + connect_timeout = 121, ///< Sync connection was not fully established in time + bad_timestamp = 122, ///< Bad timestamp (PONG) + bad_protocol_from_server = 123, ///< Bad or missing protocol version information from server + client_too_old_for_server = 124, ///< Protocol version negotiation failed: Client is too old for server + client_too_new_for_server = 125, ///< Protocol version negotiation failed: Client is too new for server + protocol_mismatch = 126, ///< Protocol version negotiation failed: No version supported by both client and server + bad_state_message = 127, ///< Bad values in state message (STATE) + missing_protocol_feature = 128, ///< Requested feature missing in negotiated protocol version + http_tunnel_failed = 131, ///< Failed to establish HTTP tunnel with configured proxy + // clang-format on +}; + +const std::error_category& client_error_category() noexcept; + +std::error_code make_error_code(Client::Error) noexcept; + +std::ostream& operator<<(std::ostream& os, Session::Config::ProxyConfig::Type); + +} // namespace sync +} // namespace realm + +namespace std { + +template <> +struct is_error_code_enum { + static const bool value = true; +}; + +} // namespace std + +namespace realm { +namespace sync { + + +// Implementation + +class BadServerUrl : public std::exception { +public: + const char* what() const noexcept override + { + return "Bad server URL"; + } +}; + +inline Session::Session(Session&& sess) noexcept + : m_impl{sess.m_impl} +{ + sess.m_impl = nullptr; +} + +inline Session::Session() noexcept {} + +inline Session::~Session() noexcept +{ + if (m_impl) + abandon(); +} + +inline Session& Session::operator=(Session&& sess) noexcept +{ + if (m_impl) + abandon(); + m_impl = sess.m_impl; + sess.m_impl = nullptr; + return *this; +} + +inline void Session::detach() noexcept +{ + if (m_impl) + abandon(); + m_impl = nullptr; +} + +inline void Session::set_error_handler(std::function handler) +{ + auto handler_2 = [handler = std::move(handler)](ConnectionState state, const ErrorInfo* error_info) { + if (state != ConnectionState::disconnected) + return; + REALM_ASSERT(error_info); + std::error_code ec = error_info->error_code; + bool is_fatal = error_info->is_fatal; + const std::string& detailed_message = error_info->detailed_message; + handler(ec, is_fatal, detailed_message); // Throws + }; + set_connection_state_change_listener(std::move(handler_2)); // Throws +} + +inline void Session::async_wait_for_sync_completion(WaitOperCompletionHandler handler) +{ + bool upload_completion = true, download_completion = true; + async_wait_for(upload_completion, download_completion, std::move(handler)); // Throws +} + +inline void Session::async_wait_for_upload_completion(WaitOperCompletionHandler handler) +{ + bool upload_completion = true, download_completion = false; + async_wait_for(upload_completion, download_completion, std::move(handler)); // Throws +} + +inline void Session::async_wait_for_download_completion(WaitOperCompletionHandler handler) +{ + bool upload_completion = false, download_completion = true; + async_wait_for(upload_completion, download_completion, std::move(handler)); // Throws +} + +} // namespace sync +} // namespace realm + +#endif // REALM_SYNC_CLIENT_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/crypto_server.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/crypto_server.hpp new file mode 100644 index 0000000..b4d7ee4 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/crypto_server.hpp @@ -0,0 +1,75 @@ + +#ifndef REALM_SYNC_CRYPTO_SERVER_HPP +#define REALM_SYNC_CRYPTO_SERVER_HPP + +#include +#include + +#include +#include + +namespace realm { +namespace sync { + +struct CryptoError : std::runtime_error { + CryptoError(std::string message) + : std::runtime_error(std::move(message)) + { + } +}; + +/// This class represents a public/private keypair, or more commonly a single public +/// key used for verifying signatures. +/// +/// Only RSA keys are supported for now. +/// +/// Its methods correspond roughly to the EVP_PKEY_* set of functionality found in +/// the OpenSSL library. +class PKey { +public: + PKey(PKey&&); + PKey& operator=(PKey&&); + ~PKey(); + + /// Load RSA public key from \a pemfile. + static PKey load_public(const std::string& pemfile); + /// Load RSA public key from a PEM buffer + static PKey load_public(BinaryData pem_buffer); + + /// Load RSA public/private keypair from \a pemfile. + static PKey load_private(const std::string& pemfile); + /// Load RSA public/private keypair from a PEM buffer + static PKey load_private(BinaryData pem_buffer); + + /// Whether or not the key can be used for signing. + /// + /// True if the private part is loaded. + bool can_sign() const noexcept; + + /// Whether or not the key can be used for verifying. + /// + /// Always true for RSA keys. + bool can_verify() const noexcept; + + /// Sign \a message with the loaded key, if the private part is + /// loaded. Store the signed message as binary data in \a signature. + /// + /// If a private key is not loaded, throws an exception of type CryptoError. + void sign(BinaryData message, util::Buffer& signature) const; + + /// Verify that \a signature is a valid digest of \a message. + /// + /// Returns true if the signature is valid, otherwise false. If an error occurs while + /// attempting verification, an exception of type CryptoError is thrown. + bool verify(BinaryData message, BinaryData signature) const; + +private: + PKey(); + struct Impl; + std::unique_ptr m_impl; +}; + +} // namespace sync +} // namespace realm + +#endif // REALM_SYNC_CRYPTO_SERVER_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/fingerprint.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/fingerprint.hpp new file mode 100644 index 0000000..f6eb994 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/fingerprint.hpp @@ -0,0 +1,34 @@ +#ifndef REALM_ENCRYPT_FINGERPRINT_HPP +#define REALM_ENCRYPT_FINGERPRINT_HPP + +#include +#include + +#include + +namespace realm { +namespace encrypt { + +// calculate_fingerprint() calculates, and returns, a fingerprint of an +// encryption key. The input key can be util::none in order to calculate a +// fingerprint even in the case of unencrypted Realms. +// +// An intruder cannot recover an unknown encryption_key from the fingerprint, +// and it is safe to save the fingerprint in a file together with the encrypted +// Realms. +// +// calculate_fingerprint() can be considered opaque, but currently the +// fingerprint is a colon separated hex representation of the SHA-256 hash of +// the encryption key. +std::string calculate_fingerprint(const util::Optional> encryption_key); + +// verify_fingerprint() returns true if `fingerprint` was obtained previously +// from calculate_fingerprint() with `encryption_key` as argument. Otherwise, +// verify_fingerprint() returns false with extremely high probability. +bool verify_fingerprint(const std::string& fingerprint, + const util::Optional> encryption_key); + +} // namespace encrypt +} // namespace realm + +#endif // REALM_ENCRYPT_FINGERPRINT_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/history.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/history.hpp new file mode 100644 index 0000000..c037c77 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/history.hpp @@ -0,0 +1,568 @@ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifndef REALM_SYNC_HISTORY_HPP +#define REALM_SYNC_HISTORY_HPP + + +namespace realm { +namespace _impl { + +struct ObjectIDHistoryState; + +} // namespace _impl +} // namespace realm + + +namespace realm { +namespace sync { + +struct VersionInfo { + /// Realm snapshot version. + version_type realm_version = 0; + + /// The synchronization version corresponding to `realm_version`. + /// + /// In the context of the client-side history type `sync_version.version` + /// will currently always be equal to `realm_version` and + /// `sync_version.salt` will always be zero. + SaltedVersion sync_version = {0, 0}; +}; + +timestamp_type generate_changeset_timestamp() noexcept; + +// FIXME: in C++17, switch to using std::timespec in place of last two +// arguments. +void map_changeset_timestamp(timestamp_type, std::time_t& seconds_since_epoch, long& nanoseconds) noexcept; + +/// Thrown if changeset cooking is not either consistently on or consistently +/// off during synchronization (ClientHistory::set_sync_progress() and +/// ClientHistory::integrate_server_changesets()). +class InconsistentUseOfCookedHistory; + +/// Thrown if a bad server version is passed to +/// ClientHistory::get_cooked_status(). +class BadCookedServerVersion; + + +class ClientReplicationBase : public SyncReplication { +public: + using SyncTransactCallback = void(VersionID old_version, VersionID new_version); + + /// Get the version of the latest snapshot of the associated Realm, as well + /// as the client file identifier and the synchronization progress as they + /// are stored in that snapshot. + /// + /// The returned current client version is the version produced by the last + /// changeset in the history. The type of version returned here, is the one + /// that identifies an entry in the sync history. Whether this is the same + /// as the snapshot number of the Realm file depends on the history + /// implementation. + /// + /// The returned client file identifier is the one that was last stored by + /// set_client_file_ident(), or `SaltedFileIdent{0, 0}` if + /// set_client_file_ident() has never been called. + /// + /// The returned SyncProgress is the one that was last stored by + /// set_sync_progress(), or `SyncProgress{}` if set_sync_progress() has + /// never been called. + virtual void get_status(version_type& current_client_version, SaltedFileIdent& client_file_ident, + SyncProgress& progress) const = 0; + + /// Stores the server assigned client file identifier in the associated + /// Realm file, such that it is available via get_status() during future + /// synchronization sessions. It is an error to set this identifier more + /// than once per Realm file. + /// + /// \param client_file_ident The server assigned client-side file + /// identifier. A client-side file identifier is a non-zero positive integer + /// strictly less than 2**64. The server guarantees that all client-side + /// file identifiers generated on behalf of a particular server Realm are + /// unique with respect to each other. The server is free to generate + /// identical identifiers for two client files if they are associated with + /// different server Realms. + /// + /// \param fix_up_object_ids The object ids that depend on client file ident + /// will be fixed in both state and history if this parameter is true. If + /// it is known that there are no objects to fix, it can be set to false to + /// achieve higher performance. + /// + /// The client is required to obtain the file identifier before engaging in + /// synchronization proper, and it must store the identifier and use it to + /// reestablish the connection between the client file and the server file + /// when engaging in future synchronization sessions. + virtual void set_client_file_ident(SaltedFileIdent client_file_ident, bool fix_up_object_ids) = 0; + + /// Stores the synchronization progress in the associated Realm file in a + /// way that makes it available via get_status() during future + /// synchronization sessions. Progress is reported by the server in the + /// DOWNLOAD message. + /// + /// See struct SyncProgress for a description of \a progress. + /// + /// \param downloadable_bytes If specified, and if the implementation cares + /// about byte-level progress, this function updates the persistent record + /// of the estimate of the number of remaining bytes to be downloaded. + /// + /// \throw InconsistentUseOfCookedHistory If a changeset cooker has been + /// attached to this history object, and the Realm file does not have a + /// cooked history, and a cooked history can no longer be added because some + /// synchronization has already happened. Or if no changeset cooker has been + /// attached, and the Realm file does have a cooked history. + virtual void set_sync_progress(const SyncProgress& progress, const std::uint_fast64_t* downloadable_bytes, + VersionInfo&) = 0; + + struct UploadChangeset { + timestamp_type origin_timestamp; + file_ident_type origin_file_ident; + UploadCursor progress; + ChunkedBinaryData changeset; + std::unique_ptr buffer; + }; + + /// \brief Scan through the history for changesets to be uploaded. + /// + /// This function scans the history for changesets to be uploaded, i.e., for + /// changesets that are not empty, and were not produced by integration of + /// changesets recieved from the server. The scan begins at the position + /// specified by the initial value of \a upload_progress.client_version, and + /// ends no later than at the position specified by \a end_version. + /// + /// The implementation is allowed to end the scan before \a end_version, + /// such as to limit the combined size of returned changesets. However, if + /// the specified range contains any changesets that are supposed to be + /// uploaded, this function must return at least one. + /// + /// Upon return, \a upload_progress will have been updated to point to the + /// position from which the next scan should resume. This must be a position + /// after the last returned changeset, and before any remaining changesets + /// that are supposed to be uploaded, although never a position that + /// succeeds \a end_version. + /// + /// The value passed as \a upload_progress by the caller, must either be one + /// that was produced by an earlier invocation of + /// find_uploadable_changesets(), one that was returned by get_status(), or + /// one that was received by the client in a DOWNLOAD message from the + /// server. When the value comes from a DOWNLOAD message, it is supposed to + /// reflect a value of UploadChangeset::progress produced by an earlier + /// invocation of find_uploadable_changesets(). + /// + /// Found changesets are added to \a uploadable_changesets. + /// + /// \param locked_server_version will be set to the value that should be + /// used as `` in a DOWNLOAD message. + /// + /// For changesets of local origin, UploadChangeset::origin_file_ident will + /// be zero. + virtual void find_uploadable_changesets(UploadCursor& upload_progress, version_type end_version, + std::vector& uploadable_changesets, + version_type& locked_server_version) const = 0; + + using RemoteChangeset = Transformer::RemoteChangeset; + + // FIXME: Apparently, this feature is expected by object store, but why? + // What is it ultimately used for? (@tgoyne) + class SyncTransactReporter { + public: + virtual void report_sync_transact(VersionID old_version, VersionID new_version) = 0; + + protected: + ~SyncTransactReporter() {} + }; + + enum class IntegrationError { bad_origin_file_ident, bad_changeset }; + + /// \brief Integrate a sequence of changesets received from the server using + /// a single Realm transaction. + /// + /// Each changeset will be transformed as if by a call to + /// Transformer::transform_remote_changeset(), and then applied to the + /// associated Realm. + /// + /// As a final step, each changeset will be added to the local history (list + /// of applied changesets). + /// + /// This function checks whether the specified changesets specify valid + /// remote origin file identifiers and whether the changesets contain valid + /// sequences of instructions. The caller must already have ensured that the + /// origin file identifiers are strictly positive and not equal to the file + /// identifier assigned to this client by the server. + /// + /// If any of the changesets are invalid, this function returns false and + /// sets `integration_error` to the appropriate value. If they are all + /// deemed valid, this function updates \a version_info to reflect the new + /// version produced by the transaction. + /// + /// \param progress The synchronization progress is what was received in the + /// DOWNLOAD message along with the specified changesets. The progress will + /// be persisted along with the changesets. + /// + /// \param downloadable_bytes If specified, and if the implementation cares + /// about byte-level progress, this function updates the persistent record + /// of the estimate of the number of remaining bytes to be downloaded. + /// + /// \param num_changesets The number of passed changesets. Must be non-zero. + /// + /// \param transact_reporter An optional callback which will be called with the + /// version immediately processing the sync transaction and that of the sync + /// transaction. + /// + /// \throw InconsistentUseOfCookedHistory If a changeset cooker has been + /// attached to this history object, and the Realm file does not have a + /// cooked history, and a cooked history can no longer be added because some + /// synchronization has already happened. Or if no changeset cooker has been + /// attached, and the Realm file does have a cooked history. + virtual bool integrate_server_changesets(const SyncProgress& progress, + const std::uint_fast64_t* downloadable_bytes, + const RemoteChangeset* changesets, std::size_t num_changesets, + VersionInfo& new_version, IntegrationError& integration_error, + util::Logger&, SyncTransactReporter* transact_reporter = nullptr) = 0; + +protected: + ClientReplicationBase(const std::string& realm_path); +}; + + +class ClientReplication : public ClientReplicationBase { +public: + class ChangesetCooker; + class Config; + + /// Get the persisted upload/download progress in bytes. + virtual void get_upload_download_bytes(std::uint_fast64_t& downloaded_bytes, + std::uint_fast64_t& downloadable_bytes, std::uint_fast64_t& uploaded_bytes, + std::uint_fast64_t& uploadable_bytes, + std::uint_fast64_t& snapshot_version) = 0; + + /// See set_cooked_progress(). + struct CookedProgress { + std::int_fast64_t changeset_index = 0; + std::int_fast64_t intrachangeset_progress = 0; + }; + + /// Get information about the current state of the cooked history including + /// the point of progress of its consumption. + /// + /// \param server_version The server version associated with the last cooked + /// changeset that should be skipped. See `/doc/cooked_history.md` for an + /// explanation of the rationale behind this. Specifying zero means that no + /// changesets should be skipped. It is an error to specify a nonzero server + /// version that is not the server version associated with any of of the + /// cooked changesets, or to specify a nonzero server version that precedes + /// the one, that is associated with the last cooked changeset that was + /// marked as consumed. Doing so, will cause BadCookedServerVersion to be + /// thrown. + /// + /// \param num_changesets Set to the total number of produced cooked + /// changesets over the lifetime of the Realm file to which this history + /// accessor object is attached. This is the number of previously consumed + /// changesets plus the number of unconsumed changesets remaining in the + /// Realm file. + /// + /// \param progress The point of progress of the consumption of the cooked + /// history. Initially, and until explicitly modified by + /// set_cooked_progress(), both `CookedProgress::changeset_index` and + /// `CookedProgress::intrachangeset_progress` are zero. If a nonzero value + /// was passed for \a server_version, \a progress will be transparently + /// adjusted to account for the skipped changesets. See also \a + /// num_skipped_changesets. If one or more changesets are skipped, + /// `CookedProgress::intrachangeset_progress` will be set to zero. + /// + /// \param num_skipped_changesets The number of skipped changesets. See also + /// \a server_version. + /// + /// \throw BadCookedServerVersion See \a server_version. + virtual void get_cooked_status(version_type server_version, std::int_fast64_t& num_changesets, + CookedProgress& progress, std::int_fast64_t& num_skipped_changesets) const = 0; + + /// Fetch the cooked changeset at the specified index. + /// + /// Cooked changesets are made available in the order they are produced by + /// the changeset cooker (ChangesetCooker). + /// + /// Behaviour is undefined if the specified index is less than the index + /// (CookedProgress::changeset_index) returned by get_cooked_progress(), or + /// if it is greater than, or equal to the total number of cooked changesets + /// (as returned by get_num_cooked_changesets()). + /// + /// The callee must append the bytes of the located cooked changeset to the + /// specified buffer, which does not have to be empty initially. + /// + /// \param server_version Will be set to the version produced on the server + /// by an earlier form of the retreived changeset. If the cooked changeset + /// was produced (as output of cooker) before migration of the client-side + /// history compartment to schema version 2, then \a server_version will be + /// set to zero instead, because the real value is unkown. Zero is not a + /// possible value in any other case. + virtual void get_cooked_changeset(std::int_fast64_t index, util::AppendBuffer&, + version_type& server_version) const = 0; + + /// Persistently stores the point of progress of the consumer of cooked + /// changesets. + /// + /// The changeset index (CookedProgress::changeset_index) is the index (as + /// passed to get_cooked_changeset()) of the first unconsumed cooked + /// changset. Changesets at lower indexes will no longer be available. + /// + /// The intrachangeset progress field + /// (CookedProgress::intrachangeset_progress) will be faithfully persisted, + /// but will otherwise be treated as an opaque object by the history + /// internals. + /// + /// As well as allowing for later retrieval, the specification of the point + /// of progress of the consumer of cooked changesets also has the effect of + /// trimming obsolete cooked changesets from the Realm file (i.e., removal + /// of all changesets at indexes lower than + /// CookedProgress::intrachangeset_progress). Indeed, if this function is + /// never called, but cooked changesets are continually being produced, then + /// the Realm file will grow without bounds. + /// + /// It is an error if the specified index (CookedProgress::changeset_index) + /// is lower than the index returned by get_cooked_progress(), and if it is + /// higher that the value returned by get_num_cooked_changesets(). + /// + /// \return The snapshot number produced by the transaction performed + /// internally in set_cooked_progress(). This is also the client-side sync + /// version, and it should be passed to + /// sync::Session::nonsync_transact_notify() if a synchronization session is + /// in progress for the same file while set_cooked_progress() is + /// called. Doing so, ensures that the server will be notified about the + /// released server versions as soon as possible. + /// + /// \throw InconsistentUseOfCookedHistory If this file does not have a + /// cooked history and one can no longer be added because changesets of + /// remote origin has already been integrated. + virtual version_type set_cooked_progress(CookedProgress) = 0; + + /// \brief Get the number of cooked changesets so far produced for this + /// Realm. + /// + /// This is the same thing as is returned via \a num_changesets by + /// get_cooked_status(). + std::int_fast64_t get_num_cooked_changesets() const noexcept; + + /// \brief Returns the persisted progress that was last stored by + /// set_cooked_progress(). + /// + /// This is the same thing as is returned via \a progress by + /// get_cooked_status() when invoked with a server version of zero. + CookedProgress get_cooked_progress() const noexcept; + + /// Same as get_cooked_changeset(std::int_fast64_t, + /// util::AppendBuffer&, version_type&) but does not retreived the + /// server version. + void get_cooked_changeset(std::int_fast64_t index, util::AppendBuffer&) const; + + /// Return an upload cursor as it would be when the uploading process + /// reaches the snapshot to which the current transaction is bound. + /// + /// **CAUTION:** Must be called only while a transaction (read or write) is + /// in progress via the SharedGroup object associated with this history + /// object. + virtual UploadCursor get_upload_anchor_of_current_transact(const Transaction&) const = 0; + + /// Return the synchronization changeset of the current transaction as it + /// would be if that transaction was committed at this time. + /// + /// The returned memory reference may be invalidated by subsequent + /// operations on the Realm state. + /// + /// **CAUTION:** Must be called only while a write transaction is in + /// progress via the SharedGroup object associated with this history object. + virtual util::StringView get_sync_changeset_of_current_transact(const Transaction&) const noexcept = 0; + +protected: + ClientReplication(const std::string& realm_path); +}; + + +/// \brief Abstract interface for changeset cookers. +/// +/// Note, it is completely up to the application to decide what a cooked +/// changeset is. History objects (instances of ClientHistory) are required to +/// treat cooked changesets as opaque entities. For an example of a concrete +/// changeset cooker, see TrivialChangesetCooker which defines the cooked +/// changesets to be identical copies of the raw changesets. +class ClientReplication::ChangesetCooker { +public: + virtual ~ChangesetCooker() {} + + /// \brief An opportunity to produce a cooked changeset. + /// + /// When the implementation chooses to produce a cooked changeset, it must + /// write the cooked changeset to the specified buffer, and return + /// true. When the implementation chooses not to produce a cooked changeset, + /// it must return false. The implementation is allowed to write to the + /// buffer, and return false, and in that case, the written data will be + /// ignored. + /// + /// \param prior_state The state of the local Realm on which the specified + /// raw changeset is based. + /// + /// \param changeset, changeset_size The raw changeset. + /// + /// \param buffer The buffer to which the cooked changeset must be written. + /// + /// \return True if a cooked changeset was produced. Otherwise false. + virtual bool cook_changeset(const Group& prior_state, const char* changeset, std::size_t changeset_size, + util::AppendBuffer& buffer) = 0; +}; + + +class ClientReplication::Config { +public: + Config() {} + + /// Must be set to true if, and only if the created history object + /// represents (is owned by) the sync agent of the specified Realm file. At + /// most one such instance is allowed to participate in a Realm file access + /// session at any point in time. Ordinarily the sync agent is encapsulated + /// by the sync::Client class, and the history instance representing the + /// agent is created transparently by sync::Client (one history instance per + /// sync::Session object). + bool owner_is_sync_agent = false; + + /// If a changeset cooker is specified, then the created history object will + /// allow for a cooked changeset to be produced for each changeset of remote + /// origin; that is, for each changeset that is integrated during the + /// execution of ClientHistory::integrate_remote_changesets(). If no + /// changeset cooker is specified, then no cooked changesets will be + /// produced on behalf of the created history object. + /// + /// ClientHistory::integrate_remote_changesets() will pass each incoming + /// changeset to the cooker after operational transformation; that is, when + /// the chageset is ready to be applied to the local Realm state. + std::shared_ptr changeset_cooker; +}; + +/// \brief Create a "sync history" implementation of the realm::Replication +/// interface. +/// +/// The intended role for such an object is as a plugin for new +/// realm::DB objects. +std::unique_ptr make_client_replication(const std::string& realm_path, + ClientReplication::Config = {}); + + +// Implementation + +inline ClientReplicationBase::ClientReplicationBase(const std::string& realm_path) + : SyncReplication{realm_path} // Throws +{ +} + +inline timestamp_type generate_changeset_timestamp() noexcept +{ + namespace chrono = std::chrono; + // Unfortunately, C++11 does not specify what the epoch is for + // `chrono::system_clock` (or for any other clock). It is believed, however, + // that there is a de-facto standard, that the Epoch for + // `chrono::system_clock` is the Unix epoch, i.e., 1970-01-01T00:00:00Z. See + // http://stackoverflow.com/a/29800557/1698548. Additionally, it is assumed + // that leap seconds are not included in the value returned by + // time_since_epoch(), i.e., that it conforms to POSIX time. This is known + // to be true on Linux. + // + // FIXME: Investigate under which conditions OS X agrees with POSIX about + // not including leap seconds in the value returned by time_since_epoch(). + // + // FIXME: Investigate whether Microsoft Windows agrees with POSIX about + // about not including leap seconds in the value returned by + // time_since_epoch(). + auto time_since_epoch = chrono::system_clock::now().time_since_epoch(); + std::uint_fast64_t millis_since_epoch = chrono::duration_cast(time_since_epoch).count(); + // `offset_in_millis` is the number of milliseconds between + // 1970-01-01T00:00:00Z and 2015-01-01T00:00:00Z not counting leap seconds. + std::uint_fast64_t offset_in_millis = 1420070400000ULL; + return timestamp_type(millis_since_epoch - offset_in_millis); +} + +inline void map_changeset_timestamp(timestamp_type timestamp, std::time_t& seconds_since_epoch, + long& nanoseconds) noexcept +{ + std::uint_fast64_t offset_in_millis = 1420070400000ULL; + std::uint_fast64_t millis_since_epoch = std::uint_fast64_t(offset_in_millis + timestamp); + seconds_since_epoch = std::time_t(millis_since_epoch / 1000); + nanoseconds = long(millis_since_epoch % 1000 * 1000000L); +} + +class InconsistentUseOfCookedHistory : public std::exception { +public: + InconsistentUseOfCookedHistory(const char* message) noexcept + : m_message{message} + { + } + const char* what() const noexcept override final + { + return m_message; + } + +private: + const char* m_message; +}; + +class BadCookedServerVersion : public std::exception { +public: + BadCookedServerVersion(const char* message) noexcept + : m_message{message} + { + } + const char* what() const noexcept override final + { + return m_message; + } + +private: + const char* m_message; +}; + +inline ClientReplication::ClientReplication(const std::string& realm_path) + : ClientReplicationBase{realm_path} // Throws +{ +} + +inline std::int_fast64_t ClientReplication::get_num_cooked_changesets() const noexcept +{ + version_type server_version = 0; // Skip nothing + std::int_fast64_t num_changesets = 0; + ClientReplication::CookedProgress progress; + std::int_fast64_t num_skipped_changesets = 0; + get_cooked_status(server_version, num_changesets, progress, num_skipped_changesets); + REALM_ASSERT(progress.changeset_index <= num_changesets); + REALM_ASSERT(num_skipped_changesets == 0); + return num_changesets; +} + +inline auto ClientReplication::get_cooked_progress() const noexcept -> CookedProgress +{ + version_type server_version = 0; // Skip nothing + std::int_fast64_t num_changesets = 0; + ClientReplication::CookedProgress progress; + std::int_fast64_t num_skipped_changesets = 0; + get_cooked_status(server_version, num_changesets, progress, num_skipped_changesets); + REALM_ASSERT(progress.changeset_index <= num_changesets); + REALM_ASSERT(num_skipped_changesets == 0); + return progress; +} + +inline void ClientReplication::get_cooked_changeset(std::int_fast64_t index, util::AppendBuffer& buffer) const +{ + version_type server_version; // Dummy + get_cooked_changeset(index, buffer, server_version); // Throws +} + +} // namespace sync +} // namespace realm + +#endif // REALM_SYNC_HISTORY_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/instruction_applier.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/instruction_applier.hpp new file mode 100644 index 0000000..4b654de --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/instruction_applier.hpp @@ -0,0 +1,199 @@ +/************************************************************************* + * + * Copyright 2017 Realm Inc. + * + * 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 REALM_SYNC_IMPL_INSTRUCTION_APPLIER_HPP +#define REALM_SYNC_IMPL_INSTRUCTION_APPLIER_HPP + +#include +#include +#include +#include +#include + +#include + +namespace realm { +namespace sync { + +struct Changeset; + +struct InstructionApplier { + explicit InstructionApplier(Transaction&, TableInfoCache&) noexcept; + + /// Throws BadChangesetError if application fails due to a problem with the + /// changeset. + /// + /// FIXME: Consider using std::error_code instead of throwing + /// BadChangesetError. + void apply(const Changeset&, util::Logger*); + + void begin_apply(const Changeset&, util::Logger*) noexcept; + void end_apply() noexcept; + +protected: + StringData get_string(InternString) const; + StringData get_string(StringBufferRange) const; + BinaryData get_binary(StringBufferRange) const; +#define REALM_DECLARE_INSTRUCTION_HANDLER(X) void operator()(const Instruction::X&); + REALM_FOR_EACH_INSTRUCTION_TYPE(REALM_DECLARE_INSTRUCTION_HANDLER) +#undef REALM_DECLARE_INSTRUCTION_HANDLER + friend struct Instruction; // to allow visitor + + template + static void apply(A& applier, const Changeset&, util::Logger*); + + // Allows for in-place modification of changeset while applying it + template + static void apply(A& applier, Changeset&, util::Logger*); + + TableRef table_for_class_name(StringData) const; // Throws + + template + REALM_NORETURN void bad_transaction_log(const char*, Params&&...) const; + + Transaction& m_transaction; + TableInfoCache& m_table_info_cache; + + template + void log(const char* fmt, Args&&... args) + { + if (m_logger) { + m_logger->trace(fmt, std::forward(args)...); // Throws + } + } + +private: + const Changeset* m_log = nullptr; + util::Logger* m_logger = nullptr; + + TableNameBuffer m_table_name_buffer; + InternString m_last_table_name; + InternString m_last_field_name; + TableRef m_last_table; + ColKey m_last_field; + util::Optional m_last_object_key; + util::Optional m_last_object; + std::unique_ptr m_last_list; + + StringData get_table_name(const Instruction::TableInstruction&, const char* instr = "(unspecified)"); + TableRef get_table(const Instruction::TableInstruction&, const char* instr = "(unspecified)"); + + // Traverse the path and find the bottom object, and treat the last string + // element as a field name. If the last element is an integer, treat the + // next-to-last element as the last field name. + std::tuple get_field(const Instruction::PathInstruction&, const char* instr = "(unspecified)"); + + // Same as get_field, but expects the field in question to be a list. + LstBase& get_list(const Instruction::PathInstruction&, const char* instr = "(unspecified)"); + + // Note: This may return a non-invalid ObjKey if the key is dangling. + ObjKey get_object_key(Table& table, const Instruction::PrimaryKey&, const char* instr = "(unspecified)") const; + util::Optional get_top_object(const Instruction::ObjectInstruction&, const char* instr = "(unspecified)"); + + + struct SetTargetInfo { + StringData table_name; + StringData col_name; + DataType type; + bool nullable; + bool is_embedded_link = false; + }; + template + void set_value(const SetTargetInfo& info, const Instruction::Payload& value, F&& setter, + const char* instr = "(unspecified)"); +}; + + +// Implementation + +inline InstructionApplier::InstructionApplier(Transaction& group, TableInfoCache& table_info_cache) noexcept + : m_transaction(group) + , m_table_info_cache(table_info_cache) +{ +} + +inline void InstructionApplier::begin_apply(const Changeset& log, util::Logger* logger) noexcept +{ + m_log = &log; + m_logger = logger; +} + +inline void InstructionApplier::end_apply() noexcept +{ + m_log = nullptr; + m_logger = nullptr; + m_last_table_name = InternString{}; + m_last_field_name = InternString{}; + m_last_table = TableRef{}; + m_last_field = ColKey{}; + m_last_object.reset(); + m_last_list.reset(); +} + +template +inline void InstructionApplier::apply(A& applier, const Changeset& changeset, util::Logger* logger) +{ + applier.begin_apply(changeset, logger); + for (auto instr : changeset) { + if (!instr) + continue; + instr->visit(applier); // Throws +#if REALM_DEBUG + applier.m_table_info_cache.verify(); +#endif + } + applier.end_apply(); +} + +template +inline void InstructionApplier::apply(A& applier, Changeset& changeset, util::Logger* logger) +{ + applier.begin_apply(changeset, logger); + for (auto instr : changeset) { + if (!instr) + continue; + instr->visit(applier); // Throws +#if REALM_DEBUG + applier.m_table_info_cache.verify(); +#endif + } + applier.end_apply(); +} + +inline void InstructionApplier::apply(const Changeset& log, util::Logger* logger) +{ + apply(*this, log, logger); // Throws +} + +template +REALM_NORETURN void InstructionApplier::bad_transaction_log(const char* msg, Params&&... params) const +{ + // FIXME: Provide a way to format strings without going through a logger implementation. + std::stringstream ss; + util::StreamLogger logger{ss}; + logger.error(msg, std::forward(params)...); + // FIXME: Avoid throwing in normal program flow (since changesets can come + // in over the network, defective changesets are part of normal program + // flow). + throw BadChangesetError{ss.str()}; +} + +} // namespace sync +} // namespace realm + +#endif // REALM_SYNC_IMPL_INSTRUCTION_APPLIER_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/instruction_replication.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/instruction_replication.hpp new file mode 100644 index 0000000..71241f0 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/instruction_replication.hpp @@ -0,0 +1,251 @@ +/************************************************************************* + * + * Copyright 2017 Realm Inc. + * + * 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 REALM_SYNC_IMPL_INSTRUCTION_REPLICATION_HPP +#define REALM_SYNC_IMPL_INSTRUCTION_REPLICATION_HPP + +#include +#include +#include +#include + +namespace realm { +namespace sync { + + +class SyncReplication : public TrivialReplication { +public: + explicit SyncReplication(const std::string& realm_path); + void set_short_circuit(bool) noexcept; + bool is_short_circuited() const noexcept; + + // reset() resets the encoder, the selected tables and the cache. It is + // called by do_initiate_transact(), but can be called at the other times + // as well. + virtual void reset(); + + ChangesetEncoder& get_instruction_encoder() noexcept; + const ChangesetEncoder& get_instruction_encoder() const noexcept; + + //@{ + /// Generate instructions for Object Store tables. These must be called + /// prior to calling the equivalent functions in Core's API. When creating a + /// class-like table, `add_class()` must be called prior to + /// `Group::insert_group_level_table()`. Similarly, `create_object()` or + /// `create_object_with_primary_key()` must be called prior to + /// `Table::insert_empty_row()` and/or `Table::set_int_unique()` or + /// `Table::set_string_unique()` or `Table::set_null_unique()`. + /// + /// If a class-like table is added, or an object-like row is inserted, + /// without calling these methods first, an exception will be thrown. + /// + /// A "class-like table" is defined as a table whose name begins with + /// "class_" (this is the convention used by Object Store). Non-class-like + /// tables can be created and modified using Core's API without calling + /// these functions, because they do not result in instructions being + /// emitted. + void prepare_erase_table(StringData table_name); + //@} + + // TrivialReplication interface: + void initialize(DB&) override; + + // TransactLogConvenientEncoder interface: + void add_class(TableKey tk, StringData table_name, bool is_embedded) override; + void add_class_with_primary_key(TableKey tk, StringData table_name, DataType pk_type, StringData pk_field, + bool nullable) override; + void create_object(const Table*, GlobalKey) override; + void create_object_with_primary_key(const Table*, GlobalKey, Mixed) override; + void erase_group_level_table(TableKey table_key, size_t num_tables) override; + void rename_group_level_table(TableKey table_key, StringData new_name) override; + void insert_column(const Table*, ColKey col_key, DataType type, StringData name, Table* target_table) override; + void erase_column(const Table*, ColKey col_key) override; + void rename_column(const Table*, ColKey col_key, StringData name) override; + + void set_int(const Table*, ColKey col_key, ObjKey key, int_fast64_t value, _impl::Instruction variant) override; + void add_int(const Table*, ColKey col_key, ObjKey key, int_fast64_t value) override; + void set_bool(const Table*, ColKey col_key, ObjKey key, bool value, _impl::Instruction variant) override; + void set_float(const Table*, ColKey col_key, ObjKey key, float value, _impl::Instruction variant) override; + void set_double(const Table*, ColKey col_key, ObjKey key, double value, _impl::Instruction variant) override; + void set_string(const Table*, ColKey col_key, ObjKey key, StringData value, _impl::Instruction variant) override; + void set_binary(const Table*, ColKey col_key, ObjKey key, BinaryData value, _impl::Instruction variant) override; + void set_timestamp(const Table*, ColKey col_key, ObjKey key, Timestamp value, + _impl::Instruction variant) override; + void set_object_id(const Table*, ColKey col_key, ObjKey key, ObjectId value, _impl::Instruction variant) override; + void set_decimal(const Table*, ColKey col_key, ObjKey key, Decimal128 value, _impl::Instruction variant) override; + void set_link(const Table*, ColKey col_key, ObjKey key, ObjKey value, _impl::Instruction variant) override; + void set_null(const Table*, ColKey col_key, ObjKey key, _impl::Instruction variant) override; + void insert_substring(const Table*, ColKey col_key, ObjKey key, size_t pos, StringData) override; + void erase_substring(const Table*, ColKey col_key, ObjKey key, size_t pos, size_t size) override; + + void list_set_null(const ConstLstBase& list, size_t ndx) override; + void list_set_int(const ConstLstBase& Lst, size_t list_ndx, int64_t value) override; + void list_set_bool(const ConstLstBase& Lst, size_t list_ndx, bool value) override; + void list_set_float(const ConstLstBase& Lst, size_t list_ndx, float value) override; + void list_set_double(const ConstLstBase& Lst, size_t list_ndx, double value) override; + void list_set_string(const Lst& Lst, size_t list_ndx, StringData value) override; + void list_set_binary(const Lst& Lst, size_t list_ndx, BinaryData value) override; + void list_set_timestamp(const Lst& Lst, size_t list_ndx, Timestamp value) override; + void list_set_object_id(const ConstLstBase& list, size_t list_ndx, ObjectId value) override; + void list_set_decimal(const Lst& list, size_t list_ndx, Decimal128 value) override; + + void list_insert_int(const ConstLstBase& Lst, size_t list_ndx, int64_t value) override; + void list_insert_bool(const ConstLstBase& Lst, size_t list_ndx, bool value) override; + void list_insert_float(const ConstLstBase& Lst, size_t list_ndx, float value) override; + void list_insert_double(const ConstLstBase& Lst, size_t list_ndx, double value) override; + void list_insert_string(const Lst& Lst, size_t list_ndx, StringData value) override; + void list_insert_binary(const Lst& Lst, size_t list_ndx, BinaryData value) override; + void list_insert_timestamp(const Lst& Lst, size_t list_ndx, Timestamp value) override; + void list_insert_object_id(const ConstLstBase& list, size_t list_ndx, ObjectId value) override; + void list_insert_decimal(const Lst& list, size_t list_ndx, Decimal128 value) override; + + void remove_object(const Table*, ObjKey) override; + + void list_insert_null(const ConstLstBase&, size_t ndx) override; + void list_set_link(const Lst&, size_t link_ndx, ObjKey value) override; + void list_insert_link(const Lst&, size_t link_ndx, ObjKey value) override; + void list_move(const ConstLstBase&, size_t from_link_ndx, size_t to_link_ndx) override; + void list_erase(const ConstLstBase&, size_t link_ndx) override; + void list_clear(const ConstLstBase&) override; + + //@{ + + /// Implicit nullifications due to removal of target row. This is redundant + /// information from the point of view of replication, as the removal of the + /// target row will reproduce the implicit nullifications in the target + /// Realm anyway. The purpose of this instruction is to allow observers + /// (reactor pattern) to be explicitly notified about the implicit + /// nullifications. + + void nullify_link(const Table*, ColKey col_key, ObjKey key) override; + void link_list_nullify(const Lst&, size_t link_ndx) override; + //@} + + template + void emit(T instruction); + + // Returns true and populates m_last_table_name if instructions for the + // table should be emitted. + bool select_table(const Table&); + +protected: + // Replication interface: + void do_initiate_transact(Group& group, version_type current_version, bool history_updated) override; + +private: + bool m_short_circuit = false; + + ChangesetEncoder m_encoder; + DB* m_sg = nullptr; + std::unique_ptr m_cache; + + // Consistency checks: + std::string m_table_being_erased; + + REALM_NORETURN void unsupported_instruction() const; // Throws TransformError + + // Returns true and populates m_last_class_name if instructions for the + // owning table should be emitted. + bool select_list(const ConstLstBase&); // returns true if table behavior != ignored + + InternString emit_class_name(StringData table_name); + InternString emit_class_name(const Table& table); + Instruction::Payload::Type get_payload_type(DataType) const; + + template + void set(const Table*, ColKey col_key, ObjKey row_ndx, T payload, _impl::Instruction variant); + template + void list_set(const ConstLstBase& Lst, size_t ndx, T payload); + template + void list_insert(const ConstLstBase& Lst, size_t ndx, T payload); + template + auto as_payload(T value); + + Instruction::PrimaryKey as_primary_key(Mixed); + Instruction::PrimaryKey primary_key_for_object(const Table&, ObjKey key); + void populate_path_instr(Instruction::PathInstruction&, const Table&, ObjKey key, ColKey field); + void populate_path_instr(Instruction::PathInstruction&, const ConstLstBase&); + void populate_path_instr(Instruction::PathInstruction&, const ConstLstBase&, uint32_t ndx); + + // Cache information for the purpose of avoiding excessive string comparisons / interning + // lookups. + const Table* m_last_table = nullptr; + ObjKey m_last_object; + ColKey m_last_field; + InternString m_last_class_name; + util::Optional m_last_primary_key; + InternString m_last_field_name; +}; + +inline void SyncReplication::set_short_circuit(bool b) noexcept +{ + m_short_circuit = b; +} + +inline bool SyncReplication::is_short_circuited() const noexcept +{ + return m_short_circuit; +} + +inline ChangesetEncoder& SyncReplication::get_instruction_encoder() noexcept +{ + return m_encoder; +} + +inline const ChangesetEncoder& SyncReplication::get_instruction_encoder() const noexcept +{ + return m_encoder; +} + +template +inline void SyncReplication::emit(T instruction) +{ + REALM_ASSERT(!m_short_circuit); + m_encoder(instruction); +} + + +// Temporarily short-circuit replication +class TempShortCircuitReplication { +public: + TempShortCircuitReplication(SyncReplication& bridge) + : m_bridge(bridge) + { + m_was_short_circuited = bridge.is_short_circuited(); + bridge.set_short_circuit(true); + } + + ~TempShortCircuitReplication() + { + m_bridge.set_short_circuit(m_was_short_circuited); + } + + bool was_short_circuited() const noexcept + { + return m_was_short_circuited; + } + +private: + SyncReplication& m_bridge; + bool m_was_short_circuited; +}; + +} // namespace sync +} // namespace realm + +#endif // REALM_SYNC_IMPL_INSTRUCTION_REPLICATION_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/instructions.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/instructions.hpp new file mode 100644 index 0000000..4c5e410 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/instructions.hpp @@ -0,0 +1,1046 @@ + +#ifndef REALM_IMPL_INSTRUCTIONS_HPP +#define REALM_IMPL_INSTRUCTIONS_HPP + +#include +#include +#include // string conversion, debug prints +#include // shared_ptr +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace realm { + +namespace sync { + +#define REALM_FOR_EACH_INSTRUCTION_TYPE(X) \ + X(AddTable) \ + X(EraseTable) \ + X(AddColumn) \ + X(EraseColumn) \ + X(CreateObject) \ + X(EraseObject) \ + X(Set) \ + X(AddInteger) \ + X(ArrayInsert) \ + X(ArrayMove) \ + X(ArrayErase) \ + X(ArrayClear) + +struct StringBufferRange { + uint32_t offset, size; + + friend bool operator==(const StringBufferRange& lhs, const StringBufferRange& rhs) noexcept + { + return lhs.offset == rhs.offset && lhs.size == rhs.size; + } +}; + +struct InternString { + static const InternString npos; + explicit constexpr InternString(uint32_t v = uint32_t(-1)) noexcept + : value(v) + { + } + + uint32_t value; + + constexpr bool operator==(const InternString& other) const noexcept + { + return value == other.value; + } + constexpr bool operator!=(const InternString& other) const noexcept + { + return value != other.value; + } + constexpr bool operator<(const InternString& other) const noexcept + { + return value < other.value; + } + + explicit operator bool() const noexcept + { + return (value != npos.value); + } +}; + +struct Instruction; + +namespace instr { + +using PrimaryKey = mpark::variant; + +struct Path { + using Element = mpark::variant; + + // FIXME: Use a "small_vector" type for this -- most paths are very short. + // Alternatively, we could use some kind of interning with copy-on-write, + // but that seems complicated. + std::vector m_path; + + size_t size() const noexcept + { + return m_path.size(); + } + + // If this path is referring to an element of an array (the last path + // element is an integer index), return true. + bool is_array_index() const noexcept + { + return !m_path.empty() && mpark::holds_alternative(m_path.back()); + } + + uint32_t& index() noexcept + { + REALM_ASSERT(is_array_index()); + return mpark::get(m_path.back()); + } + + uint32_t index() const noexcept + { + REALM_ASSERT(is_array_index()); + return mpark::get(m_path.back()); + } + + Element& back() noexcept + { + REALM_ASSERT(!m_path.empty()); + return m_path.back(); + } + + const Element& back() const noexcept + { + REALM_ASSERT(!m_path.empty()); + return m_path.back(); + } + + Element& operator[](size_t idx) noexcept + { + REALM_ASSERT(idx < m_path.size()); + return m_path[idx]; + } + + const Element& operator[](size_t idx) const noexcept + { + REALM_ASSERT(idx < m_path.size()); + return m_path[idx]; + } + + void push_back(Element element) + { + m_path.push_back(element); + } + + friend bool operator==(const Path& lhs, const Path& rhs) noexcept + { + return lhs.m_path == rhs.m_path; + } +}; + +struct Payload { + struct ObjectValue { + }; + + /// Payload data types, corresponding loosely to the `DataType` enum in + /// Core, but with some special values: + /// + /// - Null (0) indicates a NULL value of any type. + /// - GlobalKey (-1) indicates an internally generated object ID. + /// - ObjectValue (-2) indicates the creation of an embedded object. + /// + /// Furthermore, link values for both Link and LinkList columns are + /// represented by a single Link type. + enum class Type : int8_t { + // Special value indicating that an embedded object should be created at + // the position. + ObjectValue = -2, + GlobalKey = -1, + Null = 0, + Int = 1, + Bool = 2, + String = 3, + Binary = 4, + Timestamp = 5, + Float = 6, + Double = 7, + Decimal = 8, + Link = 9, + ObjectId = 10, + }; + + struct Link { + InternString target_table; + PrimaryKey target; + + friend bool operator==(const Link& lhs, const Link& rhs) noexcept + { + return lhs.target_table == rhs.target_table && lhs.target == rhs.target; + } + }; + + union Data { + GlobalKey key; + int64_t integer; + bool boolean; + StringBufferRange str; + StringBufferRange binary; + Timestamp timestamp; + float fnum; + double dnum; + Decimal128 decimal; + ObjectId object_id; + Link link; + + Data() {} + }; + + Data data; + Type type; + + Payload() + : Payload(realm::util::none) + { + } + explicit Payload(bool value) noexcept + : type(Type::Bool) + { + data.boolean = value; + } + explicit Payload(int64_t value) noexcept + : type(Type::Int) + { + data.integer = value; + } + explicit Payload(float value) noexcept + : type(Type::Float) + { + data.fnum = value; + } + explicit Payload(double value) noexcept + : type(Type::Double) + { + data.dnum = value; + } + explicit Payload(Link value) noexcept + : type(Type::Link) + { + data.link = value; + } + explicit Payload(StringBufferRange value, bool is_binary = false) noexcept + : type(is_binary ? Type::Binary : Type::String) + { + if (is_binary) { + data.binary = value; + } + else { + data.str = value; + } + } + explicit Payload(realm::util::None) noexcept + : type(Type::Null) + { + } + + // Note: Intentionally implicit. + Payload(const ObjectValue&) noexcept + : type(Type::ObjectValue) + { + } + + explicit Payload(Timestamp value) noexcept + : type(value.is_null() ? Type::Null : Type::Timestamp) + { + if (value.is_null()) { + type = Type::Null; + } + else { + type = Type::Timestamp; + data.timestamp = value; + } + } + + explicit Payload(ObjectId value) noexcept + : type(Type::ObjectId) + { + data.object_id = value; + } + + explicit Payload(Decimal128 value) noexcept + { + if (value.is_null()) { + type = Type::Null; + } + else { + type = Type::Decimal; + data.decimal = value; + } + } + + Payload(const Payload&) noexcept = default; + Payload& operator=(const Payload&) noexcept = default; + + bool is_null() const noexcept + { + return type == Type::Null; + } + + friend bool operator==(const Payload& lhs, const Payload& rhs) noexcept + { + if (lhs.type == rhs.type) { + switch (lhs.type) { + case Type::ObjectValue: + return true; + case Type::GlobalKey: + return lhs.data.key == rhs.data.key; + case Type::Null: + return true; + case Type::Int: + return lhs.data.integer == rhs.data.integer; + case Type::Bool: + return lhs.data.boolean == rhs.data.boolean; + case Type::String: + return lhs.data.str == rhs.data.str; + case Type::Binary: + return lhs.data.binary == rhs.data.binary; + case Type::Timestamp: + return lhs.data.timestamp == rhs.data.timestamp; + case Type::Float: + return lhs.data.fnum == rhs.data.fnum; + case Type::Double: + return lhs.data.dnum == rhs.data.dnum; + case Type::Decimal: + return lhs.data.decimal == rhs.data.decimal; + case Type::Link: + return lhs.data.link == rhs.data.link; + case Type::ObjectId: + return lhs.data.object_id == rhs.data.object_id; + } + } + return false; + } + + friend bool operator!=(const Payload& lhs, const Payload& rhs) noexcept + { + return !(lhs == rhs); + } +}; + +/// All instructions are TableInstructions. +struct TableInstruction { + InternString table; + +protected: + bool operator==(const TableInstruction& rhs) const noexcept + { + return table == rhs.table; + } +}; + +/// All instructions except schema instructions are ObjectInstructions. +struct ObjectInstruction : TableInstruction { + PrimaryKey object; + +protected: + bool operator==(const ObjectInstruction& rhs) const noexcept + { + return TableInstruction::operator==(rhs) && object == rhs.object; + } +}; + +/// All instructions except schema instructions and CreateObject/EraseObject are PathInstructions. +struct PathInstruction : ObjectInstruction { + InternString field; + Path path; + + uint32_t& index() noexcept + { + return path.index(); + } + + uint32_t index() const noexcept + { + return path.index(); + } + +protected: + bool operator==(const PathInstruction& rhs) const noexcept + { + return ObjectInstruction::operator==(rhs) && field == rhs.field && path == rhs.path; + } +}; + +struct AddTable : TableInstruction { + // Note: Tables "without" a primary key have a secret primary key of type + // ObjKey. The field name of such primary keys is assumed to be "_id". + struct PrimaryKeySpec { + InternString field; + Payload::Type type; + bool nullable; + + bool operator==(const PrimaryKeySpec& rhs) const noexcept + { + return field == rhs.field && type == rhs.type && nullable == rhs.nullable; + } + }; + + struct EmbeddedTable { + bool operator==(const EmbeddedTable&) const noexcept + { + return true; + } + }; + + mpark::variant type; + + bool operator==(const AddTable& rhs) const noexcept + { + return TableInstruction::operator==(rhs) && type == rhs.type; + } +}; + +struct EraseTable : TableInstruction { + using TableInstruction::TableInstruction; + + bool operator==(const EraseTable& rhs) const noexcept + { + return TableInstruction::operator==(rhs); + } +}; + +struct AddColumn : TableInstruction { + using TableInstruction::TableInstruction; + + InternString field; + Payload::Type type; + bool nullable; + bool list; + InternString link_target_table; + + bool operator==(const AddColumn& rhs) const noexcept + { + return TableInstruction::operator==(rhs) && field == rhs.field && type == rhs.type && + nullable == rhs.nullable && list == rhs.list && link_target_table == rhs.link_target_table; + } +}; + +struct EraseColumn : TableInstruction { + using TableInstruction::TableInstruction; + InternString field; + + bool operator==(const EraseColumn& rhs) const noexcept + { + return TableInstruction::operator==(rhs) && field == rhs.field; + } +}; + +struct CreateObject : ObjectInstruction { + using ObjectInstruction::ObjectInstruction; + + bool operator==(const CreateObject& rhs) const noexcept + { + return ObjectInstruction::operator==(rhs); + } +}; + +struct EraseObject : ObjectInstruction { + using ObjectInstruction::ObjectInstruction; + + bool operator==(const EraseObject& rhs) const noexcept + { + return ObjectInstruction::operator==(rhs); + } +}; + +struct Set : PathInstruction { + using PathInstruction::PathInstruction; + + // Note: For "ArraySet", the path ends with an integer. + Payload value; + union { + bool is_default; // For fields + uint32_t prior_size; // For "ArraySet" + }; + + Set() + : prior_size(0) + { + } + + bool is_array_set() const noexcept + { + return path.is_array_index(); + } + + bool operator==(const Set& rhs) const noexcept + { + return PathInstruction::operator==(rhs) && value == rhs.value && + (is_array_set() ? is_default == rhs.is_default : prior_size == rhs.prior_size); + } +}; + +struct AddInteger : PathInstruction { + using PathInstruction::PathInstruction; + int64_t value; + + bool operator==(const AddInteger& rhs) const noexcept + { + return PathInstruction::operator==(rhs) && value == rhs.value; + } +}; + +struct ArrayInsert : PathInstruction { + // Note: The insertion index is the last path component. + using PathInstruction::PathInstruction; + Payload value; + uint32_t prior_size; + + bool operator==(const ArrayInsert& rhs) const noexcept + { + return PathInstruction::operator==(rhs) && value == rhs.value && prior_size == rhs.prior_size; + } +}; + +struct ArrayMove : PathInstruction { + // Note: The move-from index is the last path component. + using PathInstruction::PathInstruction; + uint32_t ndx_2; + uint32_t prior_size; + + bool operator==(const ArrayMove& rhs) const noexcept + { + return PathInstruction::operator==(rhs) && ndx_2 == rhs.ndx_2 && prior_size == rhs.prior_size; + } +}; + +struct ArrayErase : PathInstruction { + // Note: The erased index is the last path component. + using PathInstruction::PathInstruction; + uint32_t prior_size; + + bool operator==(const ArrayErase& rhs) const noexcept + { + return PathInstruction::operator==(rhs) && prior_size == rhs.prior_size; + } +}; + +struct ArrayClear : PathInstruction { + using PathInstruction::PathInstruction; + uint32_t prior_size; + + bool operator==(const ArrayClear& rhs) const noexcept + { + return PathInstruction::operator==(rhs) && prior_size == rhs.prior_size; + } +}; + +} // namespace instr + +struct Instruction { +#define REALM_DECLARE_INSTRUCTION_STRUCT(X) using X = instr::X; + REALM_FOR_EACH_INSTRUCTION_TYPE(REALM_DECLARE_INSTRUCTION_STRUCT) +#undef REALM_DECLARE_INSTRUCTION_STRUCT + + using TableInstruction = instr::TableInstruction; + using ObjectInstruction = instr::ObjectInstruction; + using PathInstruction = instr::PathInstruction; + using PrimaryKey = instr::PrimaryKey; + using Payload = instr::Payload; + using Path = instr::Path; + using Vector = std::vector; + + // CAUTION: Any change to the enum values for the instruction types is a protocol-breaking + // change! + enum class Type : uint8_t { + AddTable = 0, + EraseTable = 1, + CreateObject = 2, + EraseObject = 3, + Set = 4, // Note: Also covers ArraySet + AddInteger = 5, + AddColumn = 6, + EraseColumn = 7, + ArrayInsert = 8, + ArrayMove = 9, + ArrayErase = 10, + ArrayClear = 11, + }; + + template + struct GetType; + template + struct GetInstructionType; + + template + Instruction(T instr); + + mpark::variant + m_instr; + + Type type() const noexcept; + + template + decltype(auto) visit(F&& lambda); + template + decltype(auto) visit(F&& lambda) const; + + template + T* get_if() noexcept; + + template + const T* get_if() const noexcept + { + return const_cast(*this).get_if(); + } + + template + T& get_as() + { + auto ptr = get_if(); + REALM_ASSERT(ptr); + return *ptr; + } + + template + const T& get_as() const + { + auto ptr = get_if(); + REALM_ASSERT(ptr); + return *ptr; + } + + bool operator==(const Instruction& other) const noexcept; + bool operator!=(const Instruction& other) const noexcept + { + return !(*this == other); + } + + bool is_vector() const noexcept + { + return mpark::holds_alternative(m_instr); + } + + size_t path_length() const noexcept; + + Vector& convert_to_vector(); + void insert(size_t pos, Instruction instr); + void erase(size_t pos); + size_t size() const noexcept; + bool is_empty() const noexcept; + Instruction& at(size_t) noexcept; + const Instruction& at(size_t) const noexcept; + +private: + template + struct Visitor; +}; + +inline const char* get_type_name(Instruction::Type type) +{ + switch (type) { +#define REALM_INSTRUCTION_TYPE_TO_STRING(X) \ + case Instruction::Type::X: \ + return #X; + REALM_FOR_EACH_INSTRUCTION_TYPE(REALM_INSTRUCTION_TYPE_TO_STRING) +#undef REALM_INSTRUCTION_TYPE_TO_STRING + } + return "(invalid)"; +} + +inline std::ostream& operator<<(std::ostream& os, Instruction::Type type) +{ + return os << get_type_name(type); +} + +inline const char* get_type_name(Instruction::Payload::Type type) +{ + using Type = Instruction::Payload::Type; + switch (type) { + case Type::ObjectValue: + return "ObjectValue"; + case Type::GlobalKey: + return "GlobalKey"; + case Type::Null: + return "Null"; + case Type::Int: + return "Int"; + case Type::Bool: + return "Bool"; + case Type::String: + return "String"; + case Type::Binary: + return "Binary"; + case Type::Timestamp: + return "Timestamp"; + case Type::Float: + return "Float"; + case Type::Double: + return "Double"; + case Type::Decimal: + return "Decimal"; + case Type::Link: + return "Link"; + case Type::ObjectId: + return "ObjectId"; + } + return "(unknown)"; +} + +inline std::ostream& operator<<(std::ostream& os, Instruction::Payload::Type type) +{ + return os << get_type_name(type); +} + +inline bool is_valid_key_type(Instruction::Payload::Type type) noexcept +{ + using Type = Instruction::Payload::Type; + switch (type) { + case Type::Null: + [[fallthrough]]; + case Type::Int: + [[fallthrough]]; + case Type::String: + [[fallthrough]]; + case Type::ObjectId: + [[fallthrough]]; + case Type::GlobalKey: + return true; + default: + return false; + } +} + +inline DataType get_data_type(Instruction::Payload::Type type) noexcept +{ + using Type = Instruction::Payload::Type; + switch (type) { + case Type::Int: + return type_Int; + case Type::Bool: + return type_Bool; + case Type::String: + return type_String; + case Type::Binary: + return type_Binary; + case Type::Timestamp: + return type_Timestamp; + case Type::Float: + return type_Float; + case Type::Double: + return type_Double; + case Type::Decimal: + return type_Decimal; + case Type::Link: + return type_Link; + case Type::ObjectId: + return type_ObjectId; + case Type::ObjectValue: + [[fallthrough]]; + case Type::GlobalKey: + [[fallthrough]]; + case Type::Null: + REALM_TERMINATE("Invalid data type"); + } + return type_Int; // Make compiler happy +} + +// 0x3f is the largest value that fits in a single byte in the variable-length +// encoded integer instruction format. +static constexpr uint8_t InstrTypeInternString = 0x3f; + +// This instruction code is only ever used internally by the Changeset class +// to allow insertion/removal while keeping iterators stable. Should never +// make it onto the wire. +static constexpr uint8_t InstrTypeMultiInstruction = 0xff; + +struct InstructionHandler { + /// Notify the handler that an InternString meta-instruction was found. + virtual void set_intern_string(uint32_t index, StringBufferRange) = 0; + + /// Notify the handler of the string value. The handler guarantees that the + /// returned string range is valid at least until the next invocation of + /// add_string_range(). + /// + /// Instances of `StringBufferRange` passed to operator() after invoking + /// this function are assumed to refer to ranges in this buffer. + virtual StringBufferRange add_string_range(StringData) = 0; + + /// Handle an instruction. + virtual void operator()(const Instruction&) = 0; +}; + + +/// Implementation: + +#define REALM_DEFINE_INSTRUCTION_GET_TYPE(X) \ + template <> \ + struct Instruction::GetType { \ + using Type = Instruction::X; \ + }; \ + template <> \ + struct Instruction::GetInstructionType { \ + static const Instruction::Type value = Instruction::Type::X; \ + }; +REALM_FOR_EACH_INSTRUCTION_TYPE(REALM_DEFINE_INSTRUCTION_GET_TYPE) +#undef REALM_DEFINE_INSTRUCTION_GET_TYPE + +template +Instruction::Instruction(T instr) + : m_instr(std::move(instr)) +{ + static_assert(!std::is_same_v); +} + +template +struct Instruction::Visitor { + F lambda; // reference type + Visitor(F lambda) + : lambda(lambda) + { + } + + template + decltype(auto) operator()(T& instr) + { + return lambda(instr); + } + + template + decltype(auto) operator()(const T& instr) + { + return lambda(instr); + } + + auto operator()(const Instruction::Vector&) -> decltype(lambda(std::declval())) + { + REALM_TERMINATE("visiting instruction vector"); + } + auto operator()(Instruction::Vector&) -> decltype(lambda(std::declval())) + { + REALM_TERMINATE("visiting instruction vector"); + } +}; + +template +inline decltype(auto) Instruction::visit(F&& lambda) +{ + // Cannot use std::visit, because it does not pass lvalue references to the visitor. + if (mpark::holds_alternative(m_instr)) { + REALM_TERMINATE("visiting instruction vector"); + } +#define REALM_VISIT_VARIANT(X) \ + else if (mpark::holds_alternative(m_instr)) \ + { \ + return lambda(mpark::get(m_instr)); \ + } + REALM_FOR_EACH_INSTRUCTION_TYPE(REALM_VISIT_VARIANT) +#undef REALM_VISIT_VARIANT + else + { + REALM_TERMINATE("Unhandled instruction variant entry"); + } +} + +template +inline decltype(auto) Instruction::visit(F&& lambda) const +{ + // Cannot use std::visit, because it does not pass lvalue references to the visitor. + if (mpark::holds_alternative(m_instr)) { + REALM_TERMINATE("visiting instruction vector"); + } +#define REALM_VISIT_VARIANT(X) \ + else if (mpark::holds_alternative(m_instr)) \ + { \ + return lambda(mpark::get(m_instr)); \ + } + REALM_FOR_EACH_INSTRUCTION_TYPE(REALM_VISIT_VARIANT) +#undef REALM_VISIT_VARIANT + else + { + REALM_TERMINATE("Unhandled instruction variant entry"); + } +} + +inline Instruction::Type Instruction::type() const noexcept +{ + return visit([](auto&& instr) { + using T = std::remove_cv_t>; + return GetInstructionType::value; + }); +} + +inline bool Instruction::operator==(const Instruction& other) const noexcept +{ + return m_instr == other.m_instr; +} + +template +inline T* Instruction::get_if() noexcept +{ + // FIXME: Is there a way to express this without giant switch statements? Note: Putting the + // base class into a union does not seem to be allowed by the standard. + if constexpr (std::is_same_v) { + // This should compile to nothing but a comparison of the type. + return visit([](auto& instr) -> TableInstruction* { + return &instr; + }); + } + else if constexpr (std::is_same_v) { + // This should compile to nothing but a comparison of the type. + return visit(util::overloaded{ + [](AddTable&) -> ObjectInstruction* { + return nullptr; + }, + [](EraseTable&) -> ObjectInstruction* { + return nullptr; + }, + [](AddColumn&) -> ObjectInstruction* { + return nullptr; + }, + [](EraseColumn&) -> ObjectInstruction* { + return nullptr; + }, + [](auto& instr) -> ObjectInstruction* { + return &instr; + }, + }); + } + else if constexpr (std::is_same_v) { + // This should compile to nothing but a comparison of the type. + return visit(util::overloaded{ + [](AddTable&) -> PathInstruction* { + return nullptr; + }, + [](EraseTable&) -> PathInstruction* { + return nullptr; + }, + [](AddColumn&) -> PathInstruction* { + return nullptr; + }, + [](EraseColumn&) -> PathInstruction* { + return nullptr; + }, + [](CreateObject&) -> PathInstruction* { + return nullptr; + }, + [](EraseObject&) -> PathInstruction* { + return nullptr; + }, + [](auto& instr) -> PathInstruction* { + return &instr; + }, + }); + } + else { + return mpark::get_if(&m_instr); + } +} + +inline size_t Instruction::size() const noexcept +{ + if (auto vec = mpark::get_if(&m_instr)) { + return vec->size(); + } + return 1; +} + +inline bool Instruction::is_empty() const noexcept +{ + return size() == 0; +} + +inline Instruction& Instruction::at(size_t idx) noexcept +{ + if (auto vec = mpark::get_if(&m_instr)) { + REALM_ASSERT(idx < vec->size()); + return (*vec)[idx]; + } + REALM_ASSERT(idx == 0); + return *this; +} + +inline const Instruction& Instruction::at(size_t idx) const noexcept +{ + if (auto vec = mpark::get_if(&m_instr)) { + REALM_ASSERT(idx < vec->size()); + return (*vec)[idx]; + } + REALM_ASSERT(idx == 0); + return *this; +} + +inline size_t Instruction::path_length() const noexcept +{ + // Find the path length of the instruction. This affects how OT decides + // which instructions are potentially nesting. + // + // AddTable/EraseTable: Length 1 + // AddColumn/EraseColumn: Length 2 (table, field) + // Object instructions: Length 2 (table, object) + // Path instructions: Length 3 + m_path.size (table, object, field, path...) + if (auto path_instr = get_if()) { + return 3 + path_instr->path.size(); + } + if (get_if()) { + return 2; + } + switch (type()) { + case Instruction::Type::AddColumn: + [[fallthrough]]; + case Instruction::Type::EraseColumn: { + return 2; + } + case Instruction::Type::AddTable: + [[fallthrough]]; + case Instruction::Type::EraseTable: { + return 1; + } + default: + REALM_TERMINATE("Unhandled instruction type in Instruction::path_len()"); + } +} + +inline Instruction::Vector& Instruction::convert_to_vector() +{ + if (auto v = mpark::get_if(&m_instr)) { + return *v; + } + else { + Vector vec; + vec.emplace_back(std::move(*this)); + m_instr = std::move(vec); + return mpark::get(m_instr); + } +} + +inline void Instruction::insert(size_t idx, Instruction instr) +{ + auto& vec = convert_to_vector(); + REALM_ASSERT(idx <= vec.size()); + vec.emplace(vec.begin() + idx, std::move(instr)); +} + +inline void Instruction::erase(size_t idx) +{ + auto& vec = convert_to_vector(); + REALM_ASSERT(idx < vec.size()); + vec.erase(vec.begin() + idx); +} + +} // namespace sync +} // namespace realm + +#endif // REALM_IMPL_INSTRUCTIONS_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/object.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/object.hpp new file mode 100644 index 0000000..d50390d --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/object.hpp @@ -0,0 +1,293 @@ +/************************************************************************* + * + * Copyright 2017 Realm Inc. + * + * 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 REALM_SYNC_OBJECT_HPP +#define REALM_SYNC_OBJECT_HPP + +#include +#include +#include +#include + +#include + +#include + +/// This file presents a convenience API for making changes to a Realm file that +/// adhere to the conventions of assigning stable IDs to every object. + +namespace realm { + +class Group; +class ReadTransaction; +class WriteTransaction; + +namespace sync { + +class SyncHistory; +struct TableInfoCache; + +/// Determine whether the Group has a sync-type history, and therefore whether +/// it supports globally stable object IDs. +/// +/// The Group does not need to be in a transaction. +bool has_object_ids(const Table&); + +/// Determine whether object IDs for objects without primary keys are globally +/// stable. This is true if and only if the Group has been in touch with the +/// server (or is the server), and will remain true forever thereafter. +/// +/// It is an error to call this function for groups that do not have object IDs +/// (i.e. where `has_object_ids()` returns false). +/// +/// The Group is assumed to be in a read transaction. +bool is_object_id_stability_achieved(const DB&, const Transaction&); + +/// Create a table with an object ID column. +/// +/// It is an error to add tables to Groups with a sync history type directly. +/// This function or related functions must be used instead. +/// +/// The resulting table will be born with 1 column, which is a column used +/// in the maintenance of object IDs. +/// +/// NOTE: The table name must begin with the prefix "class_" in accordance with +/// Object Store conventions. +/// +/// The Group must be in a write transaction. +inline TableRef create_table(Transaction& wt, StringData name) +{ + return wt.get_or_add_table(name); +} + +/// Create a table with an object ID column and a primary key column. +/// +/// It is an error to add tables to Groups with a sync history type directly. +/// This function or related functions must be used instead. +/// +/// The resulting table will be born with 2 columns, which is a column used +/// in the maintenance of object IDs and the requested primary key column. +/// The primary key column must have either integer or string type, and it +/// will be given the name provided in the argument \a pk_column_name. +/// +/// The 'pk' metadata table is updated with information about the primary key +/// column. If the 'pk' table does not yet exist, it is created. +/// +/// Please note: The 'pk' metadata table will not be synchronized directly, +/// so subsequent updates to it will be lost (as they constitute schema-breaking +/// changes). +/// +/// NOTE: The table name must begin with the prefix "class_" in accordance with +/// Object Store conventions. +/// +/// The Group must be in a write transaction. +inline TableRef create_table_with_primary_key(Transaction& wt, StringData name, DataType pk_type, + StringData pk_column_name, bool nullable = false) +{ + if (TableRef table = wt.get_table(name)) { + if (!table->get_primary_key_column() || + table->get_column_name(table->get_primary_key_column()) != pk_column_name || + table->is_nullable(table->get_primary_key_column()) != nullable) { + throw std::runtime_error("Inconsistent schema"); + } + return table; + } + return wt.add_table_with_primary_key(name, pk_type, pk_column_name, nullable); +} + + +//@{ +/// Erase table and update metadata. +/// +/// It is an error to erase tables via the Group API, because it does not +/// correctly update metadata tables (such as the `pk` table). +void erase_table(Transaction&, TableInfoCache& table_info_cache, StringData name); +void erase_table(Transaction&, TableInfoCache& table_info_cache, TableRef); +//@} + +/// Create an array column with the specified element type. +/// +/// The result will be a column of type type_Table with one subcolumn named +/// "!ARRAY_VALUE" of the specified element type and nullability. +/// +/// Return the column index of the inserted array column. +ColKey add_array_column(Table&, DataType element_type, StringData column_name, bool is_nullable = false); + + +/// Determine whether it is safe to call `object_id_for_row()` on tables without +/// primary keys. If the table has a primary key, always returns true. +bool has_globally_stable_object_ids(const Table&); + +bool table_has_primary_key(const TableInfoCache&, const Table&); + +/// Get the globally unique object ID for the row. +/// +/// If the table has a primary key, this is guaranteed to succeed. Otherwise, if +/// the server has not been contacted yet (`has_globally_stable_object_ids()` +/// returns false), an exception is thrown. +GlobalKey object_id_for_row(const TableInfoCache&, const Table&, ObjKey); +GlobalKey object_id_for_row(const TableInfoCache&, const ConstObj&); + +PrimaryKey primary_key_for_row(const Table&, ObjKey); +PrimaryKey primary_key_for_row(const ConstObj&); + +/// Get the index of the row with the object ID. +/// +/// \returns realm::npos if the object does not exist in the table. +ObjKey row_for_object_id(const TableInfoCache&, const Table&, GlobalKey); +Obj obj_for_object_id(const TableInfoCache&, Table&, GlobalKey); +ConstObj obj_for_object_id(const TableInfoCache&, const Table&, GlobalKey); + +ObjKey row_for_primary_key(const Table&, PrimaryKey); +ConstObj obj_for_primary_key(const Table&, PrimaryKey); +Obj obj_for_primary_key(Table&, PrimaryKey); + +//@{ +/// Add a row to the table and populate the object ID with an appropriate value. +/// +/// In the variant which takes an GlobalKey parameter, a check is performed to see +/// if the object already exists. If it does, the row index of the existing object +/// is returned. +/// +/// If the table has a primary key column, an exception is thrown. +/// +/// \returns the row index of the object. +inline Obj create_object(const TableInfoCache&, Table& t) +{ + return t.create_object(); +} + +inline Obj create_object(const TableInfoCache&, Table& t, GlobalKey object_id) +{ + return t.create_object(object_id); +} +//@} + +//@{ +/// Create an object with a primary key value and populate the object ID with an +/// appropriate value. +/// +/// If the table does not have a primary key column (as indicated by the Object +/// Store's metadata in the special "pk" table), or the type of the primary key +/// column does not match the argument provided, an exception is thrown. +/// +/// The primary key column's value is populated with the appropriate +/// `set_int_unique()`, `set_string_unique()`, or `set_null_unique()` method +/// called on \a table. +/// +/// If an object with the given primary key value already exists, its row number +/// is returned without creating any new objects. +/// +/// These are convenience functions, equivalent to the following: +/// - Add an empty row to the table. +/// - Obtain an `GlobalKey` with `object_id_for_primary_key()`. +/// - Obtain a local object ID with `global_to_local_object_id()`. +/// - Store the local object ID in the object ID column. +/// - Call `set_int_unique()`,`set_string_unique()`, or `set_null_unique()` +/// to set the primary key value. +/// +/// \returns the row index of the created object. +Obj create_object_with_primary_key(const TableInfoCache&, Table&, util::Optional primary_key); +Obj create_object_with_primary_key(const TableInfoCache&, Table&, StringData primary_key); +Obj create_object_with_primary_key(const TableInfoCache&, Table&, int64_t primary_key); +//@} + +struct TableInfoCache { + const Transaction& m_transaction; + + // Implicit conversion deliberately allowed for the purpose of calling the above + // functions without constructing a cache manually. + TableInfoCache(const Transaction&); + TableInfoCache(WriteTransaction&); + TableInfoCache(ReadTransaction&); + TableInfoCache(TableInfoCache&&) noexcept = default; + + struct TableInfo { + struct VTable; + + TableKey key; + StringData name; + ColKey primary_key_col; + + ConstTableRef get_table(const Transaction&) const; + TableRef get_table(Transaction&) const; + bool primary_key_nullable; + DataType primary_key_type; + mutable ObjKey last_obj_key; + mutable GlobalKey last_object_id; + + void clear_last_object() const + { + last_obj_key = realm::null_key; + last_object_id = {}; + } + }; + + mutable std::map m_table_info; + + const TableInfo& get_table_info(const Table&) const; + const TableInfo& get_table_info(TableKey) const; + void clear(); + void clear_last_object(const Table&); + void verify(); +}; + + +/// Migrate a server-side Realm file whose history type is +/// `Replication::hist_SyncServer` and whose history schema version is 0 (i.e., +/// Realm files without stable identifiers). +void import_from_legacy_format(const Group& old_group, Group& new_group, util::Logger&); + +using TableNameBuffer = std::array; +StringData table_name_to_class_name(StringData); +StringData class_name_to_table_name(StringData, TableNameBuffer&); + + +// Implementation: + +inline StringData table_name_to_class_name(StringData table_name) +{ + REALM_ASSERT(table_name.begins_with("class_")); + return table_name.substr(6); +} + + +inline StringData class_name_to_table_name(StringData class_name, TableNameBuffer& buffer) +{ + constexpr const char class_prefix[] = "class_"; + constexpr size_t class_prefix_len = sizeof(class_prefix) - 1; + char* p = std::copy_n(class_prefix, class_prefix_len, buffer.data()); + size_t len = std::min(class_name.size(), buffer.size() - class_prefix_len); + std::copy_n(class_name.data(), len, p); + return StringData(buffer.data(), class_prefix_len + len); +} + +inline TableInfoCache::TableInfoCache(WriteTransaction& wt) + : TableInfoCache(wt.operator Transaction&()) +{ +} + +inline TableInfoCache::TableInfoCache(ReadTransaction& rt) + : TableInfoCache(rt.operator Transaction&()) +{ +} + +} // namespace sync +} // namespace realm + +#endif // REALM_SYNC_OBJECT_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/object_id.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/object_id.hpp new file mode 100644 index 0000000..689ed17 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/object_id.hpp @@ -0,0 +1,131 @@ +/************************************************************************* + * + * Copyright 2017 Realm Inc. + * + * 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 REALM_SYNC_OBJECT_ID_HPP +#define REALM_SYNC_OBJECT_ID_HPP + +#include // std::hash +#include +#include // operator<< +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace realm { + +class Group; + +namespace sync { + +// Any unambiguous object identifier. Monostate represents NULL (can't use realm::None or std::nullptr_t because they +// do not implement operator<). +using PrimaryKey = mpark::variant; + +/// FIXME: Since PrimaryKey is a typedef to an `std` type, ADL for operator<< +/// doesn't work properly. This struct exists solely for passing PrimaryKey +/// instances to various output streams. +struct format_pk { + const PrimaryKey& pk; + explicit format_pk(const PrimaryKey& pk) + : pk(pk) + { + } +}; +std::ostream& operator<<(std::ostream& os, format_pk); + + +// ObjectIDSet is a set of (table name, object id) +class ObjectIDSet { +public: + void insert(StringData table, const PrimaryKey& object_id); + void erase(StringData table, const PrimaryKey& object_id); + bool contains(StringData table, const PrimaryKey& object_id) const noexcept; + bool empty() const noexcept; + + // A map from table name to a set of object ids. + util::metered::map> m_objects; +}; + +// FieldSet is a set of fields in tables. A field is defined by a +// table name, a column in the table and an object id for the row. +class FieldSet { +public: + void insert(StringData table, StringData column, const PrimaryKey& object_id); + void erase(StringData table, StringData column, const PrimaryKey& object_id); + bool contains(StringData table, const PrimaryKey& object_id) const noexcept; + bool contains(StringData table, StringData column, const PrimaryKey& object_id) const noexcept; + bool empty() const noexcept; + + // A map from table name to a map from column name to a set of + // object ids. + util::metered::map>> m_fields; +}; + +struct GlobalID { + StringData table_name; + PrimaryKey object_id; + + bool operator==(const GlobalID& other) const; + bool operator!=(const GlobalID& other) const; + bool operator<(const GlobalID& other) const; +}; + +/// Implementation: + + +inline bool GlobalID::operator==(const GlobalID& other) const +{ + return object_id == other.object_id && table_name == other.table_name; +} + +inline bool GlobalID::operator!=(const GlobalID& other) const +{ + return !(*this == other); +} + +inline bool GlobalID::operator<(const GlobalID& other) const +{ + if (table_name == other.table_name) + return object_id < other.object_id; + return table_name < other.table_name; +} + +inline bool ObjectIDSet::empty() const noexcept +{ + return m_objects.empty(); +} + +inline bool FieldSet::empty() const noexcept +{ + return m_fields.empty(); +} + +} // namespace sync +} // namespace realm + +#endif // REALM_SYNC_OBJECT_ID_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/permissions.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/permissions.hpp new file mode 100644 index 0000000..645a360 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/permissions.hpp @@ -0,0 +1,121 @@ + +#ifndef REALM_SYNC_PERMISSIONS_HPP +#define REALM_SYNC_PERMISSIONS_HPP + +#include + +namespace realm { +namespace sync { + +/// The Privilege enum is intended to be used in a bitfield. +enum class Privilege : uint_least32_t { + None = 0, + + /// The user can read the object (i.e. it can participate in the user's + /// subscription. + /// + /// NOTE: On objects, it is a prerequisite that the object's class is also + /// readable by the user. + /// + /// FIXME: Until we get asynchronous links, any object that is reachable + /// through links from another readable/queryable object is also readable, + /// regardless of whether the user specifically does not have read access. + Read = 1, + + /// The user can modify the fields of the object. + /// + /// NOTE: On objects, it is a prerequisite that the object's class is also + /// updatable by the user. When applied to a Class object, it does not + /// imply that the user can modify the schema of the class, only the + /// objects of that class. + /// + /// NOTE: This does not imply the SetPermissions privilege. + Update = 2, + + /// The user can delete the object. + /// + /// NOTE: When applied to a Class object, it has no effect on whether + /// objects of that class can be deleted by the user. + /// + /// NOTE: This implies the ability to implicitly nullify links pointing + /// to the object from other objects, even if the user does not have + /// permission to modify those objects in the normal way. + Delete = 4, + + //@{ + /// The user can modify the object's permissions. + /// + /// NOTE: The user will only be allowed to assign permissions at or below + /// their own privilege level. + SetPermissions = 8, + Share = SetPermissions, + //@} + + /// When applied to a Class object, the user can query objects in that + /// class. + /// + /// Has no effect when applied to objects other than Class. + Query = 16, + + /// When applied to a Class object, the user may create objects in that + /// class. + /// + /// NOTE: The user implicitly has Update and SetPermissions + /// (but not necessarily Delete permission) within the same + /// transaction as the object was created. + /// + /// NOTE: Even when a user has CreateObject rights, a CreateObject + /// operation may still be rejected by the server, if the object has a + /// primary key and the object already exists, but is not accessible by the + /// user. + Create = 32, + + /// When applied as a "Realm" privilege, the user can add classes and add + /// columns to classes. + /// + /// NOTE: When applied to a class or object, this has no effect. + ModifySchema = 64, + + /// + /// Aggregate permissions for compatibility: + /// + Download = Read | Query, + Upload = Update | Delete | Create, + DeleteRealm = Upload, // FIXME: This seems overly permissive +}; + +inline constexpr uint_least32_t operator|(Privilege a, Privilege b) +{ + return static_cast(a) | static_cast(b); +} + +inline constexpr uint_least32_t operator|(uint_least32_t a, Privilege b) +{ + return a | static_cast(b); +} + +inline constexpr uint_least32_t operator&(Privilege a, Privilege b) +{ + return static_cast(a) & static_cast(b); +} + +inline constexpr uint_least32_t operator&(uint_least32_t a, Privilege b) +{ + return a & static_cast(b); +} + +inline uint_least32_t& operator|=(uint_least32_t& a, Privilege b) +{ + return a |= static_cast(b); +} + +inline constexpr uint_least32_t operator~(Privilege p) +{ + return ~static_cast(p); +} + +} // namespace sync +} // namespace realm + + +#endif // REALM_SYNC_PERMISSIONS_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/protocol.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/protocol.hpp new file mode 100644 index 0000000..407572d --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/protocol.hpp @@ -0,0 +1,294 @@ +#ifndef REALM_SYNC_PROTOCOL_HPP +#define REALM_SYNC_PROTOCOL_HPP + +#include +#include + +#include + + +// NOTE: The protocol specification is in `/doc/protocol.md` + + +namespace realm { +namespace sync { + +// Protocol versions: +// +// 1 Initial version, matching io.realm.sync-30, but not including query-based +// sync, serialized transactions, and state realms (async open). +// +constexpr int get_current_protocol_version() noexcept +{ + return 1; +} + +constexpr const char* get_websocket_protocol_prefix() noexcept +{ + return "com.mongodb.realm-sync/"; +} + + +/// Supported protocol envelopes: +/// +/// Alternative (*) +/// Name Envelope URL scheme Default port default port +/// ------------------------------------------------------------------------ +/// realm WebSocket realm: 7800 80 +/// realms WebSocket + SSL realms: 7801 443 +/// ws WebSocket ws: 80 +/// wss WebSocket + SSL wss: 443 +/// +/// *) When Client::Config::enable_default_port_hack is true +/// +enum class ProtocolEnvelope { realm, realms, ws, wss }; + +inline bool is_ssl(ProtocolEnvelope protocol) noexcept +{ + switch (protocol) { + case ProtocolEnvelope::realm: + case ProtocolEnvelope::ws: + break; + case ProtocolEnvelope::realms: + case ProtocolEnvelope::wss: + return true; + } + return false; +} + + +// These integer types are selected so that they accomodate the requirements of +// the protocol specification (`/doc/protocol.md`). +// +// clang-format off +using file_ident_type = std::uint_fast64_t; +using version_type = Replication::version_type; +using salt_type = std::int_fast64_t; +using timestamp_type = std::uint_fast64_t; +using session_ident_type = std::uint_fast64_t; +using request_ident_type = std::uint_fast64_t; +using milliseconds_type = std::int_fast64_t; +// clang-format on + +constexpr file_ident_type get_max_file_ident() +{ + return 0x0'7FFF'FFFF'FFFF'FFFF; +} + + +struct SaltedFileIdent { + file_ident_type ident; + /// History divergence and identity spoofing protection. + salt_type salt; +}; + +struct SaltedVersion { + version_type version; + /// History divergence protection. + salt_type salt; +}; + + +/// \brief A client's reference to a position in the server-side history. +/// +/// A download cursor refers to a position in the server-side history. If +/// `server_version` is zero, the position is at the beginning of the history, +/// otherwise the position is after the entry whose changeset produced that +/// version. In general, positions are to be understood as places between two +/// adjacent history entries. +/// +/// `last_integrated_client_version` is the version produced on the client by +/// the last changeset that was sent to the server and integrated into the +/// server-side Realm state at the time indicated by the history position +/// specified by `server_version`, or zero if no changesets from the client were +/// integrated by the server at that point in time. +struct DownloadCursor { + version_type server_version; + version_type last_integrated_client_version; +}; + +/// Checks that `dc.last_integrated_client_version` is zero if +/// `dc.server_version` is zero. +bool is_consistent(DownloadCursor dc) noexcept; + +/// Checks that `a.last_integrated_client_version` and +/// `b.last_integrated_client_version` are equal, if `a.server_version` and +/// `b.server_version` are equal. Otherwise checks that +/// `a.last_integrated_client_version` is less than, or equal to +/// `b.last_integrated_client_version`, if `a.server_version` is less than +/// `b.server_version`. Otherwise checks that `a.last_integrated_client_version` +/// is greater than, or equal to `b.last_integrated_client_version`. +bool are_mutually_consistent(DownloadCursor a, DownloadCursor b) noexcept; + + +/// \brief The server's reference to a position in the client-side history. +/// +/// An upload cursor refers to a position in the client-side history. If +/// `client_version` is zero, the position is at the beginning of the history, +/// otherwise the position is after the entry whose changeset produced that +/// version. In general, positions are to be understood as places between two +/// adjacent history entries. +/// +/// `last_integrated_server_version` is the version produced on the server by +/// the last changeset that was sent to the client and integrated into the +/// client-side Realm state at the time indicated by the history position +/// specified by `client_version`, or zero if no changesets from the server were +/// integrated by the client at that point in time. +struct UploadCursor { + version_type client_version; + version_type last_integrated_server_version; +}; + +/// Checks that `uc.last_integrated_server_version` is zero if +/// `uc.client_version` is zero. +bool is_consistent(UploadCursor uc) noexcept; + +/// Checks that `a.last_integrated_server_version` and +/// `b.last_integrated_server_version` are equal, if `a.client_version` and +/// `b.client_version` are equal. Otherwise checks that +/// `a.last_integrated_server_version` is less than, or equal to +/// `b.last_integrated_server_version`, if `a.client_version` is less than +/// `b.client_version`. Otherwise checks that `a.last_integrated_server_version` +/// is greater than, or equal to `b.last_integrated_server_version`. +bool are_mutually_consistent(UploadCursor a, UploadCursor b) noexcept; + + +/// A client's record of the current point of progress of the synchronization +/// process. The client must store this persistently in the local Realm file. +struct SyncProgress { + /// The last server version that the client has heard about. + SaltedVersion latest_server_version = {0, 0}; + + /// The last server version integrated, or about to be integrated by the + /// client. + DownloadCursor download = {0, 0}; + + /// The last client version integrated by the server. + UploadCursor upload = {0, 0}; +}; + + +/// \brief Protocol errors discovered by the server, and reported to the client +/// by way of ERROR messages. +/// +/// These errors will be reported to the client-side application via the error +/// handlers of the affected sessions. +/// +/// ATTENTION: Please remember to update is_session_level_error() when +/// adding/removing error codes. +enum class ProtocolError { + // clang-format off + + // Connection level and protocol errors + connection_closed = 100, // Connection closed (no error) + other_error = 101, // Other connection level error + unknown_message = 102, // Unknown type of input message + bad_syntax = 103, // Bad syntax in input message head + limits_exceeded = 104, // Limits exceeded in input message + wrong_protocol_version = 105, // Wrong protocol version (CLIENT) (obsolete) + bad_session_ident = 106, // Bad session identifier in input message + reuse_of_session_ident = 107, // Overlapping reuse of session identifier (BIND) + bound_in_other_session = 108, // Client file bound in other session (IDENT) + bad_message_order = 109, // Bad input message order + bad_decompression = 110, // Error in decompression (UPLOAD) + bad_changeset_header_syntax = 111, // Bad syntax in a changeset header (UPLOAD) + bad_changeset_size = 112, // Bad size specified in changeset header (UPLOAD) + bad_changesets = 113, // Bad changesets (UPLOAD) + + // Session level errors + session_closed = 200, // Session closed (no error) + other_session_error = 201, // Other session level error + token_expired = 202, // Access token expired + bad_authentication = 203, // Bad user authentication (BIND, REFRESH) + illegal_realm_path = 204, // Illegal Realm path (BIND) + no_such_realm = 205, // No such Realm (BIND) + permission_denied = 206, // Permission denied (STATE_REQUEST, BIND, REFRESH) + bad_server_file_ident = 207, // Bad server file identifier (IDENT) (obsolete!) + bad_client_file_ident = 208, // Bad client file identifier (IDENT) + bad_server_version = 209, // Bad server version (IDENT, UPLOAD, TRANSACT) + bad_client_version = 210, // Bad client version (IDENT, UPLOAD) + diverging_histories = 211, // Diverging histories (IDENT) + bad_changeset = 212, // Bad changeset (UPLOAD) + superseded = 213, // Superseded by new session for same client-side file (deprecated) + disabled_session = 213, // Alias for `superseded` (deprecated) + partial_sync_disabled = 214, // Partial sync disabled (BIND, STATE_REQUEST) + unsupported_session_feature = 215, // Unsupported session-level feature + bad_origin_file_ident = 216, // Bad origin file identifier (UPLOAD) + bad_client_file = 217, // Synchronization no longer possible for client-side file + server_file_deleted = 218, // Server file was deleted while session was bound to it + client_file_blacklisted = 219, // Client file has been blacklisted (IDENT) + user_blacklisted = 220, // User has been blacklisted (BIND) + transact_before_upload = 221, // Serialized transaction before upload completion + client_file_expired = 222, // Client file has expired + user_mismatch = 223, // User mismatch for client file identifier (IDENT) + too_many_sessions = 224, // Too many sessions in connection (BIND) + invalid_schema_change = 225, // Invalid schema change (UPLOAD) + + // clang-format on +}; + +constexpr bool is_session_level_error(ProtocolError); + +/// Returns null if the specified protocol error code is not defined by +/// ProtocolError. +const char* get_protocol_error_message(int error_code) noexcept; + +const std::error_category& protocol_error_category() noexcept; + +std::error_code make_error_code(ProtocolError) noexcept; + +} // namespace sync +} // namespace realm + +namespace std { + +template <> +struct is_error_code_enum { + static const bool value = true; +}; + +} // namespace std + +namespace realm { +namespace sync { + + +// Implementation + +inline bool is_consistent(DownloadCursor dc) noexcept +{ + return (dc.server_version != 0 || dc.last_integrated_client_version == 0); +} + +inline bool are_mutually_consistent(DownloadCursor a, DownloadCursor b) noexcept +{ + if (a.server_version < b.server_version) + return (a.last_integrated_client_version <= b.last_integrated_client_version); + if (a.server_version > b.server_version) + return (a.last_integrated_client_version >= b.last_integrated_client_version); + return (a.last_integrated_client_version == b.last_integrated_client_version); +} + +inline bool is_consistent(UploadCursor uc) noexcept +{ + return (uc.client_version != 0 || uc.last_integrated_server_version == 0); +} + +inline bool are_mutually_consistent(UploadCursor a, UploadCursor b) noexcept +{ + if (a.client_version < b.client_version) + return (a.last_integrated_server_version <= b.last_integrated_server_version); + if (a.client_version > b.client_version) + return (a.last_integrated_server_version >= b.last_integrated_server_version); + return (a.last_integrated_server_version == b.last_integrated_server_version); +} + +constexpr bool is_session_level_error(ProtocolError error) +{ + return int(error) >= 200 && int(error) <= 299; +} + +} // namespace sync +} // namespace realm + +#endif // REALM_SYNC_PROTOCOL_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/transform.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/transform.hpp new file mode 100644 index 0000000..1eeb1bd --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/transform.hpp @@ -0,0 +1,324 @@ + +#ifndef REALM_SYNC_TRANSFORM_HPP +#define REALM_SYNC_TRANSFORM_HPP + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace realm { +namespace sync { + +struct Changeset; + +/// Represents an entry in the history of changes in a sync-enabled Realm +/// file. Server and client use different history formats, but this class is +/// used both on the server and the client side. Each history entry corresponds +/// to a version of the Realm state. For server and client-side histories, these +/// versions are referred to as *server versions* and *client versions* +/// respectively. These versions may, or may not correspond to Realm snapshot +/// numbers (on the server-side they currently do not). +/// +/// FIXME: Move this class into a separate header +/// (``). +class HistoryEntry { +public: + /// The time of origination of the changes referenced by this history entry, + /// meassured as the number of milliseconds since 2015-01-01T00:00:00Z, not + /// including leap seconds. For changes of local origin, this is the local + /// time at the point when the local transaction was committed. For changes + /// of remote origin, it is the remote time of origin at the peer (client or + /// server) identified by `origin_file_ident`. + timestamp_type origin_timestamp; + + /// The identifier of the file in the context of which the initial + /// untransformed changeset originated, or zero if the changeset originated + /// on the local peer (client or server). + /// + /// For example, when a changeset "travels" from a file with identifier 2 on + /// client A, through a file with identifier 1 on the server, to a file with + /// identifier 3 on client B, then `origin_file_ident` will be 0 on client + /// A, 2 on the server, and 2 on client B. On the other hand, if the server + /// was the originator of the changeset, then `origin_file_ident` would be + /// zero on the server, and 1 on both clients. + file_ident_type origin_file_ident; + + /// For changes of local origin on the client side, this is the last server + /// version integrated locally prior to this history entry. In other words, + /// it is a copy of `remote_version` of the last preceding history entry + /// that carries changes of remote origin, or zero if there is no such + /// preceding history entry. + /// + /// For changes of local origin on the server-side, this is always zero. + /// + /// For changes of remote origin, this is the version produced within the + /// remote-side Realm file by the change that gave rise to this history + /// entry. The remote-side Realm file is not always the same Realm file from + /// which the change originated. On the client side, the remote side is + /// always the server side, and `remote_version` is always a server version + /// (since clients do not speak directly to each other). On the server side, + /// the remote side is always a client side, and `remote_version` is always + /// a client version. + version_type remote_version; + + /// Referenced memory is not owned by this class. + ChunkedBinaryData changeset; +}; + + +/// The interface between the sync history and the operational transformer +/// (Transformer) for the purpose of transforming changesets received from a +/// particular *remote peer*. +class TransformHistory { +public: + /// Get the first history entry where the produced version is greater than + /// `begin_version` and less than or equal to `end_version`, and whose + /// changeset is neither empty, nor produced by integration of a changeset + /// received from the remote peer associated with this history. + /// + /// If \a buffer is non-null, memory will be allocated and transferred to + /// \a buffer. The changeset will be copied into the newly allocated memory. + /// + /// If \a buffer is null, the changeset is not copied out of the Realm, + /// and entry.changeset.data() does not point to the changeset. + /// The changeset in the Realm could be chunked, hence it is not possible + /// to point to it with BinaryData. entry.changeset.size() always gives the + /// size of the changeset. + /// + /// \param begin_version, end_version The range of versions to consider. If + /// `begin_version` is equal to `end_version`, it is the empty range. If + /// `begin_version` is zero, it means that everything preceeding + /// `end_version` is to be considered, which is again the empty range if + /// `end_version` is also zero. Zero is a special value in that no changeset + /// produces that version. It is an error if `end_version` precedes + /// `begin_version`, or if `end_version` is zero and `begin_version` is not. + /// + /// \return The version produced by the changeset of the located history + /// entry, or zero if no history entry exists matching the specified and + /// implied criteria. + virtual version_type find_history_entry(version_type begin_version, version_type end_version, + HistoryEntry& entry) const noexcept = 0; + + /// Get the specified reciprocal changeset. The targeted history entry is + /// the one whose untransformed changeset produced the specified version. + virtual ChunkedBinaryData get_reciprocal_transform(version_type version) const = 0; + + /// Replace the specified reciprocally transformed changeset. The targeted + /// history entry is the one whose untransformed changeset produced the + /// specified version. + /// + /// \param encoded_changeset The new reciprocally transformed changeset. + virtual void set_reciprocal_transform(version_type version, BinaryData encoded_changeset) = 0; + + virtual ~TransformHistory() noexcept {} +}; + + +class TransformError; // Exception + +class Transformer { +public: + class RemoteChangeset; + class Reporter; + + /// Produce operationally transformed versions of the specified changesets, + /// which are assumed to be received from a particular remote peer, P, + /// represented by the specified transform history. Note that P is not + /// necessarily the peer on which the changes originated. + /// + /// Operational transformation is carried out between the specified + /// changesets and all causally unrelated changesets in the local history. A + /// changeset in the local history is causally unrelated if, and only if it + /// occurs after the local changeset that produced + /// `remote_changeset.last_integrated_local_version` and is not a produced + /// by integration of a changeset received from P. This assumes that + /// `remote_changeset.last_integrated_local_version` is set to the local + /// version produced by the last local changeset, that was integrated by P + /// before P produced the specified changeset. + /// + /// The operational transformation is reciprocal (two-way), so it also + /// transforms the causally unrelated local changesets. This process does + /// not modify the history itself (the changesets available through + /// TransformHistory::get_history_entry()), instead the reciprocally + /// transformed changesets are stored separately, and individually for each + /// remote peer, such that they can participate in transformation of the + /// next incoming changeset from P. + /// + /// In general, if A and B are two causally unrelated (alternative) + /// changesets based on the same version V, then the operational + /// transformation between A and B produces changesets A' and B' such that + /// both of the concatenated changesets A + B' and B + A' produce the same + /// final state when applied to V. Operational transformation is meaningful + /// only when carried out between alternative changesets based on the same + /// version. + /// + /// \param local_file_ident The identifier of the local Realm file. The + /// transformer uses this as the actual origin file identifier for + /// changesets where HistoryEntry::origin_file_ident is zero, i.e., when the + /// changeset is of local origin. The specified identifier must never be + /// zero. + /// + /// \return The size of the transformed version of the specified + /// changesets. Upon return, the transformed changesets are concatenated + /// and placed in \a output_buffer. + /// + /// \throw TransformError Thrown if operational transformation fails due to + /// a problem with the specified changeset. + /// + /// FIXME: Consider using std::error_code instead of throwing + /// TransformError. + virtual void transform_remote_changesets(TransformHistory&, file_ident_type local_file_ident, + version_type current_local_version, Changeset* changesets, + std::size_t num_changesets, Reporter* = nullptr, + util::Logger* = nullptr) = 0; + + virtual ~Transformer() noexcept {} +}; + +std::unique_ptr make_transformer(); + +} // namespace sync + + +namespace _impl { + +class TransformerImpl : public sync::Transformer { +public: + using Changeset = sync::Changeset; + using file_ident_type = sync::file_ident_type; + using HistoryEntry = sync::HistoryEntry; + using Instruction = sync::Instruction; + using TransformHistory = sync::TransformHistory; + using version_type = sync::version_type; + + TransformerImpl(); + + void transform_remote_changesets(TransformHistory&, file_ident_type, version_type, Changeset*, std::size_t, + Reporter*, util::Logger*) override; + + struct Side; + struct MajorSide; + struct MinorSide; + +protected: + virtual void merge_changesets(file_ident_type local_file_ident, Changeset* their_changesets, + std::size_t their_size, + // our_changesets is a pointer-pointer because these changesets + // are held by the reciprocal transform cache. + Changeset** our_changesets, std::size_t our_size, Reporter* reporter, + util::Logger* logger); + +private: + util::metered::map> m_reciprocal_transform_cache; + + TransactLogParser m_changeset_parser; + + Changeset& get_reciprocal_transform(TransformHistory&, file_ident_type local_file_ident, version_type version, + const HistoryEntry&); + void flush_reciprocal_transform_cache(TransformHistory&); + + static size_t emit_changesets(const Changeset*, size_t num_changesets, util::Buffer& output_buffer); + + struct Discriminant; + struct Transformer; + struct MergeTracer; + + template + void merge_instructions(LeftSide&, RightSide&); +}; + +} // namespace _impl + + +namespace sync { + +class Transformer::RemoteChangeset { +public: + /// The version produced on the remote peer by this changeset. + /// + /// On the server, the remote peer is the client from which the changeset + /// originated, and `remote_version` is the client version produced by the + /// changeset on that client. + /// + /// On a client, the remote peer is the server, and `remote_version` is the + /// server version produced by this changeset on the server. Since the + /// server is never the originator of changes, this changeset must in turn + /// have been produced on the server by integration of a changeset uploaded + /// by some other client. + version_type remote_version = 0; + + /// The last local version that has been integrated into `remote_version`. + /// + /// A local version, L, has been integrated into a remote version, R, when, + /// and only when L is the latest local version such that all preceeding + /// changesets in the local history have been integrated by the remote peer + /// prior to R. + /// + /// On the server, this is the last server version integrated into the + /// client version `remote_version`. On a client, it is the last client + /// version integrated into the server version `remote_version`. + version_type last_integrated_local_version = 0; + + /// The changeset itself. + ChunkedBinaryData data; + + /// Same meaning as `HistoryEntry::origin_timestamp`. + timestamp_type origin_timestamp = 0; + + /// Same meaning as `HistoryEntry::origin_file_ident`. + file_ident_type origin_file_ident = 0; + + /// If the changeset was compacted during download, the size of the original + /// changeset. + std::size_t original_changeset_size = 0; + + RemoteChangeset() {} + RemoteChangeset(version_type rv, version_type lv, ChunkedBinaryData d, timestamp_type ot, file_ident_type fi); +}; + + +class Transformer::Reporter { +public: + virtual void on_changesets_merged(long num_merges) = 0; +}; + + +void parse_remote_changeset(const Transformer::RemoteChangeset&, Changeset&); + + +// Implementation + +class TransformError : public std::runtime_error { +public: + TransformError(const std::string& message) + : std::runtime_error(message) + { + } +}; + +class SchemaMismatchError : public TransformError { +public: + using TransformError::TransformError; +}; + +inline Transformer::RemoteChangeset::RemoteChangeset(version_type rv, version_type lv, ChunkedBinaryData d, + timestamp_type ot, file_ident_type fi) + : remote_version(rv) + , last_integrated_local_version(lv) + , data(d) + , origin_timestamp(ot) + , origin_file_ident(fi) +{ +} + +} // namespace sync +} // namespace realm + +#endif // REALM_SYNC_TRANSFORM_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/version.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/version.hpp new file mode 100644 index 0000000..1ea325b --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/sync/version.hpp @@ -0,0 +1,17 @@ +#ifndef REALM_SYNC_VERSION_HPP +#define REALM_SYNC_VERSION_HPP + +#include + +// clang-format off +#define REALM_SYNC_VER_MAJOR 10 +#define REALM_SYNC_VER_MINOR 0 +#define REALM_SYNC_VER_PATCH 0 +#define REALM_SYNC_PRODUCT_NAME "realm-sync" +// clang-format on + +#define REALM_SYNC_VER_STRING \ + REALM_QUOTE(REALM_SYNC_VER_MAJOR) "." REALM_QUOTE(REALM_SYNC_VER_MINOR) "." REALM_QUOTE(REALM_SYNC_VER_PATCH) +#define REALM_SYNC_VER_CHUNK "[" REALM_SYNC_PRODUCT_NAME "-" REALM_SYNC_VER_STRING "]" + +#endif // REALM_SYNC_VERSION_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/table.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/table.hpp new file mode 100644 index 0000000..9da1ec6 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/table.hpp @@ -0,0 +1,1341 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_TABLE_HPP +#define REALM_TABLE_HPP + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Only set this to one when testing the code paths that exercise object ID +// hash collisions. It artificially limits the "optimistic" local ID to use +// only the lower 15 bits of the ID rather than the lower 63 bits, making it +// feasible to generate collisions within reasonable time. +#define REALM_EXERCISE_OBJECT_ID_COLLISION 0 + +namespace realm { + +class BacklinkColumn; +template +class BacklinkCount; +class BinaryColumy; +class ConstTableView; +class Group; +class SortDescriptor; +class StringIndex; +class TableView; +template +class Columns; +template +class SubQuery; +class ColKeys; +struct GlobalKey; +class LinkChain; + +struct Link { +}; +typedef Link BackLink; + + +namespace _impl { +class TableFriend; +} +namespace metrics { +class QueryInfo; +} + +class Table { +public: + /// Construct a new freestanding top-level table with static + /// lifetime. For debugging only. + Table(Allocator& = Allocator::get_default()); + + /// Construct a copy of the specified table as a new freestanding + /// top-level table with static lifetime. For debugging only. + Table(const Table&, Allocator& = Allocator::get_default()); + + ~Table() noexcept; + + Allocator& get_alloc() const; + + /// Get the name of this table, if it has one. Only group-level tables have + /// names. For a table of any other kind, this function returns the empty + /// string. + StringData get_name() const noexcept; + + // Whether or not elements can be null. + bool is_nullable(ColKey col_key) const; + + // Whether or not the column is a list. + bool is_list(ColKey col_key) const; + + //@{ + /// Conventience functions for inspecting the dynamic table type. + /// + bool is_embedded() const noexcept; // true if table holds embedded objects + size_t get_column_count() const noexcept; + DataType get_column_type(ColKey column_key) const; + StringData get_column_name(ColKey column_key) const; + ColumnAttrMask get_column_attr(ColKey column_key) const noexcept; + ColKey get_column_key(StringData name) const noexcept; + ColKeys get_column_keys() const; + typedef util::Optional> BacklinkOrigin; + BacklinkOrigin find_backlink_origin(StringData origin_table_name, StringData origin_col_name) const noexcept; + BacklinkOrigin find_backlink_origin(ColKey backlink_col) const noexcept; + //@} + + // Primary key columns + ColKey get_primary_key_column() const; + void set_primary_key_column(ColKey col); + void validate_primary_column(); + + //@{ + /// Convenience functions for manipulating the dynamic table type. + /// + static const size_t max_column_name_length = 63; + static const uint64_t max_num_columns = 0xFFFFUL; // <-- must be power of two -1 + ColKey add_column(DataType type, StringData name, bool nullable = false); + ColKey add_column_list(DataType type, StringData name, bool nullable = false); + + ColKey add_column_link(DataType type, StringData name, Table& target); + + void remove_column(ColKey col_key); + void rename_column(ColKey col_key, StringData new_name); + bool valid_column(ColKey col_key) const noexcept; + void check_column(ColKey col_key) const; + // Change the embedded property of a table. If switching to being embedded, the table must + // not have a primary key and all objects must have exactly 1 backlink. Return value + // indicates if the conversion was done + bool set_embedded(bool embedded); + //@} + + /// True for `col_type_Link` and `col_type_LinkList`. + static bool is_link_type(ColumnType) noexcept; + + //@{ + + /// has_search_index() returns true if, and only if a search index has been + /// added to the specified column. Rather than throwing, it returns false if + /// the table accessor is detached or the specified index is out of range. + /// + /// add_search_index() adds a search index to the specified column of the + /// table. It has no effect if a search index has already been added to the + /// specified column (idempotency). + /// + /// remove_search_index() removes the search index from the specified column + /// of the table. It has no effect if the specified column has no search + /// index. The search index cannot be removed from the primary key of a + /// table. + /// + /// \param col_key The key of a column of the table. + + bool has_search_index(ColKey col_key) const noexcept; + void add_search_index(ColKey col_key); + void remove_search_index(ColKey col_key); + + void enumerate_string_column(ColKey col_key); + bool is_enumerated(ColKey col_key) const noexcept; + bool contains_unique_values(ColKey col_key) const; + + //@} + + /// If the specified column is optimized to store only unique values, then + /// this function returns the number of unique values currently + /// stored. Otherwise it returns zero. This function is mainly intended for + /// debugging purposes. + size_t get_num_unique_values(ColKey col_key) const; + + template + Columns column(ColKey col_key) const; // FIXME: Should this one have been declared noexcept? + template + Columns column(const Table& origin, ColKey origin_col_key) const; + + // BacklinkCount is a total count per row and therefore not attached to a specific column + template + BacklinkCount get_backlink_count() const; + + template + SubQuery column(ColKey col_key, Query subquery) const; + template + SubQuery column(const Table& origin, ColKey origin_col_key, Query subquery) const; + + // Table size and deletion + bool is_empty() const noexcept; + size_t size() const noexcept + { + return m_clusters.size(); + } + size_t nb_unresolved() const noexcept + { + return m_tombstones ? m_tombstones->size() : 0; + } + + //@{ + + /// Object handling. + + // Create an object with key. If the key is omitted, a key will be generated by the system + Obj create_object(ObjKey key = {}, const FieldValues& = {}); + // Create an object with specific GlobalKey - or return already existing object + // Potential tombstone will be resurrected + Obj create_object(GlobalKey object_id, const FieldValues& = {}); + // Create an object with primary key. If an object with the given primary key already exists, it + // will be returned and did_create (if supplied) will be set to false. + // Potential tombstone will be resurrected + Obj create_object_with_primary_key(const Mixed& primary_key, FieldValues&&, bool* did_create = nullptr); + Obj create_object_with_primary_key(const Mixed& primary_key, bool* did_create = nullptr) + { + return create_object_with_primary_key(primary_key, {{}}, did_create); + } + // Return key for existing object or return null key. + ObjKey find_primary_key(Mixed value) const; + // Return ObjKey for object identified by id. If objects does not exist, return null key + ObjKey get_objkey(GlobalKey id) const; + // Return key for existing object or return unresolved key. + // Important: This is to be used ONLY by the Sync client. SDKs should NEVER + // observe an unresolved key. Ever. + ObjKey get_objkey_from_primary_key(const Mixed& primary_key); + // Return key for existing object or return unresolved key. + // Important: This is to be used ONLY by the Sync client. SDKs should NEVER + // observe an unresolved key. Ever. + // Important (2): This function must not be called for tables with primary keys. + ObjKey get_objkey_from_global_key(GlobalKey key); + /// Create a number of objects and add corresponding keys to a vector + void create_objects(size_t number, std::vector& keys); + /// Create a number of objects with keys supplied + void create_objects(const std::vector& keys); + /// Does the key refer to an object within the table? + bool is_valid(ObjKey key) const + { + return m_clusters.is_valid(key); + } + GlobalKey get_object_id(ObjKey key) const; + Obj get_object(ObjKey key) + { + REALM_ASSERT(!key.is_unresolved()); + return m_clusters.get(key); + } + ConstObj get_object(ObjKey key) const + { + REALM_ASSERT(!key.is_unresolved()); + return m_clusters.get(key); + } + Obj get_object(size_t ndx) + { + return m_clusters.get(ndx); + } + ConstObj get_object(size_t ndx) const + { + return m_clusters.get(ndx); + } + // Get object based on primary key + Obj get_object_with_primary_key(Mixed pk); + // Get primary key based on ObjKey + Mixed get_primary_key(ObjKey key); + // Get logical index for object. This function is not very efficient + size_t get_object_ndx(ObjKey key) const + { + return m_clusters.get_ndx(key); + } + + void dump_objects(); + + bool traverse_clusters(ClusterTree::TraverseFunction func) const + { + return m_clusters.traverse(func); + } + + /// remove_object() removes the specified object from the table. + /// Any links from the specified object into objects residing in an embedded + /// table will cause those objects to be deleted as well, and so on recursively. + void remove_object(ObjKey key); + /// remove_object_recursive() will delete linked rows if the removed link was the + /// last one holding on to the row in question. This will be done recursively. + void remove_object_recursive(ObjKey key); + // Invalidate object. To be used by the Sync client. + // - turns the object into a tombstone if links exist + // - otherwise works just as remove_object() + void invalidate_object(ObjKey key); + ConstObj get_tombstone(ObjKey key) const + { + REALM_ASSERT(key.is_unresolved()); + REALM_ASSERT(m_tombstones); + return m_tombstones->get(key); + } + + void clear(); + using Iterator = ClusterTree::Iterator; + using ConstIterator = ClusterTree::ConstIterator; + ConstIterator begin() const; + ConstIterator end() const; + Iterator begin(); + Iterator end(); + void remove_object(const ConstIterator& it) + { + remove_object(it->get_key()); + } + //@} + + + TableRef get_link_target(ColKey column_key) noexcept; + ConstTableRef get_link_target(ColKey column_key) const noexcept; + + static const size_t max_string_size = 0xFFFFF8 - Array::header_size - 1; + static const size_t max_binary_size = 0xFFFFF8 - Array::header_size; + + static constexpr int_fast64_t max_integer = std::numeric_limits::max(); + static constexpr int_fast64_t min_integer = std::numeric_limits::min(); + + /// Only group-level unordered tables can be used as origins or targets of + /// links. + bool is_group_level() const noexcept; + + /// A Table accessor obtained from a frozen transaction is also frozen. + bool is_frozen() const noexcept { return m_is_frozen; } + + /// If this table is a group-level table, then this function returns the + /// index of this table within the group. Otherwise it returns realm::npos. + size_t get_index_in_group() const noexcept; + TableKey get_key() const noexcept; + + uint64_t allocate_sequence_number(); + // Used by upgrade + void set_sequence_number(uint64_t seq); + void set_collision_map(ref_type ref); + + // Get the key of this table directly, without needing a Table accessor. + static TableKey get_key_direct(Allocator& alloc, ref_type top_ref); + + // Aggregate functions + size_t count_int(ColKey col_key, int64_t value) const; + size_t count_string(ColKey col_key, StringData value) const; + size_t count_float(ColKey col_key, float value) const; + size_t count_double(ColKey col_key, double value) const; + size_t count_decimal(ColKey col_key, Decimal128 value) const; + + int64_t sum_int(ColKey col_key) const; + double sum_float(ColKey col_key) const; + double sum_double(ColKey col_key) const; + Decimal128 sum_decimal(ColKey col_key) const; + int64_t maximum_int(ColKey col_key, ObjKey* return_ndx = nullptr) const; + float maximum_float(ColKey col_key, ObjKey* return_ndx = nullptr) const; + double maximum_double(ColKey col_key, ObjKey* return_ndx = nullptr) const; + Decimal128 maximum_decimal(ColKey col_key, ObjKey* return_ndx = nullptr) const; + Timestamp maximum_timestamp(ColKey col_key, ObjKey* return_ndx = nullptr) const; + int64_t minimum_int(ColKey col_key, ObjKey* return_ndx = nullptr) const; + float minimum_float(ColKey col_key, ObjKey* return_ndx = nullptr) const; + double minimum_double(ColKey col_key, ObjKey* return_ndx = nullptr) const; + Decimal128 minimum_decimal(ColKey col_key, ObjKey* return_ndx = nullptr) const; + Timestamp minimum_timestamp(ColKey col_key, ObjKey* return_ndx = nullptr) const; + double average_int(ColKey col_key, size_t* value_count = nullptr) const; + double average_float(ColKey col_key, size_t* value_count = nullptr) const; + double average_double(ColKey col_key, size_t* value_count = nullptr) const; + Decimal128 average_decimal(ColKey col_key, size_t* value_count = nullptr) const; + + // Will return pointer to search index accessor. Will return nullptr if no index + StringIndex* get_search_index(ColKey col) const noexcept + { + report_invalid_key(col); + if (!has_search_index(col)) + return nullptr; + return m_index_accessors[col.get_index().val]; + } + template + ObjKey find_first(ColKey col_key, T value) const; + + ObjKey find_first_int(ColKey col_key, int64_t value) const; + ObjKey find_first_bool(ColKey col_key, bool value) const; + ObjKey find_first_timestamp(ColKey col_key, Timestamp value) const; + ObjKey find_first_object_id(ColKey col_key, ObjectId value) const; + ObjKey find_first_float(ColKey col_key, float value) const; + ObjKey find_first_double(ColKey col_key, double value) const; + ObjKey find_first_decimal(ColKey col_key, Decimal128 value) const; + ObjKey find_first_string(ColKey col_key, StringData value) const; + ObjKey find_first_binary(ColKey col_key, BinaryData value) const; + ObjKey find_first_null(ColKey col_key) const; + + // TableView find_all_link(Key target_key); + // ConstTableView find_all_link(Key target_key) const; + TableView find_all_int(ColKey col_key, int64_t value); + ConstTableView find_all_int(ColKey col_key, int64_t value) const; + TableView find_all_bool(ColKey col_key, bool value); + ConstTableView find_all_bool(ColKey col_key, bool value) const; + TableView find_all_float(ColKey col_key, float value); + ConstTableView find_all_float(ColKey col_key, float value) const; + TableView find_all_double(ColKey col_key, double value); + ConstTableView find_all_double(ColKey col_key, double value) const; + TableView find_all_string(ColKey col_key, StringData value); + ConstTableView find_all_string(ColKey col_key, StringData value) const; + TableView find_all_binary(ColKey col_key, BinaryData value); + ConstTableView find_all_binary(ColKey col_key, BinaryData value) const; + TableView find_all_null(ColKey col_key); + ConstTableView find_all_null(ColKey col_key) const; + + TableView get_sorted_view(ColKey col_key, bool ascending = true); + ConstTableView get_sorted_view(ColKey col_key, bool ascending = true) const; + + TableView get_sorted_view(SortDescriptor order); + ConstTableView get_sorted_view(SortDescriptor order) const; + + // Report the current content version. This is a 64-bit value which is bumped whenever + // the content in the table changes. + uint_fast64_t get_content_version() const noexcept; + + // Report the current instance version. This is a 64-bit value which is bumped + // whenever the table accessor is recycled. + uint_fast64_t get_instance_version() const noexcept; + + // Report the current storage version. This is a 64-bit value which is bumped + // whenever the location in memory of any part of the table changes. + uint_fast64_t get_storage_version(uint64_t instance_version) const; + uint_fast64_t get_storage_version() const; + void bump_storage_version() const noexcept; + void bump_content_version() const noexcept; + + // Change the nullability of the column identified by col_key. + // This might result in the creation of a new column and deletion of the old. + // The column key to use going forward is returned. + // If the conversion is from nullable to non-nullable, throw_on_null determines + // the reaction to encountering a null value: If clear, null values will be + // converted to default values. If set, a 'column_not_nullable' is thrown and the + // table is unchanged. + ColKey set_nullability(ColKey col_key, bool nullable, bool throw_on_null); + + // Iterate through (subset of) columns. The supplied function may abort iteration + // by returning 'true' (early out). + template + bool for_each_and_every_column(Func func) const + { + for (auto col_key : m_leaf_ndx2colkey) { + if (!col_key) + continue; + if (func(col_key)) + return true; + } + return false; + } + template + bool for_each_public_column(Func func) const + { + for (auto col_key : m_leaf_ndx2colkey) { + if (!col_key) + continue; + if (col_key.get_type() == col_type_BackLink) + continue; + if (func(col_key)) + return true; + } + return false; + } + template + bool for_each_backlink_column(Func func) const + { + // FIXME: Optimize later - to not iterate through all non-backlink columns: + for (auto col_key : m_leaf_ndx2colkey) { + if (!col_key) + continue; + if (col_key.get_type() != col_type_BackLink) + continue; + if (func(col_key)) + return true; + } + return false; + } + +private: + template + TableView find_all(ColKey col_key, T value); + void build_column_mapping(); + ColKey generate_col_key(ColumnType ct, ColumnAttrMask attrs); + void convert_column(ColKey from, ColKey to, bool throw_on_null); + template + void change_nullability(ColKey from, ColKey to, bool throw_on_null); + template + void change_nullability_list(ColKey from, ColKey to, bool throw_on_null); + Obj create_linked_object(GlobalKey = {}); + /// Changes embeddedness unconditionally. Called only from Group::do_get_or_add_table() + void do_set_embedded(bool embedded); + +public: + // mapping between index used in leaf nodes (leaf_ndx) and index used in spec (spec_ndx) + // as well as the full column key. A leaf_ndx can be obtained directly from the column key + size_t colkey2spec_ndx(ColKey key) const; + size_t leaf_ndx2spec_ndx(ColKey::Idx idx) const; + ColKey::Idx spec_ndx2leaf_ndx(size_t idx) const; + ColKey leaf_ndx2colkey(ColKey::Idx idx) const; + ColKey spec_ndx2colkey(size_t ndx) const; + void report_invalid_key(ColKey col_key) const; + size_t num_leaf_cols() const; + + // Queries + // Using where(tv) is the new method to perform queries on TableView. The 'tv' can have any order; it does not + // need to be sorted, and, resulting view retains its order. + Query where(ConstTableView* tv = nullptr) + { + return Query(m_own_ref, tv); + } + + // FIXME: We need a ConstQuery class or runtime check against modifications in read transaction. + Query where(ConstTableView* tv = nullptr) const + { + return Query(m_own_ref, tv); + } + + // Perform queries on a LinkView. The returned Query holds a reference to list. + Query where(const LnkLst& list) const + { + return Query(m_own_ref, list); + } + + //@{ + /// WARNING: The link() and backlink() methods will alter a state on the Table object and return a reference + /// to itself. Be aware if assigning the return value of link() to a variable; this might be an error! + + /// This is an error: + + /// Table& cats = owners->link(1); + /// auto& dogs = owners->link(2); + + /// Query q = person_table->where() + /// .and_query(cats.column(5).equal("Fido")) + /// .Or() + /// .and_query(dogs.column(6).equal("Meowth")); + + /// Instead, do this: + + /// Query q = owners->where() + /// .and_query(person_table->link(1).column(5).equal("Fido")) + /// .Or() + /// .and_query(person_table->link(2).column(6).equal("Meowth")); + + /// The two calls to link() in the erroneous example will append the two values 0 and 1 to an internal vector in + /// the owners table, and we end up with three references to that same table: owners, cats and dogs. They are all + /// the same table, its vector has the values {0, 1}, so a query would not make any sense. + LinkChain link(ColKey link_column) const; + LinkChain backlink(const Table& origin, ColKey origin_col_key) const; + + // Conversion + void to_json(std::ostream& out, size_t link_depth = 0, + std::map* renames = nullptr) const; + + /// \brief Compare two tables for equality. + /// + /// Two tables are equal if they have equal descriptors + /// (`Descriptor::operator==()`) and equal contents. Equal descriptors imply + /// that the two tables have the same columns in the same order. Equal + /// contents means that the two tables must have the same number of rows, + /// and that for each row index, the two rows must have the same values in + /// each column. + /// + /// In mixed columns, both the value types and the values are required to be + /// equal. + /// + /// For a particular row and column, if the two values are themselves tables + /// (subtable and mixed columns) value equality implies a recursive + /// invocation of `Table::operator==()`. + bool operator==(const Table&) const; + + /// \brief Compare two tables for inequality. + /// + /// See operator==(). + bool operator!=(const Table& t) const; + + /// Compute the sum of the sizes in number of bytes of all the array nodes + /// that currently make up this table. See also + /// Group::compute_aggregate_byte_size(). + /// + /// If this table accessor is the detached state, this function returns + /// zero. + size_t compute_aggregated_byte_size() const noexcept; + + // Debug + void verify() const; + +#ifdef REALM_DEBUG + MemStats stats() const; +#endif + TableRef get_opposite_table(ColKey col_key) const; + TableKey get_opposite_table_key(ColKey col_key) const; + bool links_to_self(ColKey col_key) const; + ColKey get_opposite_column(ColKey col_key) const; + ColKey find_opposite_column(ColKey col_key) const; + +protected: + /// Compare the objects of two tables under the assumption that the two tables + /// have the same number of columns, and the same data type at each column + /// index (as expressed through the DataType enum). + bool compare_objects(const Table&) const; + + void check_lists_are_empty(size_t row_ndx) const; + +private: + mutable WrappedAllocator m_alloc; + Array m_top; + void update_allocator_wrapper(bool writable) + { + m_alloc.update_from_underlying_allocator(writable); + } + Spec m_spec; // 1st slot in m_top + ClusterTree m_clusters; // 3rd slot in m_top + std::unique_ptr m_tombstones; // 13th slot in m_top + TableKey m_key; // 4th slot in m_top + Array m_index_refs; // 5th slot in m_top + Array m_opposite_table; // 7th slot in m_top + Array m_opposite_column; // 8th slot in m_top + std::vector m_index_accessors; + ColKey m_primary_key_col; + Replication* const* m_repl; + static Replication* g_dummy_replication; + bool m_is_frozen = false; + util::Optional m_has_any_embedded_objects; + TableRef m_own_ref; + + void batch_erase_rows(const KeyColumn& keys); + size_t do_set_link(ColKey col_key, size_t row_ndx, size_t target_row_ndx); + + void populate_search_index(ColKey col_key); + + // Migration support + void migrate_column_info(); + bool verify_column_keys(); + void migrate_indexes(ColKey pk_col_key); + void migrate_subspec(); + void create_columns(); + bool migrate_objects(ColKey pk_col_key); // Returns true if there are no links to migrate + void migrate_links(); + void finalize_migration(ColKey pk_col_key); + + /// Disable copying assignment. + /// + /// It could easily be implemented by calling assign(), but the + /// non-checking nature of the low-level dynamically typed API + /// makes it too risky to offer this feature as an + /// operator. + /// + /// FIXME: assign() has not yet been implemented, but the + /// intention is that it will copy the rows of the argument table + /// into this table after clearing the original contents, and for + /// target tables without a shared spec, it would also copy the + /// spec. For target tables with shared spec, it would be an error + /// to pass an argument table with an incompatible spec, but + /// assign() would not check for spec compatibility. This would + /// make it ideal as a basis for implementing operator=() for + /// typed tables. + Table& operator=(const Table&) = delete; + + /// Create an uninitialized accessor whose lifetime is managed by Group + Table(Replication* const* repl, Allocator&); + void revive(Replication* const* repl, Allocator& new_allocator, bool writable); + + void init(ref_type top_ref, ArrayParent*, size_t ndx_in_parent, bool is_writable, bool is_frozen); + void ensure_graveyard(); + + void set_key(TableKey key); + + ColKey do_insert_column(ColKey col_key, DataType type, StringData name, Table* target_table); + + struct InsertSubtableColumns; + struct EraseSubtableColumns; + struct RenameSubtableColumns; + + void erase_root_column(ColKey col_key); + ColKey do_insert_root_column(ColKey col_key, ColumnType, StringData name); + void do_erase_root_column(ColKey col_key); + + bool has_any_embedded_objects(); + void set_opposite_column(ColKey col_key, TableKey opposite_table, ColKey opposite_column); + void do_set_primary_key_column(ColKey col_key); + void validate_column_is_unique(ColKey col_key) const; + void rebuild_table_with_pk_column(); + + ObjKey get_next_key(); + /// Some Object IDs are generated as a tuple of the client_file_ident and a + /// local sequence number. This function takes the next number in the + /// sequence for the given table and returns an appropriate globally unique + /// GlobalKey. + GlobalKey allocate_object_id_squeezed(); + + /// Find the local 64-bit object ID for the provided global 128-bit ID. + ObjKey global_to_local_object_id_hashed(GlobalKey global_id) const; + + /// After a local ObjKey collision has been detected, this function may be + /// called to obtain a non-colliding local ObjKey in such a way that subsequent + /// calls to global_to_local_object_id() will return the correct local ObjKey + /// for both \a incoming_id and \a colliding_id. + ObjKey allocate_local_id_after_hash_collision(GlobalKey incoming_id, GlobalKey colliding_id, + ObjKey colliding_local_id); + /// Create a placeholder for a not yet existing object and return key to it + Obj get_or_create_tombstone(ObjKey key, const FieldValues& values); + /// Should be called when an object is deleted + void free_local_id_after_hash_collision(ObjKey key); + /// Should be called when last entry is removed - or when table is cleared + void free_collision_table(); + + /// Called in the context of Group::commit() to ensure that + /// attached table accessors stay valid across a commit. Please + /// note that this works only for non-transactional commits. Table + /// accessors obtained during a transaction are always detached + /// when the transaction ends. + void update_from_parent(size_t old_baseline) noexcept; + + // Detach accessor. This recycles the Table accessor and all subordinate + // accessors become invalid. + void detach() noexcept; + void fully_detach() noexcept; + + ColumnType get_real_column_type(ColKey col_key) const noexcept; + + /// If this table is a group-level table, the parent group is returned, + /// otherwise null is returned. + Group* get_parent_group() const noexcept; + uint64_t get_sync_file_id() const noexcept; + + static size_t get_size_from_ref(ref_type top_ref, Allocator&) noexcept; + static size_t get_size_from_ref(ref_type spec_ref, ref_type columns_ref, Allocator&) noexcept; + + /// Create an empty table with independent spec and return just + /// the reference to the underlying memory. + static ref_type create_empty_table(Allocator&, TableKey = TableKey()); + + void nullify_links(CascadeState&); + void remove_recursive(CascadeState&); + + /// Used by query. Follows chain of link columns and returns final target table + const Table* get_link_chain_target(const std::vector&) const; + + Replication* get_repl() const noexcept; + + void set_ndx_in_parent(size_t ndx_in_parent) noexcept; + + /// Refresh the part of the accessor tree that is rooted at this + /// table. + void refresh_accessor_tree(); + void refresh_index_accessors(); + void refresh_content_version(); + void flush_for_commit(); + + bool is_cross_table_link_target() const noexcept; + template + R aggregate(ColKey col_key, T value = {}, size_t* resultcount = nullptr, ObjKey* return_ndx = nullptr) const; + template + double average(ColKey col_key, size_t* resultcount) const; + + std::vector m_leaf_ndx2colkey; + std::vector m_spec_ndx2leaf_ndx; + std::vector m_leaf_ndx2spec_ndx; + bool m_is_embedded = false; + uint64_t m_in_file_version_at_transaction_boundary = 0; + + static constexpr int top_position_for_spec = 0; + static constexpr int top_position_for_columns = 1; + static constexpr int top_position_for_cluster_tree = 2; + static constexpr int top_position_for_key = 3; + static constexpr int top_position_for_search_indexes = 4; + static constexpr int top_position_for_column_key = 5; + static constexpr int top_position_for_version = 6; + static constexpr int top_position_for_opposite_table = 7; + static constexpr int top_position_for_opposite_column = 8; + static constexpr int top_position_for_sequence_number = 9; + static constexpr int top_position_for_collision_map = 10; + static constexpr int top_position_for_pk_col = 11; + static constexpr int top_position_for_flags = 12; + // flags contents: bit 0 - is table embedded? + static constexpr int top_position_for_tombstones = 13; + static constexpr int top_array_size = 14; + + enum { s_collision_map_lo = 0, s_collision_map_hi = 1, s_collision_map_local_id = 2, s_collision_map_num_slots }; + + friend class SubtableNode; + friend class _impl::TableFriend; + friend class Query; + friend class metrics::QueryInfo; + template + friend class SimpleQuerySupport; + friend class LangBindHelper; + friend class ConstTableView; + template + friend class Columns; + friend class Columns; + friend class ParentNode; + friend struct util::serializer::SerialisationState; + friend class LinksToNode; + friend class LinkMap; + friend class LinkView; + friend class Group; + friend class Transaction; + friend class Cluster; + friend class ClusterTree; + friend class ColKeyIterator; + friend class ConstObj; + friend class Obj; + friend class LnkLst; + friend class IncludeDescriptor; +}; + +class ColKeyIterator { +public: + bool operator!=(const ColKeyIterator& other) + { + return m_pos != other.m_pos; + } + ColKeyIterator& operator++() + { + ++m_pos; + return *this; + } + ColKeyIterator operator++(int) + { + ColKeyIterator tmp(m_table, m_pos); + ++m_pos; + return tmp; + } + ColKey operator*() + { + if (m_pos < m_table->get_column_count()) { + REALM_ASSERT(m_table->m_spec.get_key(m_pos) == m_table->spec_ndx2colkey(m_pos)); + return m_table->m_spec.get_key(m_pos); + } + return {}; + } + +private: + friend class ColKeys; + const Table* m_table; + size_t m_pos; + + ColKeyIterator(const Table* t, size_t p) + : m_table(t) + , m_pos(p) + { + } +}; + +class ColKeys { +public: + ColKeys(const Table* t) + : m_table(t) + { + } + + ColKeys() + : m_table(nullptr) + { + } + + size_t size() const + { + return m_table->get_column_count(); + } + bool empty() const + { + return size() == 0; + } + ColKey operator[](size_t p) const + { + return ColKeyIterator(m_table, p).operator*(); + } + ColKeyIterator begin() const + { + return ColKeyIterator(m_table, 0); + } + ColKeyIterator end() const + { + return ColKeyIterator(m_table, size()); + } + +private: + const Table* m_table; +}; + +enum class ExpressionComparisonType : unsigned char { + Any, + All, + None, +}; + +// Class used to collect a chain of links when building up a Query following links. +// It has member functions corresponding to the ones defined on Table. +class LinkChain { +public: + LinkChain(ConstTableRef t, ExpressionComparisonType type = ExpressionComparisonType::Any) + : m_current_table(t.unchecked_ptr()) + , m_base_table(t) + , m_comparison_type(type) + { + } + const Table* get_base_table() + { + return m_base_table.unchecked_ptr(); + } + + LinkChain& link(ColKey link_column) + { + add(link_column); + return *this; + } + + LinkChain& backlink(const Table& origin, ColKey origin_col_key) + { + auto backlink_col_key = origin.get_opposite_column(origin_col_key); + return link(backlink_col_key); + } + + + template + inline Columns column(ColKey col_key) + { + m_current_table->report_invalid_key(col_key); + + // Check if user-given template type equals Realm type. + auto ct = col_key.get_type(); + if (ct == col_type_LinkList) + ct = col_type_Link; + if (ct != ColumnTypeTraits::column_id) + throw LogicError(LogicError::type_mismatch); + + if (std::is_same::value || std::is_same::value || std::is_same::value) { + m_link_cols.push_back(col_key); + } + + return Columns(col_key, m_base_table, m_link_cols, m_comparison_type); + } + template + Columns column(const Table& origin, ColKey origin_col_key) + { + static_assert(std::is_same::value, ""); + + auto backlink_col_key = origin.get_opposite_column(origin_col_key); + m_link_cols.push_back(backlink_col_key); + + return Columns(backlink_col_key, m_base_table, std::move(m_link_cols)); + } + template + SubQuery column(ColKey col_key, Query subquery) + { + static_assert(std::is_same::value, "A subquery must involve a link list or backlink column"); + return SubQuery(column(col_key), std::move(subquery)); + } + + template + SubQuery column(const Table& origin, ColKey origin_col_key, Query subquery) + { + static_assert(std::is_same::value, "A subquery must involve a link list or backlink column"); + return SubQuery(column(origin, origin_col_key), std::move(subquery)); + } + + + template + BacklinkCount get_backlink_count() + { + return BacklinkCount(m_base_table, std::move(m_link_cols)); + } + +private: + friend class Table; + + std::vector m_link_cols; + const Table* m_current_table; + ConstTableRef m_base_table; + ExpressionComparisonType m_comparison_type; + + void add(ColKey ck) + { + // Link column can be a single Link, LinkList, or BackLink. + REALM_ASSERT(m_current_table->valid_column(ck)); + ColumnType type = ck.get_type(); + if (type == col_type_LinkList || type == col_type_Link || type == col_type_BackLink) { + m_current_table = m_current_table->get_opposite_table(ck).unchecked_ptr(); + } + else { + // Only last column in link chain is allowed to be non-link + throw(LogicError::type_mismatch); + } + m_link_cols.push_back(ck); + } +}; + +// Implementation: + +inline ColKeys Table::get_column_keys() const +{ + return ColKeys(this); +} + +inline uint_fast64_t Table::get_content_version() const noexcept +{ + return m_alloc.get_content_version(); +} + +inline uint_fast64_t Table::get_instance_version() const noexcept +{ + return m_alloc.get_instance_version(); +} + + +inline uint_fast64_t Table::get_storage_version(uint64_t instance_version) const +{ + return m_alloc.get_storage_version(instance_version); +} + +inline uint_fast64_t Table::get_storage_version() const +{ + return m_alloc.get_storage_version(); +} + + +inline TableKey Table::get_key() const noexcept +{ + return m_key; +} + +inline void Table::bump_storage_version() const noexcept +{ + return m_alloc.bump_storage_version(); +} + +inline void Table::bump_content_version() const noexcept +{ + m_alloc.bump_content_version(); +} + + + +inline size_t Table::get_column_count() const noexcept +{ + return m_spec.get_public_column_count(); +} + +inline bool Table::is_embedded() const noexcept +{ + return m_is_embedded; +} + +inline StringData Table::get_column_name(ColKey column_key) const +{ + auto spec_ndx = colkey2spec_ndx(column_key); + REALM_ASSERT_3(spec_ndx, <, get_column_count()); + return m_spec.get_column_name(spec_ndx); +} + +inline ColKey Table::get_column_key(StringData name) const noexcept +{ + size_t spec_ndx = m_spec.get_column_index(name); + if (spec_ndx == npos) + return ColKey(); + return spec_ndx2colkey(spec_ndx); +} + +inline ColumnType Table::get_real_column_type(ColKey col_key) const noexcept +{ + return col_key.get_type(); +} + +inline DataType Table::get_column_type(ColKey column_key) const +{ + return DataType(column_key.get_type()); +} + +inline ColumnAttrMask Table::get_column_attr(ColKey column_key) const noexcept +{ + return column_key.get_attrs(); +} + + +inline Table::Table(Allocator& alloc) + : m_alloc(alloc) + , m_top(m_alloc) + , m_spec(m_alloc) + , m_clusters(this, m_alloc, top_position_for_cluster_tree) + , m_index_refs(m_alloc) + , m_opposite_table(m_alloc) + , m_opposite_column(m_alloc) + , m_repl(&g_dummy_replication) + , m_own_ref(this, alloc.get_instance_version()) +{ + m_spec.set_parent(&m_top, top_position_for_spec); + m_index_refs.set_parent(&m_top, top_position_for_search_indexes); + m_opposite_table.set_parent(&m_top, top_position_for_opposite_table); + m_opposite_column.set_parent(&m_top, top_position_for_opposite_column); + + ref_type ref = create_empty_table(m_alloc); // Throws + ArrayParent* parent = nullptr; + size_t ndx_in_parent = 0; + init(ref, parent, ndx_in_parent, true, false); +} + +inline Table::Table(Replication* const* repl, Allocator& alloc) + : m_alloc(alloc) + , m_top(m_alloc) + , m_spec(m_alloc) + , m_clusters(this, m_alloc, top_position_for_cluster_tree) + , m_index_refs(m_alloc) + , m_opposite_table(m_alloc) + , m_opposite_column(m_alloc) + , m_repl(repl) + , m_own_ref(this, alloc.get_instance_version()) +{ + m_spec.set_parent(&m_top, top_position_for_spec); + m_index_refs.set_parent(&m_top, top_position_for_search_indexes); + m_opposite_table.set_parent(&m_top, top_position_for_opposite_table); + m_opposite_column.set_parent(&m_top, top_position_for_opposite_column); +} + +inline void Table::revive(Replication* const* repl, Allocator& alloc, bool writable) +{ + m_alloc.switch_underlying_allocator(alloc); + m_alloc.update_from_underlying_allocator(writable); + m_repl = repl; + m_own_ref = TableRef(this, m_alloc.get_instance_version()); + + // since we're rebinding to a new table, we'll bump version counters + // FIXME + // this can be optimized if version counters are saved along with the + // table data. + bump_content_version(); + bump_storage_version(); + // we assume all other accessors are detached, so we're done. +} + +inline Allocator& Table::get_alloc() const +{ + return m_alloc; +} + +// For use by queries +template +inline Columns Table::column(ColKey col_key) const +{ + LinkChain lc(m_own_ref); + return lc.column(col_key); +} + +template +inline Columns Table::column(const Table& origin, ColKey origin_col_key) const +{ + LinkChain lc(m_own_ref); + return lc.column(origin, origin_col_key); +} + +template +inline BacklinkCount Table::get_backlink_count() const +{ + return BacklinkCount(this, {}); +} + +template +SubQuery Table::column(ColKey col_key, Query subquery) const +{ + LinkChain lc(m_own_ref); + return lc.column(col_key, subquery); +} + +template +SubQuery Table::column(const Table& origin, ColKey origin_col_key, Query subquery) const +{ + LinkChain lc(m_own_ref); + return lc.column(origin, origin_col_key, subquery); +} + +inline LinkChain Table::link(ColKey link_column) const +{ + LinkChain lc(m_own_ref); + lc.add(link_column); + + return lc; +} + +inline LinkChain Table::backlink(const Table& origin, ColKey origin_col_key) const +{ + auto backlink_col_key = origin.get_opposite_column(origin_col_key); + return link(backlink_col_key); +} + +inline bool Table::is_empty() const noexcept +{ + return size() == 0; +} + +inline ConstTableRef Table::get_link_target(ColKey col_key) const noexcept +{ + return const_cast(this)->get_link_target(col_key); +} + +inline bool Table::is_group_level() const noexcept +{ + return bool(get_parent_group()); +} + +inline bool Table::operator==(const Table& t) const +{ + return m_spec == t.m_spec && compare_objects(t); // Throws +} + +inline bool Table::operator!=(const Table& t) const +{ + return !(*this == t); // Throws +} + +inline size_t Table::get_size_from_ref(ref_type top_ref, Allocator& alloc) noexcept +{ + const char* top_header = alloc.translate(top_ref); + std::pair p = Array::get_two(top_header, 0); + ref_type spec_ref = to_ref(p.first), columns_ref = to_ref(p.second); + return get_size_from_ref(spec_ref, columns_ref, alloc); +} + +inline bool Table::is_link_type(ColumnType col_type) noexcept +{ + return col_type == col_type_Link || col_type == col_type_LinkList; +} + +inline Replication* Table::get_repl() const noexcept +{ + return *m_repl; +} + +inline void Table::set_ndx_in_parent(size_t ndx_in_parent) noexcept +{ + REALM_ASSERT(m_top.is_attached()); + m_top.set_ndx_in_parent(ndx_in_parent); +} + +inline size_t Table::colkey2spec_ndx(ColKey key) const +{ + auto leaf_idx = key.get_index(); + REALM_ASSERT(leaf_idx.val < m_leaf_ndx2spec_ndx.size()); + return m_leaf_ndx2spec_ndx[leaf_idx.val]; +} + +inline size_t Table::num_leaf_cols() const +{ + return m_leaf_ndx2spec_ndx.size(); +} + +inline ColKey Table::spec_ndx2colkey(size_t spec_ndx) const +{ + REALM_ASSERT(spec_ndx < m_spec_ndx2leaf_ndx.size()); + return m_leaf_ndx2colkey[m_spec_ndx2leaf_ndx[spec_ndx].val]; +} + +inline void Table::report_invalid_key(ColKey col_key) const +{ + if (col_key == ColKey()) + throw LogicError(LogicError::column_does_not_exist); + auto idx = col_key.get_index(); + if (idx.val >= m_leaf_ndx2colkey.size() || m_leaf_ndx2colkey[idx.val] != col_key) + throw LogicError(LogicError::column_does_not_exist); +} + +inline size_t Table::leaf_ndx2spec_ndx(ColKey::Idx leaf_ndx) const +{ + REALM_ASSERT(leaf_ndx.val < m_leaf_ndx2colkey.size()); + return m_leaf_ndx2spec_ndx[leaf_ndx.val]; +} + +inline ColKey::Idx Table::spec_ndx2leaf_ndx(size_t spec_ndx) const +{ + REALM_ASSERT(spec_ndx < m_spec_ndx2leaf_ndx.size()); + return m_spec_ndx2leaf_ndx[spec_ndx]; +} + +inline ColKey Table::leaf_ndx2colkey(ColKey::Idx leaf_ndx) const +{ + // this may be called with leaf indicies outside of the table. This can happen + // when a column is removed from the mapping, but space for it is still reserved + // at leaf level. Operations on Cluster and ClusterTree which walks the columns + // based on leaf indicies may ask for colkeys which are no longer valid. + if (leaf_ndx.val < m_leaf_ndx2spec_ndx.size()) + return m_leaf_ndx2colkey[leaf_ndx.val]; + else + return ColKey(); +} + +bool inline Table::valid_column(ColKey col_key) const noexcept +{ + if (col_key == ColKey()) + return false; + ColKey::Idx leaf_idx = col_key.get_index(); + if (leaf_idx.val >= m_leaf_ndx2colkey.size()) + return false; + return col_key == m_leaf_ndx2colkey[leaf_idx.val]; +} + +inline void Table::check_column(ColKey col_key) const +{ + if (REALM_UNLIKELY(!valid_column(col_key))) + throw ColumnNotFound(); +} + +// The purpose of this class is to give internal access to some, but +// not all of the non-public parts of the Table class. +class _impl::TableFriend { +public: + static Spec& get_spec(Table& table) noexcept + { + return table.m_spec; + } + + static const Spec& get_spec(const Table& table) noexcept + { + return table.m_spec; + } + + static TableRef get_opposite_link_table(const Table& table, ColKey col_key); + + static Group* get_parent_group(const Table& table) noexcept + { + return table.get_parent_group(); + } + + static void remove_recursive(Table& table, CascadeState& rows) + { + table.remove_recursive(rows); // Throws + } + + static void batch_erase_rows(Table& table, const KeyColumn& keys) + { + table.batch_erase_rows(keys); // Throws + } + // Temporary hack + static Obj create_linked_object(Table& table, GlobalKey id) + { + return table.create_linked_object(id); + } + static ObjKey global_to_local_object_id_hashed(const Table& table, GlobalKey global_id) + { + return table.global_to_local_object_id_hashed(global_id); + } +}; + +} // namespace realm + +#endif // REALM_TABLE_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/table_ref.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/table_ref.hpp new file mode 100644 index 0000000..f454792 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/table_ref.hpp @@ -0,0 +1,141 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_TABLE_REF_HPP +#define REALM_TABLE_REF_HPP + +#include +#include +namespace realm { + + +class Table; +class TableRef; + +class ConstTableRef { +public: + ConstTableRef() noexcept {} + ConstTableRef(std::nullptr_t) noexcept {} + ConstTableRef(const TableRef& other) noexcept; + + const Table* operator->() const; + const Table& operator*() const; + operator bool() const noexcept; + const Table* unchecked_ptr() const + { + return m_table; + } + + bool operator==(const ConstTableRef& other) const + { + return m_table == other.m_table && m_instance_version == other.m_instance_version; + } + + bool operator!=(const ConstTableRef& other) const + { + return !(*this == other); + } + + bool operator<(const ConstTableRef& other) const + { + if (m_table == other.m_table) + return m_instance_version < other.m_instance_version; + else + return m_table < other.m_table; + } + + bool operator>(const ConstTableRef& other) const + { + if (m_table == other.m_table) + return m_instance_version > other.m_instance_version; + else + return m_table > other.m_table; + } + + std::ostream& print(std::ostream& o) const + { + return o << "TableRef(" << m_table << ", " << m_instance_version << ")"; + } + TableRef cast_away_const() const; + static ConstTableRef unsafe_create(const Table* t_ptr); + void check() const; + +protected: + explicit ConstTableRef(const Table* t_ptr, uint64_t instance_version) + : m_table(const_cast(t_ptr)) + , m_instance_version(instance_version) + { + } + friend class Group; + friend class Table; + friend class ClusterTree; + + Table* m_table = nullptr; + uint64_t m_instance_version = 0; +}; + +class TableRef : public ConstTableRef { +public: + TableRef() noexcept + : ConstTableRef() + { + } + TableRef(std::nullptr_t) noexcept + : ConstTableRef() + { + } + + Table* operator->() const; + Table& operator*() const; + Table* unchecked_ptr() const + { + return m_table; + } + static TableRef unsafe_create(Table* t_ptr); + +private: + explicit TableRef(Table* t_ptr, uint64_t instance_version) + : ConstTableRef(t_ptr, instance_version) + { + } + friend class Group; + friend class Table; + friend class ClusterTree; + friend class ConstTableRef; +}; + + +inline ConstTableRef::ConstTableRef(const TableRef& other) noexcept + : m_table(other.m_table) + , m_instance_version(other.m_instance_version) +{ +} + +inline TableRef ConstTableRef::cast_away_const() const +{ + return TableRef(m_table, m_instance_version); +} + +inline std::ostream& operator<<(std::ostream& o, const ConstTableRef& tr) +{ + return tr.print(o); +} + +} // namespace realm + +#endif // REALM_TABLE_REF_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/table_view.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/table_view.hpp new file mode 100644 index 0000000..76621d4 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/table_view.hpp @@ -0,0 +1,712 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_TABLE_VIEW_HPP +#define REALM_TABLE_VIEW_HPP + +#include +#include +#include +#include +#include + +namespace realm { + +// Views, tables and synchronization between them: +// +// Views are built through queries against either tables or another view. +// Views may be restricted to only hold entries provided by another view. +// this other view is called the "restricting view". +// Views may be sorted in ascending or descending order of values in one ore more columns. +// +// Views remember the query from which it was originally built. +// Views remember the table from which it was originally built. +// Views remember a restricting view if one was used when it was originally built. +// Views remember the sorting criteria (columns and direction) +// +// A view may be operated in one of two distinct modes: *reflective* and *imperative*. +// Sometimes the term "reactive" is used instead of "reflective" with the same meaning. +// +// Reflective views: +// - A reflective view *always* *reflect* the result of running the query. +// If the underlying tables or tableviews change, the reflective view changes as well. +// A reflective view may need to rerun the query it was generated from, a potentially +// costly operation which happens on demand. +// - It does not matter whether changes are explicitly done within the transaction, or +// occur implicitly as part of advance_read() or promote_to_write(). +// +// Imperative views: +// - An imperative view only *initially* holds the result of the query. An imperative +// view *never* reruns the query. To force the view to match it's query (by rerunning it), +// the view must be operated in reflective mode. +// An imperative view can be modified explicitly. References can be added, removed or +// changed. +// +// - In imperative mode, the references in the view tracks movement of the referenced data: +// If you delete an entry which is referenced from a view, said reference is detached, +// not removed. +// - It does not matter whether the delete is done in-line (as part of the current transaction), +// or if it is done implicitly as part of advance_read() or promote_to_write(). +// +// The choice between reflective and imperative views might eventually be represented by a +// switch on the tableview, but isn't yet. For now, clients (bindings) must call sync_if_needed() +// to get reflective behavior. +// +// Use cases: +// +// 1. Presenting data +// The first use case (and primary motivator behind the reflective view) is to just track +// and present the state of the database. In this case, the view is operated in reflective +// mode, it is not modified within the transaction, and it is not used to modify data in +// other parts of the database. +// +// 2. Background execution +// This is the second use case. The implicit rerun of the query in our first use case +// may be too costly to be acceptable on the main thread. Instead you want to run the query +// on a worker thread, but display it on the main thread. To achieve this, you need two +// Transactions locked on to the same version of the database. If you have that, you can +// import_copy_of() a view from one transaction to the other. See also db.hpp for more +// information. Technically, you can also import_copy_of into a transaction locked to a +// different version. The imported view will automatically match the importing version. +// +// 3. Iterating a view and changing data +// The third use case (and a motivator behind the imperative view) is when you want +// to make changes to the database in accordance with a query result. Imagine you want to +// find all employees with a salary below a limit and raise their salaries to the limit (pseudocode): +// +// promote_to_write(); +// view = table.where().less_than(salary_column,limit).find_all(); +// for (size_t i = 0; i < view.size(); ++i) { +// view[i].set(salary_column, limit); +// // add this to get reflective mode: view.sync_if_needed(); +// } +// commit_and_continue_as_read(); +// +// This is idiomatic imperative code and it works if the view is operated in imperative mode. +// +// If the view is operated in reflective mode, the behaviour surprises most people: When the +// first salary is changed, the entry no longer fullfills the query, so it is dropped from the +// view implicitly. view[0] is removed, view[1] moves to view[0] and so forth. But the next +// loop iteration has i=1 and refers to view[1], thus skipping view[0]. The end result is that +// every other employee get a raise, while the others don't. +// +// 4. Iterating intermixed with implicit updates +// This leads us to use case 4, which is similar to use case 3, but uses promote_to_write() +// intermixed with iterating a view. This is actually quite important to some, who do not want +// to end up with a large write transaction. +// +// view = table.where().less_than(salary_column,limit).find_all(); +// for (size_t i = 0; i < view.size(); ++i) { +// promote_to_write(); +// view[i].set(salary_column, limit); +// commit_and_continue_as_write(); +// } +// +// Anything can happen at the call to promote_to_write(). The key question then becomes: how +// do we support a safe way of realising the original goal (raising salaries) ? +// +// using the imperative operating mode: +// +// view = table.where().less_than(salary_column,limit).find_all(); +// for (size_t i = 0; i < view.size(); ++i) { +// promote_to_write(); +// // add r.sync_if_needed(); to get reflective mode +// if (r.is_obj_valid(i)) { +// auto r = view[i]; +// view[i].set(salary_column, limit); +// } +// commit_and_continue_as_write(); +// } +// +// This is safe, and we just aim for providing low level safety: is_obj_valid() can tell +// if the reference is valid, and the references in the view continue to point to the +// same object at all times, also following implicit updates. The rest is up to the +// application logic. +// +// It is important to see, that there is no guarantee that all relevant employees get +// their raise in cases whith concurrent updates. At every call to promote_to_write() new +// employees may be added to the underlying table, but as the view is in imperative mode, +// these new employees are not added to the view. Also at promote_to_write() an existing +// employee could recieve a (different, larger) raise which would then be overwritten and lost. +// However, these are problems that you should expect, since the activity is spread over multiple +// transactions. + + +/// A ConstTableView gives read access to the parent table, but no +/// write access. The view itself, though, can be changed, for +/// example, it can be sorted. +/// +/// Note that methods are declared 'const' if, and only if they leave +/// the view unmodified, and this is irrespective of whether they +/// modify the parent table. +/// +/// A ConstTableView has both copy and move semantics. See TableView +/// for more on this. +class ConstTableView : public ObjList { +public: + + /// Construct null view (no memory allocated). + ConstTableView() + : m_key_values(Allocator::get_default()) + { + } + + + /// Construct empty view, ready for addition of row indices. + ConstTableView(ConstTableRef parent); + ConstTableView(ConstTableRef parent, Query& query, size_t start, size_t end, size_t limit); + ConstTableView(ConstTableRef parent, ColKey column, const ConstObj& obj); + ConstTableView(ConstTableRef parent, ConstLnkLstPtr link_list); + + /// Copy constructor. + ConstTableView(const ConstTableView&); + + /// Move constructor. + ConstTableView(ConstTableView&&) noexcept; + + ConstTableView& operator=(const ConstTableView&); + ConstTableView& operator=(ConstTableView&&) noexcept; + + ConstTableView(const ConstTableView& source, Transaction* tr, PayloadPolicy mode); + ConstTableView(ConstTableView& source, Transaction* tr, PayloadPolicy mode); + + ~ConstTableView() + { + m_key_values.destroy(); // Shallow + } + + TableRef get_target_table() const override + { + return m_table.cast_away_const(); + } + size_t size() const override + { + return m_key_values.size(); + } + bool is_empty() const noexcept + { + return m_key_values.size() == 0; + } + + // Tells if the table that this TableView points at still exists or has been deleted. + bool is_attached() const noexcept + { + return bool(m_table); + } + + ObjKey get_key(size_t ndx) const override + { + return m_key_values.get(ndx); + } + + bool is_obj_valid(size_t ndx) const noexcept override + { + return m_table->is_valid(get_key(ndx)); + } + + Obj get_object(size_t ndx) const override + { + return m_table.cast_away_const()->get_object(get_key(ndx)); + } + + // Get the query used to create this TableView + // The query will have a null source table if this tv was not created from + // a query + const Query& get_query() const noexcept + { + return m_query; + } + + std::unique_ptr clone() const + { + return std::unique_ptr(new ConstTableView(*this)); + } + + // import_copy_of() machinery entry points based on dynamic type. These methods: + // a) forward their calls to the static type entry points. + // b) new/delete patch data structures. + std::unique_ptr clone_for_handover(Transaction* tr, PayloadPolicy mode) const + { + std::unique_ptr retval(new ConstTableView(*this, tr, mode)); + return retval; + } + template + R aggregate(ColKey column_key, size_t* result_count = nullptr, ObjKey* return_key = nullptr) const; + template + size_t aggregate_count(ColKey column_key, T count_target) const; + + int64_t sum_int(ColKey column_key) const; + int64_t maximum_int(ColKey column_key, ObjKey* return_key = nullptr) const; + int64_t minimum_int(ColKey column_key, ObjKey* return_key = nullptr) const; + double average_int(ColKey column_key, size_t* value_count = nullptr) const; + size_t count_int(ColKey column_key, int64_t target) const; + + double sum_float(ColKey column_key) const; + float maximum_float(ColKey column_key, ObjKey* return_key = nullptr) const; + float minimum_float(ColKey column_key, ObjKey* return_key = nullptr) const; + double average_float(ColKey column_key, size_t* value_count = nullptr) const; + size_t count_float(ColKey column_key, float target) const; + + double sum_double(ColKey column_key) const; + double maximum_double(ColKey column_key, ObjKey* return_key = nullptr) const; + double minimum_double(ColKey column_key, ObjKey* return_key = nullptr) const; + double average_double(ColKey column_key, size_t* value_count = nullptr) const; + size_t count_double(ColKey column_key, double target) const; + + Timestamp minimum_timestamp(ColKey column_key, ObjKey* return_key = nullptr) const; + Timestamp maximum_timestamp(ColKey column_key, ObjKey* return_key = nullptr) const; + size_t count_timestamp(ColKey column_key, Timestamp target) const; + + Decimal128 sum_decimal(ColKey column_key) const; + Decimal128 maximum_decimal(ColKey column_key, ObjKey* return_key = nullptr) const; + Decimal128 minimum_decimal(ColKey column_key, ObjKey* return_key = nullptr) const; + Decimal128 average_decimal(ColKey column_key, size_t* value_count = nullptr) const; + size_t count_decimal(ColKey column_key, Decimal128 target) const; + + /// Search this view for the specified key. If found, the index of that row + /// within this view is returned, otherwise `realm::not_found` is returned. + size_t find_by_source_ndx(ObjKey key) const noexcept + { + return m_key_values.find_first(key); + } + + // Conversion + void to_json(std::ostream&, size_t link_depth = 0, std::map* renames = nullptr) const; + + // Determine if the view is 'in sync' with the underlying table + // as well as other views used to generate the view. Note that updates + // through views maintains synchronization between view and table. + // It doesnt by itself maintain other views as well. So if a view + // is generated from another view (not a table), updates may cause + // that view to be outdated, AND as the generated view depends upon + // it, it too will become outdated. + bool is_in_sync() const override; + + // A TableView is frozen if it is a) obtained from a query against a frozen table + // and b) is synchronized (is_in_sync()) + bool is_frozen() { return m_table->is_frozen() && is_in_sync(); } + // Tells if this TableView depends on a LinkList or row that has been deleted. + bool depends_on_deleted_object() const; + + // Synchronize a view to match a table or tableview from which it + // has been derived. Synchronization is achieved by rerunning the + // query used to generate the view. If derived from another view, that + // view will be synchronized as well. + // + // "live" or "reactive" views are implemented by calling sync_if_needed() + // before any of the other access-methods whenever the view may have become + // outdated. + void sync_if_needed() const override; + // Return the version of the source it was created from. + TableVersions get_dependency_versions() const + { + TableVersions ret; + get_dependencies(ret); + return ret; + } + + + // Sort m_key_values according to one column + void sort(ColKey column, bool ascending = true); + + // Sort m_key_values according to multiple columns + void sort(SortDescriptor order); + + // Get the number of total results which have been filtered out because a number of "LIMIT" operations have + // been applied. This number only applies to the last sync. + size_t get_num_results_excluded_by_limit() const noexcept + { + return m_limit_count; + } + + // Remove rows that are duplicated with respect to the column set passed as argument. + // distinct() will preserve the original order of the row pointers, also if the order is a result of sort() + // If two rows are indentical (for the given set of distinct-columns), then the last row is removed. + // You can call sync_if_needed() to update the distinct view, just like you can for a sorted view. + // Each time you call distinct() it will compound on the previous calls + void distinct(ColKey column); + void distinct(DistinctDescriptor columns); + void limit(LimitDescriptor limit); + void include(IncludeDescriptor include_paths); + IncludeDescriptor get_include_descriptors(); + + // Replace the order of sort and distinct operations, bypassing manually + // calling sort and distinct. This is a convenience method for bindings. + void apply_descriptor_ordering(const DescriptorOrdering& new_ordering); + + // Gets a readable and parsable string which completely describes the sort and + // distinct operations applied to this view. + std::string get_descriptor_ordering_description() const; + + // Returns whether the rows are guaranteed to be in table order. + // This is true only of unsorted TableViews created from either: + // - Table::find_all() + // - Query::find_all() when the query is not restricted to a view. + bool is_in_table_order() const; + + bool is_backlink_view() const + { + return m_source_column_key != ColKey(); + } + +protected: + // This TableView can be "born" from 4 different sources: + // - LinkView + // - Query::find_all() + // - Table::get_distinct_view() + // - Table::get_backlink_view() + + void get_dependencies(TableVersions&) const override; + + void do_sync(); + void do_sort(const DescriptorOrdering&); + + mutable ConstTableRef m_table; + // The source column index that this view contain backlinks for. + ColKey m_source_column_key; + // The target object that rows in this view link to. + ObjKey m_linked_obj_key; + ConstTableRef m_linked_table; + + // If this TableView was created from a LnkLst, then this reference points to it. Otherwise it's 0 + mutable ConstLnkLstPtr m_linklist_source; + + // Stores the ordering criteria of applied sort and distinct operations. + DescriptorOrdering m_descriptor_ordering; + size_t m_limit_count = 0; + + // A valid query holds a reference to its table which must match our m_table. + // hence we can use a query with a null table reference to indicate that the view + // was NOT generated by a query, but follows a table directly. + Query m_query; + // parameters for findall, needed to rerun the query + size_t m_start = 0; + size_t m_end = size_t(-1); + size_t m_limit = size_t(-1); + + mutable TableVersions m_last_seen_versions; + KeyColumn m_key_values; + +private: + ObjKey find_first_integer(ColKey column_key, int64_t value) const; + template + Timestamp minmax_timestamp(ColKey column_key, ObjKey* return_key) const; + util::RaceDetector m_race_detector; + + friend class Table; + friend class ConstObj; + friend class Query; + friend class DB; + friend class ObjList; +}; + +enum class RemoveMode { ordered, unordered }; + + +/// A TableView gives read and write access to the parent table. +/// +/// A 'const TableView' cannot be changed (e.g. sorted), nor can the +/// parent table be modified through it. +/// +/// A TableView is both copyable and movable. +class TableView : public ConstTableView { +public: + using ConstTableView::ConstTableView; + + TableView() = default; + + TableRef get_parent() noexcept + { + return m_table.cast_away_const(); + } + + // Rows + Obj get(size_t row_ndx); + Obj front(); + Obj back(); + Obj operator[](size_t row_ndx); + + /// \defgroup table_view_removes + //@{ + /// \brief Remove the specified row (or rows) from the underlying table. + /// + /// remove() removes the specified row from the underlying table, + /// remove_last() removes the last row in the table view from the underlying + /// table, and clear removes all the rows in the table view from the + /// underlying table. + /// + /// When rows are removed from the underlying table, they will by necessity + /// also be removed from the table view. The order of the remaining rows in + /// the the table view will be maintained. + /// + /// \param row_ndx The index within this table view of the row to be removed. + void remove(size_t row_ndx); + void remove_last(); + void clear(); + //@} + + std::unique_ptr clone() const + { + return std::unique_ptr(new TableView(*this)); + } + + std::unique_ptr clone_for_handover(Transaction* tr, PayloadPolicy policy) const + { + std::unique_ptr retval(new TableView(*this, tr, policy)); + return retval; + } + +private: + TableView(TableRef parent); + TableView(TableRef parent, Query& query, size_t start, size_t end, size_t limit); + TableView(TableRef parent, ConstLnkLstPtr); + + friend class ConstTableView; + friend class Table; + friend class Query; + friend class LnkLst; +}; + + + + +// ================================================================================================ +// ConstTableView Implementation: + +inline ConstTableView::ConstTableView(ConstTableRef parent) + : m_table(parent) // Throws + , m_key_values(Allocator::get_default()) +{ + m_key_values.create(); + if (m_table) { + m_last_seen_versions.emplace_back(m_table->get_key(), m_table->get_content_version()); + } +} + +inline ConstTableView::ConstTableView(ConstTableRef parent, Query& query, size_t start, size_t end, size_t lim) + : m_table(parent) + , m_query(query) + , m_start(start) + , m_end(end) + , m_limit(lim) + , m_key_values(Allocator::get_default()) +{ + m_key_values.create(); +} + +inline ConstTableView::ConstTableView(ConstTableRef src_table, ColKey src_column_key, const ConstObj& obj) + : m_table(src_table) // Throws + , m_source_column_key(src_column_key) + , m_linked_obj_key(obj.get_key()) + , m_linked_table(obj.get_table()) + , m_key_values(Allocator::get_default()) +{ + m_key_values.create(); + if (m_table) { + m_last_seen_versions.emplace_back(m_table->get_key(), m_table->get_content_version()); + m_last_seen_versions.emplace_back(obj.get_table()->get_key(), obj.get_table()->get_content_version()); + } +} + +inline ConstTableView::ConstTableView(ConstTableRef parent, ConstLnkLstPtr link_list) + : m_table(parent) // Throws + , m_linklist_source(std::move(link_list)) + , m_key_values(Allocator::get_default()) +{ + REALM_ASSERT(m_linklist_source); + m_key_values.create(); + if (m_table) { + m_last_seen_versions.emplace_back(m_table->get_key(), m_table->get_content_version()); + } +} + +inline ConstTableView::ConstTableView(const ConstTableView& tv) + : m_table(tv.m_table) + , m_source_column_key(tv.m_source_column_key) + , m_linked_obj_key(tv.m_linked_obj_key) + , m_linked_table(tv.m_linked_table) + , m_linklist_source(tv.m_linklist_source ? tv.m_linklist_source->clone() : LnkLstPtr{}) + , m_descriptor_ordering(tv.m_descriptor_ordering) + , m_query(tv.m_query) + , m_start(tv.m_start) + , m_end(tv.m_end) + , m_limit(tv.m_limit) + , m_last_seen_versions(tv.m_last_seen_versions) + , m_key_values(tv.m_key_values) +{ + m_limit_count = tv.m_limit_count; +} + +inline ConstTableView::ConstTableView(ConstTableView&& tv) noexcept + : m_table(tv.m_table) + , m_source_column_key(tv.m_source_column_key) + , m_linked_obj_key(tv.m_linked_obj_key) + , m_linked_table(tv.m_linked_table) + , m_linklist_source(std::move(tv.m_linklist_source)) + , m_descriptor_ordering(std::move(tv.m_descriptor_ordering)) + , m_query(std::move(tv.m_query)) + , m_start(tv.m_start) + , m_end(tv.m_end) + , m_limit(tv.m_limit) + // if we are created from a table view which is outdated, take care to use the outdated + // version number so that we can later trigger a sync if needed. + , m_last_seen_versions(std::move(tv.m_last_seen_versions)) + , m_key_values(std::move(tv.m_key_values)) +{ + m_limit_count = tv.m_limit_count; +} + +inline ConstTableView& ConstTableView::operator=(ConstTableView&& tv) noexcept +{ + m_table = std::move(tv.m_table); + + m_key_values = std::move(tv.m_key_values); + m_query = std::move(tv.m_query); + m_last_seen_versions = tv.m_last_seen_versions; + m_start = tv.m_start; + m_end = tv.m_end; + m_limit = tv.m_limit; + m_limit_count = tv.m_limit_count; + m_source_column_key = tv.m_source_column_key; + m_linked_obj_key = tv.m_linked_obj_key; + m_linked_table = tv.m_linked_table; + m_linklist_source = std::move(tv.m_linklist_source); + m_descriptor_ordering = std::move(tv.m_descriptor_ordering); + + return *this; +} + +inline ConstTableView& ConstTableView::operator=(const ConstTableView& tv) +{ + if (this == &tv) + return *this; + + m_key_values = tv.m_key_values; + + m_query = tv.m_query; + m_last_seen_versions = tv.m_last_seen_versions; + m_start = tv.m_start; + m_end = tv.m_end; + m_limit = tv.m_limit; + m_limit_count = tv.m_limit_count; + m_source_column_key = tv.m_source_column_key; + m_linked_obj_key = tv.m_linked_obj_key; + m_linked_table = tv.m_linked_table; + m_linklist_source = tv.m_linklist_source ? tv.m_linklist_source->clone() : LnkLstPtr{}; + m_descriptor_ordering = tv.m_descriptor_ordering; + + return *this; +} + +#define REALM_ASSERT_COLUMN(column_key) \ + m_table.check(); \ + REALM_ASSERT(m_table->colkey2ndx(column_key)) + +#define REALM_ASSERT_ROW(row_ndx) \ + m_table.check(); \ + REALM_ASSERT(row_ndx < m_key_values.size()) + +#define REALM_ASSERT_COLUMN_AND_TYPE(column_key, column_type) \ + REALM_ASSERT_COLUMN(column_key); \ + REALM_DIAG_PUSH(); \ + REALM_DIAG_IGNORE_TAUTOLOGICAL_COMPARE(); \ + REALM_ASSERT(m_table->get_column_type(column_key) == column_type); \ + REALM_DIAG_POP() + +#define REALM_ASSERT_INDEX(column_key, row_ndx) \ + REALM_ASSERT_COLUMN(column_key); \ + REALM_ASSERT(row_ndx < m_key_values.size()) + +#define REALM_ASSERT_INDEX_AND_TYPE(column_key, row_ndx, column_type) \ + REALM_ASSERT_COLUMN_AND_TYPE(column_key, column_type); \ + REALM_ASSERT(row_ndx < m_key_values.size()) + +#define REALM_ASSERT_INDEX_AND_TYPE_TABLE_OR_MIXED(column_key, row_ndx) \ + REALM_ASSERT_COLUMN(column_key); \ + REALM_DIAG_PUSH(); \ + REALM_DIAG_IGNORE_TAUTOLOGICAL_COMPARE(); \ + REALM_ASSERT(m_table->get_column_type(column_key) == type_Table || \ + (m_table->get_column_type(column_key) == type_Mixed)); \ + REALM_DIAG_POP(); \ + REALM_ASSERT(row_ndx < m_key_values.size()) + +//-------------------------- TableView, ConstTableView implementation: + +template +ConstTableView ObjList::find_all(ColKey column_key, T value) const +{ + ConstTableView tv(get_target_table()); + auto& keys = tv.m_key_values; + for_each([column_key, value, &keys](ConstObj& o) { + if (o.get(column_key) == value) { + keys.add(o.get_key()); + } + return false; + }); + return tv; +} + +inline void TableView::remove_last() +{ + if (!is_empty()) + remove(size() - 1); +} + +inline TableView::TableView(TableRef parent) + : ConstTableView(parent) +{ +} + +inline TableView::TableView(TableRef parent, Query& query, size_t start, size_t end, size_t lim) + : ConstTableView(parent, query, start, end, lim) +{ +} + +inline TableView::TableView(TableRef parent, ConstLnkLstPtr link_list) + : ConstTableView(parent, std::move(link_list)) +{ +} + +// Rows +inline Obj TableView::get(size_t row_ndx) +{ + REALM_ASSERT_ROW(row_ndx); + ObjKey key(m_key_values.get(row_ndx)); + REALM_ASSERT(key != realm::null_key); + return get_parent()->get_object(key); +} + +inline Obj TableView::front() +{ + return get(0); +} + +inline Obj TableView::back() +{ + size_t last_row_ndx = size() - 1; + return get(last_row_ndx); +} + +inline Obj TableView::operator[](size_t row_ndx) +{ + return get(row_ndx); +} + +} // namespace realm + +#endif // REALM_TABLE_VIEW_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/timestamp.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/timestamp.hpp new file mode 100644 index 0000000..20265f1 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/timestamp.hpp @@ -0,0 +1,233 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_TIMESTAMP_HPP +#define REALM_TIMESTAMP_HPP + +#include +#include +#include +#include +#include +#include + +namespace realm { + +class Timestamp { +public: + // Construct from the number of seconds and nanoseconds since the UNIX epoch: 00:00:00 UTC on 1 January 1970 + // + // To split a native nanosecond representation, only division and modulo are necessary: + // + // s = native_nano / nanoseconds_per_second + // n = native_nano % nanoseconds_per_second + // Timestamp ts(s, n); + // + // To convert back into native nanosecond representation, simple multiply and add: + // + // native_nano = ts.s * nanoseconds_per_second + ts.n + // + // Specifically this allows the nanosecond part to become negative (only) for Timestamps before the UNIX epoch. + // Usually this will not need special attention, but for reference, valid Timestamps will have one of the + // following sign combinations: + // + // s | n + // ----- + // + | + + // + | 0 + // 0 | + + // 0 | 0 + // 0 | - + // - | 0 + // - | - + // + // Examples: + // The UNIX epoch is constructed by Timestamp(0, 0) + // Relative times are constructed as follows: + // +1 second is constructed by Timestamp(1, 0) + // +1 nanosecond is constructed by Timestamp(0, 1) + // +1.1 seconds (1100 milliseconds after the epoch) is constructed by Timestamp(1, 100000000) + // -1.1 seconds (1100 milliseconds before the epoch) is constructed by Timestamp(-1, -100000000) + // + Timestamp(int64_t seconds, int32_t nanoseconds) + : m_seconds(seconds) + , m_nanoseconds(nanoseconds) + , m_is_null(false) + { + REALM_ASSERT_EX(-nanoseconds_per_second < nanoseconds && nanoseconds < nanoseconds_per_second, nanoseconds); + const bool both_non_negative = seconds >= 0 && nanoseconds >= 0; + const bool both_non_positive = seconds <= 0 && nanoseconds <= 0; + REALM_ASSERT_EX(both_non_negative || both_non_positive, both_non_negative, both_non_positive); + } + Timestamp(realm::null) + : m_is_null(true) + { + } + template + Timestamp(std::chrono::time_point tp) + : m_is_null(false) + { + int64_t native_nano = std::chrono::duration_cast(tp.time_since_epoch()).count(); + m_seconds = native_nano / nanoseconds_per_second; + m_nanoseconds = static_cast(native_nano % nanoseconds_per_second); + } + Timestamp() + : Timestamp(null{}) + { + } + + bool is_null() const + { + return m_is_null; + } + + int64_t get_seconds() const noexcept + { + REALM_ASSERT(!m_is_null); + return m_seconds; + } + + int32_t get_nanoseconds() const noexcept + { + REALM_ASSERT(!m_is_null); + return m_nanoseconds; + } + + template + std::chrono::time_point get_time_point() + { + REALM_ASSERT(!m_is_null); + + int64_t native_nano = m_seconds * nanoseconds_per_second + m_nanoseconds; + auto duration = std::chrono::duration_cast(std::chrono::duration{native_nano}); + + return std::chrono::time_point(duration); + } + + bool operator==(const Timestamp& rhs) const + { + if (is_null() && rhs.is_null()) + return true; + + if (is_null() != rhs.is_null()) + return false; + + return m_seconds == rhs.m_seconds && m_nanoseconds == rhs.m_nanoseconds; + } + bool operator!=(const Timestamp& rhs) const + { + return !(*this == rhs); + } + bool operator>(const Timestamp& rhs) const + { + if (is_null()) { + return false; + } + if (rhs.is_null()) { + return true; + } + return (m_seconds > rhs.m_seconds) || (m_seconds == rhs.m_seconds && m_nanoseconds > rhs.m_nanoseconds); + } + bool operator<(const Timestamp& rhs) const + { + if (rhs.is_null()) { + return false; + } + if (is_null()) { + return true; + } + return (m_seconds < rhs.m_seconds) || (m_seconds == rhs.m_seconds && m_nanoseconds < rhs.m_nanoseconds); + } + bool operator<=(const Timestamp& rhs) const + { + if (is_null()) { + return true; + } + if (rhs.is_null()) { + return false; + } + return *this < rhs || *this == rhs; + } + bool operator>=(const Timestamp& rhs) const + { + if (rhs.is_null()) { + return true; + } + if (is_null()) { + return false; + } + return *this > rhs || *this == rhs; + } + Timestamp& operator=(const Timestamp& rhs) = default; + + template + friend std::basic_ostream& operator<<(std::basic_ostream& out, const Timestamp&); + static constexpr int32_t nanoseconds_per_second = 1000000000; + +private: + int64_t m_seconds; + int32_t m_nanoseconds; + bool m_is_null; +}; + +// LCOV_EXCL_START +template +inline std::basic_ostream& operator<<(std::basic_ostream& out, const Timestamp& d) +{ + auto seconds = time_t(d.get_seconds()); + struct tm buf; +#ifdef _MSC_VER + bool success = gmtime_s(&buf, &seconds) == 0; +#else + bool success = gmtime_r(&seconds, &buf) != nullptr; +#endif + if (success) { + // We need a buffer for formatting dates. + // Max size is 20 bytes (incl terminating zero) "YYYY-MM-DD HH:MM:SS"\0 + char buffer[30]; + if (strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &buf)) { + out << buffer; + } + } + + return out; +} +// LCOV_EXCL_STOP + +} // namespace realm + +namespace std { +template <> +struct numeric_limits { + static constexpr bool is_integer = false; + static realm::Timestamp min() + { + return realm::Timestamp(numeric_limits::min(), 0); + } + static realm::Timestamp lowest() + { + return realm::Timestamp(numeric_limits::lowest(), 0); + } + static realm::Timestamp max() + { + return realm::Timestamp(numeric_limits::max(), 0); + } +}; +} + +#endif // REALM_TIMESTAMP_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/unicode.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/unicode.hpp new file mode 100644 index 0000000..d8b3d33 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/unicode.hpp @@ -0,0 +1,163 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_UNICODE_HPP +#define REALM_UNICODE_HPP + +#include +#include +#include + +#include +#include +#include + + +namespace realm { + +enum string_compare_method_t { + STRING_COMPARE_CORE, + STRING_COMPARE_CPP11, + STRING_COMPARE_CALLBACK, + STRING_COMPARE_CORE_SIMILAR +}; + +extern StringCompareCallback string_compare_callback; +extern string_compare_method_t string_compare_method; + +// Description for set_string_compare_method(): +// +// Short summary: iOS language binding: call +// set_string_compare_method() for fast but slightly inaccurate sort in some countries, or +// set_string_compare_method(2, callbackptr) for slow but precise sort (see callbackptr below) +// +// Different countries ('locales') have different sorting order for strings and letters. Because there unfortunatly +// doesn't exist any unified standardized way to compare strings in C++ on multiple platforms, we need this method. +// +// It determins how sorting a TableView by a String column must take place. The 'method' argument can be: +// +// 0: Fast core-only compare (no OS/framework calls). LIMITATIONS: Works only upto 'Latin Extended 2' (unicodes +// 0...591). Also, sorting order is according to 'en_US' so it may be slightly inaccurate for some countries. +// 'callback' argument is ignored. +// +// Return value: Always 'true' +// +// 1: Native C++11 method if core is compiled as C++11. Gives precise sorting according +// to user's current locale. LIMITATIONS: Currently works only on Windows and on Linux with clang. Does NOT work on +// iOS (due to only 'C' locale being available in CoreFoundation, which puts 'Z' before 'a'). Unknown if works on +// Windows Phone / Android. Furthermore it does NOT work on Linux with gcc 4.7 or 4.8 (lack of c++11 feature that +// can convert utf8->wstring without calls to setlocale()). +// +// Return value: 'true' if supported, otherwise 'false' (if so, then previous setting, if any, is preserved). +// +// 2: Callback method. Language binding / C++ user must provide a utf-8 callback method of prototype: +// bool callback(const char* string1, const char* string2) where 'callback' must return bool(string1 < string2). +// +// Return value: Always 'true' +// +// Default is method = 0 if the function is never called +// +// NOT THREAD SAFE! Call once during initialization or make sure it's not called simultaneously with different +// arguments. The setting is remembered per-process; it does NOT need to be called prior to each sort +bool set_string_compare_method(string_compare_method_t method, StringCompareCallback callback); + + +// Return size in bytes of utf8 character. No error checking +size_t sequence_length(char lead); + +// Limitations for case insensitive string search +// Case insensitive search (equal, begins_with, ends_with, like and contains) +// only works for unicodes 0...0x7f which is the same as the 0...127 +// ASCII character set (letters a-z and A-Z). + +// In does *not* work for the 0...255 ANSI character set that contains +// characters from many European countries like Germany, France, Denmark, +// etc. + +// It also does not work for characters from non-western countries like +// Japan, Russia, Arabia, etc. + +// If there exists characters outside the ASCII range either in the text +// to be searched for, or in the Realm string column which is searched +// in, then the compare yields a random result such that the row may or +// may not be included in the result set. + +// Return bool(string1 < string2) +bool utf8_compare(StringData string1, StringData string2); + +// Return unicode value of character. +uint32_t utf8value(const char* character); + +inline bool equal_sequence(const char*& begin, const char* end, const char* begin2); + +// FIXME: The current approach to case insensitive comparison requires +// that case mappings can be done in a way that does not change he +// number of bytes used to encode the individual Unicode +// character. This is not generally the case, so, as far as I can see, +// this approach has no future. +// +// FIXME: The current approach to case insensitive comparison relies +// on checking each "haystack" character against the corresponding +// character in both a lower cased and an upper cased version of the +// "needle". While this leads to efficient comparison, it ignores the +// fact that "case folding" is the only correct approach to case +// insensitive comparison in a locale agnostic Unicode +// environment. +// +// See +// http://www.w3.org/International/wiki/Case_folding +// http://userguide.icu-project.org/transforms/casemappings#TOC-Case-Folding. +// +// The ideal API would probably be something like this: +// +// case_fold: utf_8 -> case_folded +// equal_case_fold: (needle_case_folded, single_haystack_entry_utf_8) -> found +// search_case_fold: (needle_case_folded, huge_haystack_string_utf_8) -> found_at_position +// +// The case folded form would probably be using UTF-32 or UTF-16. + + +/// If successful, returns a string of the same size as \a source. +/// Returns none if invalid UTF-8 encoding was encountered. +util::Optional case_map(StringData source, bool upper); + +enum IgnoreErrorsTag { IgnoreErrors }; +std::string case_map(StringData source, bool upper, IgnoreErrorsTag); + +/// Assumes that the sizes of \a needle_upper and \a needle_lower are +/// identical to the size of \a haystack. Returns false if the needle +/// is different from the haystack. +bool equal_case_fold(StringData haystack, const char* needle_upper, const char* needle_lower); + +/// Assumes that the sizes of \a needle_upper and \a needle_lower are +/// both equal to \a needle_size. Returns haystack.size() if the +/// needle was not found. +size_t search_case_fold(StringData haystack, const char* needle_upper, const char* needle_lower, size_t needle_size); + +/// Assumes that the sizes of \a needle_upper and \a needle_lower are +/// both equal to \a needle_size. Returns false if the +/// needle was not found. +bool contains_ins(StringData haystack, const char* needle_upper, const char* needle_lower, size_t needle_size, const std::array &charmap); + +/// Case insensitive wildcard matching ('?' for single char, '*' for zero or more chars) +bool string_like_ins(StringData text, StringData pattern) noexcept; +bool string_like_ins(StringData text, StringData upper, StringData lower) noexcept; + +} // namespace realm + +#endif // REALM_UNICODE_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/aes_cryptor.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/aes_cryptor.hpp new file mode 100644 index 0000000..23720b1 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/aes_cryptor.hpp @@ -0,0 +1,113 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 +#include +#include +#include +#include +#include + +#if REALM_ENABLE_ENCRYPTION + +#if REALM_PLATFORM_APPLE +#include +#elif defined(_WIN32) +#include +#include +#include +#pragma comment(lib, "bcrypt.lib") +#else +#include +#include +#endif + +namespace realm { +namespace util { + +struct iv_table; +class EncryptedFileMapping; + +class AESCryptor { +public: + AESCryptor(const uint8_t* key); + ~AESCryptor() noexcept; + + void set_file_size(off_t new_size); + + bool read(FileDesc fd, off_t pos, char* dst, size_t size); + void write(FileDesc fd, off_t pos, const char* src, size_t size) noexcept; + +private: + enum EncryptionMode { +#if REALM_PLATFORM_APPLE + mode_Encrypt = kCCEncrypt, + mode_Decrypt = kCCDecrypt +#elif defined(_WIN32) + mode_Encrypt = 0, + mode_Decrypt = 1 +#else + mode_Encrypt = 1, + mode_Decrypt = 0 +#endif + }; + +#if REALM_PLATFORM_APPLE + CCCryptorRef m_encr; + CCCryptorRef m_decr; +#elif defined(_WIN32) + BCRYPT_KEY_HANDLE m_aes_key_handle; +#else + uint8_t m_aesKey[32]; + EVP_CIPHER_CTX* m_ctx; +#endif + + uint8_t m_hmacKey[32]; + std::vector m_iv_buffer; + std::unique_ptr m_rw_buffer; + std::unique_ptr m_dst_buffer; + + void calc_hmac(const void* src, size_t len, uint8_t* dst, const uint8_t* key) const; + bool check_hmac(const void* data, size_t len, const uint8_t* hmac) const; + void crypt(EncryptionMode mode, off_t pos, char* dst, const char* src, const char* stored_iv) noexcept; + iv_table& get_iv_table(FileDesc fd, off_t data_pos) noexcept; + void handle_error(); +}; + +struct ReaderInfo { + const void* reader_ID; + uint64_t version; +}; + +struct SharedFileInfo { + FileDesc fd; + AESCryptor cryptor; + std::vector mappings; + uint64_t last_scanned_version = 0; + uint64_t current_version = 0; + size_t num_decrypted_pages = 0; + size_t num_reclaimed_pages = 0; + size_t progress_index = 0; + std::vector readers; + + SharedFileInfo(const uint8_t* key, FileDesc file_descriptor); +}; +} +} + +#endif // REALM_ENABLE_ENCRYPTION diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/allocation_metrics.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/allocation_metrics.hpp new file mode 100644 index 0000000..5fe327b --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/allocation_metrics.hpp @@ -0,0 +1,310 @@ +#ifndef REALM_UTIL_ALLOCATION_METRICS_HPP +#define REALM_UTIL_ALLOCATION_METRICS_HPP + +#include +#include + +#include + +namespace realm { +namespace util { + +/// Designate a name to be used in heap allocation metrics. +/// +/// An instance can be used with `AllocationMetricsContext::get_metric()` to +/// obtain an instance of `MeteredAllocator` that counts +/// allocations/deallocations towards this name, within that context. +/// +/// Instances of `AllocationMetricName` should be statically allocated. When an +/// instance has been initialized, it must not be destroyed until the program +/// terminates. This is to ensure that iterating over existing names is +/// thread-safe and lock-free. +/// +/// Similarly, when an instance of `AllocationMetricsContext` has been +/// allocated, no further instances of AllocationMetricName must be +/// instantiated. +struct AllocationMetricName { + explicit AllocationMetricName(const char* name) noexcept; + + /// Get the string name. + /// + /// This method is thread-safe. + const char* name() const noexcept; + + /// Get the index of this metric. The index corresponds to an allocator + /// inside the current instance of AllocatorMetricTenant. + /// + /// This method is thread-safe. + size_t index() const noexcept; + + /// Get the next name. The names are returned in no particular order. + /// + /// This method is thread-safe. + const AllocationMetricName* next() const noexcept; + + /// Get the first name in the internal list of names, for the purpose + /// of iterating over all names in the program. + /// + /// This method is thread-safe. + static const AllocationMetricName* get_top() noexcept; + static const AllocationMetricName* find(const char* name) noexcept; + +private: + const char* m_name; + size_t m_index; // Index into `AllocationMetricsContext::m_metrics`. + + // This is used to iterate over all existing components. Instances of + // AllocationMetricName are expected to be statically allocated. + const AllocationMetricName* m_next = nullptr; +}; + + +/// A heap memory allocator that keeps track of how much was +/// allocated/deallocated throughout its lifetime. +/// +/// Memory is allocated with `DefaultAllocator`. +/// +/// All methods on instances of this class are thread-safe. +class MeteredAllocator final : public AllocatorBase { +public: + MeteredAllocator() noexcept; + + static MeteredAllocator& unknown() noexcept; + + /// Return the currently allocated number of bytes. + /// + /// This method is thread-safe, but may temporarily return slightly + /// inaccurate results if allocations/deallocations are happening while it + /// is being called. + std::size_t get_currently_allocated_bytes() const noexcept; + + /// Return the total number of bytes that have been allocated (including + /// allocations that have since been freed). + /// + /// This method is thread-safe. + std::size_t get_total_allocated_bytes() const noexcept; + + /// Return the total number of bytes that have been freed. + /// + /// This method is thread-safe. + std::size_t get_total_deallocated_bytes() const noexcept; + + // AllocatorBase interface: + + /// Return a reference to an MeteredAllocator that belongs to the current + /// AllocationMetricsContext (if any) and the current AllocationMetricNameScope + /// (if any). + /// + /// The returned reference is valid for the duration of the lifetime of the + /// instance of AllocationMetricsContext that is "current" at the time of + /// calling this function, and namely it is valid beyond the lifetime of + /// the current AllocationMetricNameScope. + /// + /// If there is no current AllocationMetricsContext, the global "unknown" + /// tenant will be used. + /// + /// If no metric name is currently in scope (through the use of + /// AllocationMetricNameScope), allocations and deallocations will be counted + /// towards the default "unknown" metric. + /// + /// This method is thread-safe. + static MeteredAllocator& get_default() noexcept; + + /// Allocate memory, accounting for the allocation in metrics. + /// + /// This method is thread-safe. + void* allocate(size_t size, size_t align) override final; + + /// Free memory, accounting for the deallocation in metrics. + /// + /// This method is thread-safe. + void free(void* ptr, size_t size) noexcept override final; + + /// Notify metrics that an allocation happened. + /// + /// This method is thread-safe. + void did_allocate_bytes(std::size_t) noexcept; + + /// Notify metrics that a deallocation happened. + /// + /// This method is thread-safe. + void did_free_bytes(std::size_t) noexcept; + +private: + std::atomic m_allocated_bytes; + // These members are spaced by 64 bytes to prevent false sharing + // (inter-processor CPU locks when multiple processes are modifying them + // concurrently). + char dummy[56]; + std::atomic m_deallocated_bytes; + char dummy2[56]; // Prevent false sharing with the next element. +}; + +/// `AllocationMetricsContext` represents a runtime scope for metrics, such as +/// for instance a server running in a multi-tenant scenario, where each tenant +/// would have one context associated with it. +/// +/// `AllocationMetricsContext` is not available on mobile, due to lack of +/// thread-local storage support on iOS. +struct AllocationMetricsContext { +public: + AllocationMetricsContext(); + ~AllocationMetricsContext(); + +#if !REALM_MOBILE + /// Get the thread-specific AllocationMetricsContext. If none has been set, a + /// reference to a globally-allocated "unknown" tenant will be returned. + static AllocationMetricsContext& get_current() noexcept; +#endif + + /// Get the statically-allocated "unknown" tenant. + static AllocationMetricsContext& get_unknown(); + + MeteredAllocator& get_metric(const AllocationMetricName& name) noexcept; + +private: + std::unique_ptr m_metrics; + + // In debug builds, this is incremented/decremented by + // `AllocationMetricsContextScope`, and checked in the destructor, to avoid + // dangling references. + std::atomic m_refcount; + friend class AllocationMetricsContextScope; +}; + +/// Open a scope where metered memory allocations are counted towards the given +/// name. +/// +/// Creating an instance of this class causes calls to +/// `MeteredAllocator::get_default()` from the current thread to return a +/// reference to an allocator that accounts for allocations/deallocations +/// under the named metric specified as the constructor argument. +/// +/// When such an instance is destroyed, the previous scope will come back +/// in effect (if one exists; if none exists, the "unknown" metric will be +/// used). +/// +/// It is usually an error to create instances of this class with non-scope +/// lifetime, for example on the heap. For that reason, `operator new` is +/// disabled as a precaution. +/// +/// If no `AllocationMetricsContext` is current (by instantiation of +/// `AllocationMetricsContextScope`), metrics recorded in the scope introduced +/// by this instance will count towards the "unknown" context, accessible by +/// calling `AllocationMetricsContext::get_unknown()`. +class AllocationMetricNameScope final { +public: + /// Establish a scope under which all allocations will be tracked as + /// belonging to \a name. + explicit AllocationMetricNameScope(const AllocationMetricName& name) noexcept; + ~AllocationMetricNameScope(); + AllocationMetricNameScope(AllocationMetricNameScope&&) = delete; + AllocationMetricNameScope& operator=(AllocationMetricNameScope&&) = delete; + + void* operator new(std::size_t) = delete; + +private: + const AllocationMetricName& m_name; + const AllocationMetricName* m_previous = nullptr; +}; + +/// Open a scope using the given context for allocation metrics. +/// +/// Creating an instance of this class causes calls to +/// `AllocationMetricsContext::get_current()` to return the provided +/// instance. This function is called when by `MeteredAllocator::get_default()` +/// to return an instance that belongs to the given context. +/// +/// When the instance is destroyed, the previous context will become active, or +/// the "unknown" context if there was none. +/// +/// It is usually an error to create instances of this class with non-scope +/// lifetime, for example on the heap. For that reason, `operator new` is +/// disabled as a precaution. +class AllocationMetricsContextScope final { +public: + explicit AllocationMetricsContextScope(AllocationMetricsContext& context) noexcept; + ~AllocationMetricsContextScope(); + AllocationMetricsContextScope(AllocationMetricsContextScope&&) = delete; + AllocationMetricsContextScope& operator=(AllocationMetricsContextScope&&) = delete; + + void* operator new(std::size_t) = delete; + +private: + AllocationMetricsContext& m_context; + AllocationMetricsContext& m_previous; +}; + + +/// Convenience STL-compatible allocator that counts allocations as part of the +/// current AllocationMetricNameScope. +template +using MeteredSTLAllocator = STLAllocator; + + +// Implementation: + +inline const char* AllocationMetricName::name() const noexcept +{ + return m_name; +} + +inline size_t AllocationMetricName::index() const noexcept +{ + return m_index; +} + +inline const AllocationMetricName* AllocationMetricName::next() const noexcept +{ + return m_next; +} + +inline std::size_t MeteredAllocator::get_currently_allocated_bytes() const noexcept +{ + return get_total_allocated_bytes() - get_total_deallocated_bytes(); +} + +inline std::size_t MeteredAllocator::get_total_allocated_bytes() const noexcept +{ + return m_allocated_bytes.load(std::memory_order_relaxed); +} + +inline std::size_t MeteredAllocator::get_total_deallocated_bytes() const noexcept +{ + return m_deallocated_bytes.load(std::memory_order_relaxed); +} + +inline void* MeteredAllocator::allocate(size_t size, size_t align) +{ + void* ptr = DefaultAllocator::get_default().allocate(size, align); + did_allocate_bytes(size); + return ptr; +} + +inline void MeteredAllocator::free(void* ptr, size_t size) noexcept +{ + DefaultAllocator::get_default().free(ptr, size); + did_free_bytes(size); +} + +inline void MeteredAllocator::did_allocate_bytes(std::size_t size) noexcept +{ +#if !REALM_MOBILE + m_allocated_bytes.fetch_add(size, std::memory_order_relaxed); +#else + static_cast(size); +#endif +} + +inline void MeteredAllocator::did_free_bytes(std::size_t size) noexcept +{ +#if !REALM_MOBILE + m_deallocated_bytes.fetch_add(size, std::memory_order_relaxed); +#else + static_cast(size); +#endif +} +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_ALLOCATION_METRICS_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/allocator.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/allocator.hpp new file mode 100644 index 0000000..6db41a6 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/allocator.hpp @@ -0,0 +1,389 @@ +/************************************************************************* + * + * Copyright 2018 Realm Inc. + * + * 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 REALM_UTIL_ALLOCATOR_HPP +#define REALM_UTIL_ALLOCATOR_HPP + +#include +#include +#include + +namespace realm { +namespace util { + +/// Dynamic heap allocation interface. +/// +/// Implementors may optionally implement a static method `get_default()`, which +/// should return a reference to an allocator instance. This allows +/// `STLAllocator` to be default-constructed. +/// +/// NOTE: This base class is not related to the `realm::Allocator` interface, +/// which is used in the context of allocating memory inside a Realm file. +struct AllocatorBase { + static constexpr std::size_t max_alignment = 16; // FIXME: This is arch-dependent + + /// Allocate \a size bytes at aligned at \a align. + /// + /// May throw `std::bad_alloc` if allocation fails. May **NOT** return + /// an invalid pointer (such as `nullptr`). + virtual void* allocate(std::size_t size, std::size_t align) = 0; + + /// Free the previously allocated block of memory. \a size is not required + /// to be accurate, and is only provided for statistics and debugging + /// purposes. + /// + /// \a ptr may be `nullptr`, in which case this shall be a noop. + virtual void free(void* ptr, size_t size) noexcept = 0; +}; + +/// Implementation of AllocatorBase that uses `operator new`/`operator delete`. +/// +/// Using this allocator with standard containers is zero-overhead: No +/// additional storage is required at any level. +struct DefaultAllocator final : AllocatorBase { + /// Return a reference to a global singleton. + /// + /// This method is thread-safe. + static DefaultAllocator& get_default() noexcept; + + /// Allocate memory (using `operator new`). + /// + /// \a align must not exceed `max_alignment` before C++17. + /// + /// This method is thread-safe. + void* allocate(std::size_t size, std::size_t align) final; + + /// Free memory (using `operator delete`). + /// + /// If \a ptr equals `nullptr`, this is a no-op. + /// + /// This method is thread-safe. + void free(void* ptr, std::size_t size) noexcept final; + +private: + static DefaultAllocator g_instance; + DefaultAllocator() {} +}; + +template +struct STLDeleter; + +namespace detail { +/// Base class for things that hold a reference to an allocator. The default +/// implementation carries a pointer to the allocator instance. Singleton +/// allocators (such as `DefaultAllocator`) may specialize this class such that +/// no extra storage is needed. +template +struct GetAllocator { + // Note: Some allocators may not define get_default(). This is OK, and + // this constructor will not be instantiated (SFINAE). + GetAllocator() noexcept + : m_allocator(&Allocator::get_default()) + { + } + + template + GetAllocator(A& allocator) noexcept + : m_allocator(&allocator) + { + } + + template + GetAllocator& operator=(const GetAllocator& other) noexcept + { + m_allocator = &other.get_allocator(); + return *this; + } + + Allocator& get_allocator() const noexcept + { + return *m_allocator; + } + + bool operator==(const GetAllocator& other) const noexcept + { + return m_allocator == other.m_allocator; + } + + bool operator!=(const GetAllocator& other) const noexcept + { + return m_allocator != other.m_allocator; + } + + Allocator* m_allocator; +}; + +/// Specialization for `DefaultAllocator` that has zero size, i.e. no extra +/// storage requirements compared with `std::allocator`. +template <> +struct GetAllocator { + GetAllocator() noexcept {} + + GetAllocator(DefaultAllocator&) noexcept {} + + DefaultAllocator& get_allocator() const noexcept + { + return DefaultAllocator::get_default(); + } + + bool operator==(const GetAllocator&) const noexcept + { + return true; + } + + bool operator!=(const GetAllocator&) const noexcept + { + return false; + } +}; +} // namespace detail + +/// STL-compatible static dispatch bridge to a dynamic implementation of +/// `AllocatorBase`. Wraps a pointer to an object that adheres to the +/// `AllocatorBase` interface. It is optional whether the `Allocator` class +/// template argument actually derives from `AllocatorBase`. +/// +/// The intention is that users of this class can set `Allocator` to the +/// nearest-known base class of the expected allocator implementations, such +/// that appropriate devirtualization can take place. +template +struct STLAllocator : detail::GetAllocator { + using value_type = T; + using Deleter = STLDeleter; + + // These typedefs are optional, but GCC 4.9 requires them when using the + // allocator together with std::map, std::basic_string, etc. + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using reference = T&; + using const_reference = const T&; + using pointer = T*; + using const_pointer = const T*; + + /// The default constructor is only availble when the static method + /// `Allocator::get_default()` exists. + STLAllocator() noexcept {} + + constexpr STLAllocator(Allocator& base) noexcept + : detail::GetAllocator(base) + { + } + template + constexpr STLAllocator(const STLAllocator& other) noexcept + : detail::GetAllocator(other.get_allocator()) + { + } + + STLAllocator& operator=(const STLAllocator& other) noexcept = default; + + T* allocate(std::size_t n) + { + static_assert(alignof(T) <= Allocator::max_alignment, "Over-aligned allocation"); + void* ptr = this->get_allocator().allocate(sizeof(T) * n, alignof(T)); + return static_cast(ptr); + } + + void deallocate(T* ptr, std::size_t n) noexcept + { + this->get_allocator().free(ptr, sizeof(T) * n); + } + + operator Allocator&() const + { + return this->get_allocator(); + } + + template + struct rebind { + using other = STLAllocator; + }; + + // construct() and destroy() are optional, but are required by some + // containers under GCC 4.9 (verified for at least std::list). + template + void construct(T* ptr, Args&&... args) + { + ::new (ptr) T(std::forward(args)...); + } + + template + void destroy(U* ptr) + { + ptr->~U(); + } + +private: + template + friend struct STLAllocator; +}; + +template +struct STLDeleter : detail::GetAllocator { + // The reason for this member is to accurately pass `size` to `free()` when + // deallocating. `sizeof(T)` may not be good enough, because the pointer may + // have been cast to a relative type of different size. + size_t m_size; + + explicit STLDeleter(Allocator& allocator) noexcept + : STLDeleter(0, allocator) + { + } + explicit STLDeleter(size_t size, Allocator& allocator) noexcept + : detail::GetAllocator(allocator) + , m_size(size) + { + } + + template + STLDeleter(const STLDeleter& other) noexcept + : detail::GetAllocator(other.get_allocator()) + , m_size(other.m_size) + { + } + + void operator()(T* ptr) + { + ptr->~T(); + this->get_allocator().free(ptr, m_size); + } +}; + +template +struct STLDeleter : detail::GetAllocator { + // Note: Array-allocated pointers cannot be upcast to base classes, because + // of array slicing. + size_t m_count; + explicit STLDeleter(Allocator& allocator) noexcept + : STLDeleter(0, allocator) + { + } + explicit STLDeleter(size_t count, Allocator& allocator) noexcept + : detail::GetAllocator(allocator) + , m_count(count) + { + } + + template + STLDeleter(const STLDeleter& other) noexcept + : detail::GetAllocator(other.get_allocator()) + , m_count(other.m_count) + { + } + + template + STLDeleter& operator=(const STLDeleter& other) noexcept + { + static_cast&>(*this) = static_cast&>(other); + m_count = other.m_count; + return *this; + } + + void operator()(T* ptr) + { + for (size_t i = 0; i < m_count; ++i) { + ptr[i].~T(); + } + this->get_allocator().free(ptr, m_count * sizeof(T)); + } +}; + +/// make_unique with custom allocator (non-array version) +template +auto make_unique(Allocator& allocator, Args&&... args) + -> std::enable_if_t::value, std::unique_ptr>> +{ + void* memory = allocator.allocate(sizeof(T), alignof(T)); // Throws + T* ptr; + try { + ptr = new (memory) T(std::forward(args)...); // Throws + } + catch (...) { + allocator.free(memory, sizeof(T)); + throw; + } + std::unique_ptr> result{ptr, STLDeleter{sizeof(T), allocator}}; + return result; +} + +/// make_unique with custom allocator supporting `get_default()` +/// (non-array-version) +template +auto make_unique(Args&&... args) + -> std::enable_if_t::value, std::unique_ptr>> +{ + return make_unique(Allocator::get_default(), std::forward(args)...); +} + +/// make_unique with custom allocator (array version) +template +auto make_unique(Allocator& allocator, size_t count) + -> std::enable_if_t::value, std::unique_ptr>> +{ + using T = std::remove_extent_t; + void* memory = allocator.allocate(sizeof(T) * count, alignof(T)); // Throws + T* ptr = reinterpret_cast(memory); + size_t constructed = 0; + try { + // FIXME: Can't use array placement new, because MSVC has a buggy + // implementation of it. :-( + while (constructed < count) { + new (&ptr[constructed]) T; // Throws + ++constructed; + } + } + catch (...) { + for (size_t i = 0; i < constructed; ++i) { + ptr[i].~T(); + } + allocator.free(memory, sizeof(T) * count); + throw; + } + std::unique_ptr> result{ptr, STLDeleter{count, allocator}}; + return result; +} + +/// make_unique with custom allocator supporting `get_default()` (array version) +template +auto make_unique(size_t count) + -> std::enable_if_t::value, std::unique_ptr>> +{ + return make_unique(Allocator::get_default(), count); +} + + +// Implementation: + +inline DefaultAllocator& DefaultAllocator::get_default() noexcept +{ + return g_instance; +} + +inline void* DefaultAllocator::allocate(std::size_t size, std::size_t) +{ + return new char[size]; +} + +inline void DefaultAllocator::free(void* ptr, std::size_t) noexcept +{ + delete[] static_cast(ptr); +} + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_ALLOCATOR_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/any.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/any.hpp new file mode 100644 index 0000000..5ac72b2 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/any.hpp @@ -0,0 +1,165 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2017 Realm Inc. +// +// 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 REALM_UTIL_ANY_HPP +#define REALM_UTIL_ANY_HPP + +#include +#include +#include +#include + +#include + +namespace realm { +namespace util { + +using bad_cast = ExceptionWithBacktrace; + +// A naive implementation of C++17's std::any +// This does not perform the small-object optimization or make any particular +// attempt at being performant +class Any final { +public: + // Constructors + + Any() = default; + Any(Any&&) noexcept = default; + ~Any() = default; + Any& operator=(Any&&) noexcept = default; + + Any(Any const& rhs) + : m_value(rhs.m_value ? rhs.m_value->copy() : nullptr) + { + } + + template::type, Any>::value>::type> + Any(T&& value) + : m_value(std::make_unique::type>>(std::forward(value))) + { + } + + Any& operator=(Any const& rhs) + { + m_value = rhs.m_value ? rhs.m_value->copy() : nullptr; + return *this; + } + + template::type, Any>::value>::type> + Any& operator=(T&& value) + { + m_value = std::make_unique::type>>(std::forward(value)); + return *this; + } + + // Modifiers + + void reset() noexcept { m_value.reset(); } + void swap(Any& rhs) noexcept { std::swap(m_value, rhs.m_value); } + + // Observers + + bool has_value() const noexcept { return m_value != nullptr; } + std::type_info const& type() const noexcept { return m_value ? m_value->type() : typeid(void); } + +private: + struct ValueBase { + virtual ~ValueBase() noexcept { } + virtual std::type_info const& type() const noexcept = 0; + virtual std::unique_ptr copy() const = 0; + }; + template + struct Value : ValueBase { + T value; + template Value(U&& v) : value(std::forward(v)) { } + + std::type_info const& type() const noexcept override { return typeid(T); } + std::unique_ptr copy() const override + { + return std::make_unique>(value); + } + }; + std::unique_ptr m_value; + + template + friend const T* any_cast(const Any* operand) noexcept; + template + friend T* any_cast(Any* operand) noexcept; + + template + const T* cast() const noexcept + { + return &static_cast*>(m_value.get())->value; + } + + template + T* cast() noexcept + { + return &static_cast*>(m_value.get())->value; + } +}; + +template +T any_cast(Any const& value) +{ + auto ptr = any_cast::type>::type>(&value); + if (!ptr) + throw bad_cast(); + return *ptr; +} + +template +T any_cast(Any& value) +{ + auto ptr = any_cast::type>(&value); + if (!ptr) + throw bad_cast(); + return *ptr; +} + +template +T any_cast(Any&& value) +{ + auto ptr = any_cast::type>(&value); + if (!ptr) + throw bad_cast(); + return std::move(*ptr); +} + +template +T* any_cast(Any* value) noexcept +{ + return value && value->type() == typeid(T) ? value->cast() : nullptr; +} + +template +const T* any_cast(const Any* value) noexcept +{ + return value && value->type() == typeid(T) ? value->cast() : nullptr; +} +} // namespace util +} // namespace realm + +namespace std { +inline void swap(realm::util::Any& lhs, realm::util::Any& rhs) noexcept +{ + lhs.swap(rhs); +} +} // namespace std + +#endif // REALM_UTIL_ANY_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/assert.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/assert.hpp new file mode 100644 index 0000000..5e75066 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/assert.hpp @@ -0,0 +1,107 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_UTIL_ASSERT_HPP +#define REALM_UTIL_ASSERT_HPP + +#include +#include + +#if REALM_ENABLE_ASSERTIONS || defined(REALM_DEBUG) +#define REALM_ASSERTIONS_ENABLED 1 +#else +#define REALM_ASSERTIONS_ENABLED 0 +#endif + +#define REALM_ASSERT_RELEASE(condition) \ + (REALM_LIKELY(condition) ? static_cast(0) \ + : realm::util::terminate("Assertion failed: " #condition, __FILE__, __LINE__)) + +#if REALM_ASSERTIONS_ENABLED +#define REALM_ASSERT(condition) REALM_ASSERT_RELEASE(condition) +#else +#define REALM_ASSERT(condition) static_cast(sizeof bool(condition)) +#endif + +#ifdef REALM_DEBUG +#define REALM_ASSERT_DEBUG(condition) REALM_ASSERT_RELEASE(condition) +#else +#define REALM_ASSERT_DEBUG(condition) static_cast(sizeof bool(condition)) +#endif + +#define REALM_STRINGIFY(X) #X + +#define REALM_ASSERT_RELEASE_EX(condition, ...) \ + (REALM_LIKELY(condition) ? static_cast(0) \ + : realm::util::terminate_with_info("Assertion failed: " #condition, __LINE__, __FILE__, \ + REALM_STRINGIFY((__VA_ARGS__)), __VA_ARGS__)) + +#ifdef REALM_DEBUG +#define REALM_ASSERT_DEBUG_EX REALM_ASSERT_RELEASE_EX +#else +#define REALM_ASSERT_DEBUG_EX(condition, ...) static_cast(sizeof bool(condition)) +#endif + +// Becase the assert is used in noexcept methods, it's a bad idea to allocate +// buffer space for the message so therefore we must pass it to terminate which +// will 'cerr' it for us without needing any buffer +#if REALM_ENABLE_ASSERTIONS || defined(REALM_DEBUG) + +#define REALM_ASSERT_EX REALM_ASSERT_RELEASE_EX + +#define REALM_ASSERT_3(left, cmp, right) \ + (REALM_LIKELY((left)cmp(right)) ? static_cast(0) \ + : realm::util::terminate("Assertion failed: " \ + "" #left " " #cmp " " #right, \ + __FILE__, __LINE__, left, right)) + +#define REALM_ASSERT_7(left1, cmp1, right1, logical, left2, cmp2, right2) \ + (REALM_LIKELY(((left1)cmp1(right1))logical((left2)cmp2(right2))) \ + ? static_cast(0) \ + : realm::util::terminate("Assertion failed: " \ + "" #left1 " " #cmp1 " " #right1 " " #logical " " \ + "" #left2 " " #cmp2 " " #right2, \ + __FILE__, __LINE__, left1, right1, left2, right2)) + +#define REALM_ASSERT_11(left1, cmp1, right1, logical1, left2, cmp2, right2, logical2, left3, cmp3, right3) \ + (REALM_LIKELY(((left1)cmp1(right1))logical1((left2)cmp2(right2)) logical2((left3)cmp3(right3))) \ + ? static_cast(0) \ + : realm::util::terminate("Assertion failed: " \ + "" #left1 " " #cmp1 " " #right1 " " #logical1 " " \ + "" #left2 " " #cmp2 " " #right2 " " #logical2 " " \ + "" #left3 " " #cmp3 " " #right3, \ + __FILE__, __LINE__, left1, right1, left2, right2, left3, right3)) +#else +#define REALM_ASSERT_EX(condition, ...) static_cast(sizeof bool(condition)) +#define REALM_ASSERT_3(left, cmp, right) static_cast(sizeof bool((left)cmp(right))) +#define REALM_ASSERT_7(left1, cmp1, right1, logical, left2, cmp2, right2) \ + static_cast(sizeof bool(((left1)cmp1(right1))logical((left2)cmp2(right2)))) +#define REALM_ASSERT_11(left1, cmp1, right1, logical1, left2, cmp2, right2, logical2, left3, cmp3, right3) \ + static_cast(sizeof bool(((left1)cmp1(right1))logical1((left2)cmp2(right2)) logical2((left3)cmp3(right3)))) +#endif + +#define REALM_UNREACHABLE() realm::util::terminate("Unreachable code", __FILE__, __LINE__) +#ifdef REALM_COVER +#define REALM_COVER_NEVER(x) false +#define REALM_COVER_ALWAYS(x) true +#else +#define REALM_COVER_NEVER(x) (x) +#define REALM_COVER_ALWAYS(x) (x) +#endif + +#endif // REALM_UTIL_ASSERT_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/backtrace.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/backtrace.hpp new file mode 100644 index 0000000..8011023 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/backtrace.hpp @@ -0,0 +1,226 @@ +/************************************************************************* + * + * Copyright 2018 Realm Inc. + * + * 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 REALM_UTIL_BACKTRACE_HPP +#define REALM_UTIL_BACKTRACE_HPP + +#include +#include +#include + +namespace realm { +namespace util { + +/// Backtrace encapsulates a stack trace, usually as captured by `backtrace()` +/// and `backtrace_symbols()` (or platform-specific equivalents). +struct Backtrace { + /// Capture a symbolicated stack trace, excluding the call to `capture()` + /// itself. If any error occurs while capturing the stack trace or + /// translating symbol names, a `Backtrace` object is returned containing a + /// single line describing the error. + /// + /// This function only allocates memory as part of calling + /// `backtrace_symbols()` (or the current platform's equivalent). + static Backtrace capture() noexcept; + + /// Print the backtrace to the stream. Each line is separated by a newline. + /// The format of the output is unspecified. + void print(std::ostream&) const; + + /// Construct an empty stack trace. + Backtrace() noexcept + { + } + + /// Move constructor. This operation cannot fail. + Backtrace(Backtrace&&) noexcept; + + /// Copy constructor. See the copy assignment operator. + Backtrace(const Backtrace&) noexcept; + + ~Backtrace(); + + /// Move assignment operator. This operation cannot fail. + Backtrace& operator=(Backtrace&&) noexcept; + + /// Copy assignment operator. Copying a `Backtrace` object may result in a + /// memory allocation. If such an allocation fails, the backtrace is + /// replaced with a single line describing the error. + Backtrace& operator=(const Backtrace&) noexcept; + +private: + Backtrace(void* memory, const char* const* strs, size_t len) + : m_memory(memory) + , m_strs(strs) + , m_len(len) + { + } + Backtrace(void* memory, size_t len) + : m_memory(memory) + , m_strs(static_cast(memory)) + , m_len(len) + { + } + + // m_memory is a pointer to the memory block returned by + // `backtrace_symbols()`. It is usually equal to `m_strs`, except in the + // case where an error has occurred and `m_strs` points to statically + // allocated memory describing the error. + // + // When `m_memory` is non-null, the memory is owned by this object. + void* m_memory = nullptr; + + // A pointer to a list of string pointers describing the stack trace (same + // format as returned by `backtrace_symbols()`). + const char* const* m_strs = nullptr; + + // Number of entries in this stack trace. + size_t m_len = 0; +}; + +namespace detail { + +class ExceptionWithBacktraceBase { +public: + ExceptionWithBacktraceBase() + : m_backtrace(util::Backtrace::capture()) + { + } + const util::Backtrace& backtrace() const noexcept + { + return m_backtrace; + } + virtual const char* message() const noexcept = 0; + +protected: + util::Backtrace m_backtrace; + // Cannot use Optional here, because Optional wants to use + // ExceptionWithBacktrace. + mutable bool m_has_materialized_message = false; + mutable std::string m_materialized_message; + + // Render the message and the backtrace into m_message_with_backtrace. If an + // exception is thrown while rendering the message, the message without the + // backtrace will be returned. + const char* materialize_message() const noexcept; +}; + +} // namespace detail + +/// Base class for exceptions that record a stack trace of where they were +/// thrown. +/// +/// The template argument is expected to be an exception type conforming to the +/// standard library exception API (`std::exception` and friends). +/// +/// It is possible to opt in to exception backtraces in two ways, (a) as part of +/// the exception type, in which case the backtrace will always be included for +/// all exceptions of that type, or (b) at the call-site of an opaque exception +/// type, in which case it is up to the throw-site to decide whether a backtrace +/// should be included. +/// +/// Example (a): +/// ``` +/// class MyException : ExceptionWithBacktrace { +/// public: +/// const char* message() const noexcept override +/// { +/// return "MyException error message"; +/// } +/// }; +/// +/// ... +/// +/// try { +/// throw MyException{}; +/// } +/// catch (const MyException& ex) { +/// // Print the backtrace without the message: +/// std::cerr << ex.backtrace() << "\n"; +/// // Print the exception message and the backtrace: +/// std::cerr << ex.what() << "\n"; +/// // Print the exception message without the backtrace: +/// std::cerr << ex.message() << "\n"; +/// } +/// ``` +/// +/// Example (b): +/// ``` +/// class MyException : std::exception { +/// public: +/// const char* what() const noexcept override +/// { +/// return "MyException error message"; +/// } +/// }; +/// +/// ... +/// +/// try { +/// throw ExceptionWithBacktrace{}; +/// } +/// catch (const MyException& ex) { +/// // Print the exception message and the backtrace: +/// std::cerr << ex.what() << "\n"; +/// } +/// ``` +template +class ExceptionWithBacktrace : public Base, public detail::ExceptionWithBacktraceBase { +public: + template + inline ExceptionWithBacktrace(Args&&... args) + : Base(std::forward(args)...) + , detail::ExceptionWithBacktraceBase() // backtrace captured here + { + } + + /// Return the message of the exception, including the backtrace of where + /// the exception was thrown. + const char* what() const noexcept final + { + return materialize_message(); + } + + /// Return the message of the exception without the backtrace. The default + /// implementation calls `Base::what()`. + const char* message() const noexcept override + { + return Base::what(); + } +}; + +// Wrappers for standard exception types with backtrace support +using runtime_error = ExceptionWithBacktrace; +using range_error = ExceptionWithBacktrace; +using overflow_error = ExceptionWithBacktrace; +using underflow_error = ExceptionWithBacktrace; +using bad_alloc = ExceptionWithBacktrace; +using invalid_argument = ExceptionWithBacktrace; +using out_of_range = ExceptionWithBacktrace; +using logic_error = ExceptionWithBacktrace; + +} // namespace util +} // namespace realm + +inline std::ostream& operator<<(std::ostream& os, const realm::util::Backtrace& bt) +{ + bt.print(os); + return os; +} + +#endif // REALM_UTIL_BACKTRACE_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/base64.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/base64.hpp new file mode 100644 index 0000000..b08eb5f --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/base64.hpp @@ -0,0 +1,79 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_UTIL_BASE64_HPP +#define REALM_UTIL_BASE64_HPP + +#include +#include +#include + +namespace realm { +namespace util { + + +/// base64_encode() encodes the bnary data in \param in_buffer of size \param in_buffer_size . +/// The encoded data is placed in \param out_buffer . The size of \param \out_buffer is passed in +/// \param out_buffer_size . The output buffer out_buffer must be +/// large enough to hold the base64 encoded data. The size can be obtained from the function +/// base64_encoded_size. out_buffer_size is only used to assert that the output buffer is +/// large enough. +size_t base64_encode(const char *in_buffer, size_t in_buffer_size, char* out_buffer, size_t out_buffer_size) noexcept; + +/// base64_encoded_size() returns the exact size of the base64 encoded +/// data as a function of the size of the input data. +inline size_t base64_encoded_size(size_t in_buffer_size) noexcept +{ + return 4 * ((in_buffer_size + 2) / 3); +} + + +/// Decode base64-encoded string in input, and places the result in out_buffer. +/// The length of the out_buffer must be at least 3 * input.size() / 4. +/// +/// The input must be padded base64 (i.e. the number of non-whitespace +/// characters in the input must be a multiple of 4). Whitespace (spaces, tabs, +/// newlines) is ignored. +/// +/// The algorithm stops when the first character not in the base64 character +/// set is encountered, or when the end of the input is reached. +/// +/// \returns the number of successfully decoded bytes written to out_buffer, or +/// none if the whole input was not valid base64. +Optional base64_decode(StringData input, char* out_buffer, size_t out_buffer_len) noexcept; + +/// Return an upper bound on the decoded size of a Base64-encoded data +/// stream of length \a base64_size. The returned value is suitable for +/// allocation of buffers containing decoded data. +inline size_t base64_decoded_size(size_t base64_size) noexcept +{ + return (base64_size * 3 + 3) / 4; +} + + + +/// base64_decode_to_vector() is a convenience function that decodes \param +/// encoded and returns the result in a std::vector with the correct size. +/// This function returns none if the input is invalid. +Optional> base64_decode_to_vector(StringData encoded); + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_BASE64_HPP + diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/basic_system_errors.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/basic_system_errors.hpp new file mode 100644 index 0000000..8f7a626 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/basic_system_errors.hpp @@ -0,0 +1,89 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_UTIL_BASIC_SYSTEM_ERRORS_HPP +#define REALM_UTIL_BASIC_SYSTEM_ERRORS_HPP + +#include +#include + + +namespace realm { +namespace util { +namespace error { + +enum basic_system_errors { + /// Address family not supported by protocol. + address_family_not_supported = EAFNOSUPPORT, + + /// Invalid argument. + invalid_argument = EINVAL, + + /// Cannot allocate memory. + no_memory = ENOMEM, + + /// Operation cancelled. + operation_aborted = ECANCELED, + + /// Connection aborted. + connection_aborted = ECONNABORTED, + + /// Connection reset by peer + connection_reset = ECONNRESET, + + /// Broken pipe + broken_pipe = EPIPE, + + /// Resource temporarily unavailable + resource_unavailable_try_again = EAGAIN, +}; + +std::error_code make_error_code(basic_system_errors) noexcept; + +} // namespace error +} // namespace util +} // namespace realm + +namespace std { + +template <> +class is_error_code_enum { +public: + static const bool value = true; +}; + +} // namespace std + +namespace realm { +namespace util { + +std::error_code make_basic_system_error_code(int) noexcept; + + +// implementation + +inline std::error_code make_basic_system_error_code(int err) noexcept +{ + using namespace error; + return make_error_code(basic_system_errors(err)); +} + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_BASIC_SYSTEM_ERRORS_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/bind_ptr.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/bind_ptr.hpp new file mode 100644 index 0000000..e5b8a99 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/bind_ptr.hpp @@ -0,0 +1,484 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_UTIL_BIND_PTR_HPP +#define REALM_UTIL_BIND_PTR_HPP + +#include +#include +#include +#include + +#include +#include + + +namespace realm { +namespace util { + +class bind_ptr_base { +public: + struct adopt_tag { + }; +}; + + +/// A generic intrusive smart pointer that binds itself explicitely to +/// the target object. +/// +/// This class is agnostic towards what 'binding' means for the target +/// object, but a common use is 'reference counting'. See RefCountBase +/// for an example of that. +/// +/// This smart pointer implementation assumes that the target object +/// destructor never throws. +template +class bind_ptr : public bind_ptr_base { +public: + constexpr bind_ptr() noexcept + : m_ptr(nullptr) + { + } + ~bind_ptr() noexcept + { + unbind(); + } + + explicit bind_ptr(T* p) noexcept + { + bind(p); + } + template + explicit bind_ptr(U* p) noexcept + { + bind(p); + } + + bind_ptr(T* p, adopt_tag) noexcept + { + m_ptr = p; + } + template + bind_ptr(U* p, adopt_tag) noexcept + { + m_ptr = p; + } + + // Copy construct + bind_ptr(const bind_ptr& p) noexcept + { + bind(p.m_ptr); + } + template + bind_ptr(const bind_ptr& p) noexcept + { + bind(p.m_ptr); + } + + // Copy assign + bind_ptr& operator=(const bind_ptr& p) noexcept + { + bind_ptr(p).swap(*this); + return *this; + } + template + bind_ptr& operator=(const bind_ptr& p) noexcept + { + bind_ptr(p).swap(*this); + return *this; + } + + // Move construct + bind_ptr(bind_ptr&& p) noexcept + : m_ptr(p.release()) + { + } + template + bind_ptr(bind_ptr&& p) noexcept + : m_ptr(p.release()) + { + } + + // Move assign + bind_ptr& operator=(bind_ptr&& p) noexcept + { + bind_ptr(std::move(p)).swap(*this); + return *this; + } + template + bind_ptr& operator=(bind_ptr&& p) noexcept + { + bind_ptr(std::move(p)).swap(*this); + return *this; + } + + //@{ + // Comparison + template + bool operator==(const bind_ptr&) const noexcept; + + template + bool operator==(U*) const noexcept; + + template + bool operator!=(const bind_ptr&) const noexcept; + + template + bool operator!=(U*) const noexcept; + + template + bool operator<(const bind_ptr&) const noexcept; + + template + bool operator<(U*) const noexcept; + + template + bool operator>(const bind_ptr&) const noexcept; + + template + bool operator>(U*) const noexcept; + + template + bool operator<=(const bind_ptr&) const noexcept; + + template + bool operator<=(U*) const noexcept; + + template + bool operator>=(const bind_ptr&) const noexcept; + + template + bool operator>=(U*) const noexcept; + //@} + + // Dereference + T& operator*() const noexcept + { + return *m_ptr; + } + T* operator->() const noexcept + { + return m_ptr; + } + + explicit operator bool() const noexcept + { + return m_ptr != 0; + } + + T* get() const noexcept + { + return m_ptr; + } + void reset() noexcept + { + bind_ptr().swap(*this); + } + void reset(T* p) noexcept + { + bind_ptr(p).swap(*this); + } + template + void reset(U* p) noexcept + { + bind_ptr(p).swap(*this); + } + + T* release() noexcept + { + T* const p = m_ptr; + m_ptr = nullptr; + return p; + } + + void swap(bind_ptr& p) noexcept + { + std::swap(m_ptr, p.m_ptr); + } + friend void swap(bind_ptr& a, bind_ptr& b) noexcept + { + a.swap(b); + } + +protected: + struct casting_move_tag { + }; + template + bind_ptr(bind_ptr* p, casting_move_tag) noexcept + : m_ptr(static_cast(p->release())) + { + } + +private: + T* m_ptr; + + void bind(T* p) noexcept + { + if (p) + p->bind_ptr(); + m_ptr = p; + } + void unbind() noexcept + { + if (m_ptr) + m_ptr->unbind_ptr(); + } + + template + friend class bind_ptr; +}; + + +template +inline std::basic_ostream& operator<<(std::basic_ostream& out, const bind_ptr& p) +{ + out << static_cast(p.get()); + return out; +} + + +//@{ +// Comparison +template +bool operator==(T*, const bind_ptr&) noexcept; +template +bool operator!=(T*, const bind_ptr&) noexcept; +template +bool operator<(T*, const bind_ptr&) noexcept; +template +bool operator>(T*, const bind_ptr&) noexcept; +template +bool operator<=(T*, const bind_ptr&) noexcept; +template +bool operator>=(T*, const bind_ptr&) noexcept; +//@} + + +/// Polymorphic convenience base class for reference counting objects. +/// +/// Together with bind_ptr, this class delivers simple instrusive +/// reference counting. +/// +/// \sa bind_ptr +class RefCountBase { +public: + RefCountBase() noexcept + : m_ref_count(0) + { + } + virtual ~RefCountBase() noexcept + { + REALM_ASSERT(m_ref_count == 0); + } + + RefCountBase(const RefCountBase&) = delete; + RefCountBase(RefCountBase&&) = delete; + + void operator=(const RefCountBase&) = delete; + void operator=(RefCountBase&&) = delete; + +protected: + void bind_ptr() const noexcept + { + ++m_ref_count; + } + void unbind_ptr() const noexcept + { + if (--m_ref_count == 0) + delete this; + } + +private: + mutable unsigned long m_ref_count; + + template + friend class bind_ptr; +}; + + +/// Same as RefCountBase, but this one makes the copying of, and the +/// destruction of counted references thread-safe. +/// +/// \sa RefCountBase +/// \sa bind_ptr +class AtomicRefCountBase { +public: + AtomicRefCountBase() noexcept + : m_ref_count(0) + { + } + virtual ~AtomicRefCountBase() noexcept + { + REALM_ASSERT(m_ref_count == 0); + } + + AtomicRefCountBase(const AtomicRefCountBase&) = delete; + AtomicRefCountBase(AtomicRefCountBase&&) = delete; + + void operator=(const AtomicRefCountBase&) = delete; + void operator=(AtomicRefCountBase&&) = delete; + +protected: + // FIXME: Operators ++ and -- as used below use + // std::memory_order_seq_cst. This can be optimized. + void bind_ptr() const noexcept + { + ++m_ref_count; + } + void unbind_ptr() const noexcept + { + if (--m_ref_count == 0) { + delete this; + } + } + +private: + mutable std::atomic m_ref_count; + + template + friend class bind_ptr; +}; + + +// Implementation: + +template +template +bool bind_ptr::operator==(const bind_ptr& p) const noexcept +{ + return m_ptr == p.m_ptr; +} + +template +template +bool bind_ptr::operator==(U* p) const noexcept +{ + return m_ptr == p; +} + +template +template +bool bind_ptr::operator!=(const bind_ptr& p) const noexcept +{ + return m_ptr != p.m_ptr; +} + +template +template +bool bind_ptr::operator!=(U* p) const noexcept +{ + return m_ptr != p; +} + +template +template +bool bind_ptr::operator<(const bind_ptr& p) const noexcept +{ + return m_ptr < p.m_ptr; +} + +template +template +bool bind_ptr::operator<(U* p) const noexcept +{ + return m_ptr < p; +} + +template +template +bool bind_ptr::operator>(const bind_ptr& p) const noexcept +{ + return m_ptr > p.m_ptr; +} + +template +template +bool bind_ptr::operator>(U* p) const noexcept +{ + return m_ptr > p; +} + +template +template +bool bind_ptr::operator<=(const bind_ptr& p) const noexcept +{ + return m_ptr <= p.m_ptr; +} + +template +template +bool bind_ptr::operator<=(U* p) const noexcept +{ + return m_ptr <= p; +} + +template +template +bool bind_ptr::operator>=(const bind_ptr& p) const noexcept +{ + return m_ptr >= p.m_ptr; +} + +template +template +bool bind_ptr::operator>=(U* p) const noexcept +{ + return m_ptr >= p; +} + +template +bool operator==(T* a, const bind_ptr& b) noexcept +{ + return b == a; +} + +template +bool operator!=(T* a, const bind_ptr& b) noexcept +{ + return b != a; +} + +template +bool operator<(T* a, const bind_ptr& b) noexcept +{ + return b > a; +} + +template +bool operator>(T* a, const bind_ptr& b) noexcept +{ + return b < a; +} + +template +bool operator<=(T* a, const bind_ptr& b) noexcept +{ + return b >= a; +} + +template +bool operator>=(T* a, const bind_ptr& b) noexcept +{ + return b <= a; +} + + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_BIND_PTR_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/buffer.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/buffer.hpp new file mode 100644 index 0000000..2a2bf94 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/buffer.hpp @@ -0,0 +1,302 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_UTIL_BUFFER_HPP +#define REALM_UTIL_BUFFER_HPP + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace realm { +namespace util { + + +/// A simple buffer concept that owns a region of memory and knows its +/// size. +template +class Buffer { +public: + Buffer(Allocator& alloc = Allocator::get_default()) noexcept + : m_data(nullptr, STLDeleter{alloc}) + , m_size(0) + { + } + explicit Buffer(size_t initial_size, Allocator& alloc = Allocator::get_default()); + Buffer(Buffer&&) noexcept = default; + Buffer& operator=(Buffer&&) noexcept = default; + + T& operator[](size_t i) noexcept + { + return m_data[i]; + } + const T& operator[](size_t i) const noexcept + { + return m_data[i]; + } + + T* data() noexcept + { + return m_data.get(); + } + const T* data() const noexcept + { + return m_data.get(); + } + size_t size() const noexcept + { + return m_size; + } + + /// False iff the data() returns null. + explicit operator bool() const noexcept + { + return bool(m_data); + } + + /// Discards the original contents. + void set_size(size_t new_size); + + /// \param new_size Specifies the new buffer size. + /// \param copy_begin copy_end Specifies a range of element + /// values to be retained. \a copy_end must be less than, or equal + /// to size(). + /// + /// \param copy_to Specifies where the retained range should be + /// copied to. `\a copy_to + \a copy_end - \a copy_begin` must be + /// less than, or equal to \a new_size. + void resize(size_t new_size, size_t copy_begin, size_t copy_end, size_t copy_to); + + void reserve(size_t used_size, size_t min_capacity); + + void reserve_extra(size_t used_size, size_t min_extra_capacity); + + /// Release the internal buffer to the caller. + REALM_NODISCARD std::unique_ptr> release() noexcept; + + friend void swap(Buffer& a, Buffer& b) noexcept + { + using std::swap; + swap(a.m_data, b.m_data); + swap(a.m_size, b.m_size); + } + + Allocator& get_allocator() const noexcept + { + return m_data.get_deleter().get_allocator(); + } + +private: + std::unique_ptr> m_data; + size_t m_size; +}; + + +/// A buffer that can be efficiently resized. It acheives this by +/// using an underlying buffer that may be larger than the logical +/// size, and is automatically expanded in progressively larger steps. +template +class AppendBuffer { +public: + AppendBuffer(Allocator& alloc = Allocator::get_default()) noexcept; + AppendBuffer(AppendBuffer&&) noexcept = default; + AppendBuffer& operator=(AppendBuffer&&) noexcept = default; + + /// Returns the current size of the buffer. + size_t size() const noexcept; + + /// Gives read and write access to the elements. + T* data() noexcept; + + /// Gives read access the elements. + const T* data() const noexcept; + + /// Append the specified elements. This increases the size of this + /// buffer by \a append_data_size. If the caller has previously requested + /// a minimum capacity that is greater than, or equal to the + /// resulting size, this function is guaranteed to not throw. + void append(const T* append_data, size_t append_data_size); + + /// If the specified size is less than the current size, then the + /// buffer contents is truncated accordingly. If the specified + /// size is greater than the current size, then the extra elements + /// will have undefined values. If the caller has previously + /// requested a minimum capacity that is greater than, or equal to + /// the specified size, this function is guaranteed to not throw. + void resize(size_t new_size); + + /// This operation does not change the size of the buffer as + /// returned by size(). If the specified capacity is less than the + /// current capacity, this operation has no effect. + void reserve(size_t min_capacity); + + /// Set the size to zero. The capacity remains unchanged. + void clear() noexcept; + + /// Release the underlying buffer and reset the size. Note: The returned + /// buffer may be larger than the amount of data appended to this buffer. + /// Callers should call `size()` prior to releasing the buffer to know the + /// usable/logical size. + REALM_NODISCARD Buffer release() noexcept; + +private: + util::Buffer m_buffer; + size_t m_size; +}; + + +// Implementation: + +class BufferSizeOverflow : public std::exception { +public: + const char* what() const noexcept override + { + return "Buffer size overflow"; + } +}; + +template +inline Buffer::Buffer(size_t initial_size, A& alloc) + : m_data(util::make_unique(alloc, initial_size)) // Throws + , m_size(initial_size) +{ +} + +template +inline void Buffer::set_size(size_t new_size) +{ + m_data = util::make_unique(get_allocator(), new_size); // Throws + m_size = new_size; +} + +template +inline void Buffer::resize(size_t new_size, size_t copy_begin, size_t copy_end, size_t copy_to) +{ + auto new_data = util::make_unique(get_allocator(), new_size); // Throws + realm::safe_copy_n(m_data.get() + copy_begin, copy_end - copy_begin, new_data.get() + copy_to); + m_data = std::move(new_data); + m_size = new_size; +} + +template +inline void Buffer::reserve(size_t used_size, size_t min_capacity) +{ + size_t current_capacity = m_size; + if (REALM_LIKELY(current_capacity >= min_capacity)) + return; + size_t new_capacity = current_capacity; + + // Use growth factor 1.5. + if (REALM_UNLIKELY(int_multiply_with_overflow_detect(new_capacity, 3))) + new_capacity = std::numeric_limits::max(); + new_capacity /= 2; + + if (REALM_UNLIKELY(new_capacity < min_capacity)) + new_capacity = min_capacity; + resize(new_capacity, 0, used_size, 0); // Throws +} + +template +inline void Buffer::reserve_extra(size_t used_size, size_t min_extra_capacity) +{ + size_t min_capacity = used_size; + if (REALM_UNLIKELY(int_add_with_overflow_detect(min_capacity, min_extra_capacity))) + throw BufferSizeOverflow(); + reserve(used_size, min_capacity); // Throws +} + +template +inline std::unique_ptr> Buffer::release() noexcept +{ + m_size = 0; + return std::move(m_data); +} + + +template +inline AppendBuffer::AppendBuffer(A& alloc) noexcept + : m_buffer(alloc) + , m_size(0) +{ +} + +template +inline size_t AppendBuffer::size() const noexcept +{ + return m_size; +} + +template +inline T* AppendBuffer::data() noexcept +{ + return m_buffer.data(); +} + +template +inline const T* AppendBuffer::data() const noexcept +{ + return m_buffer.data(); +} + +template +inline void AppendBuffer::append(const T* append_data, size_t append_data_size) +{ + m_buffer.reserve_extra(m_size, append_data_size); // Throws + realm::safe_copy_n(append_data, append_data_size, m_buffer.data() + m_size); + m_size += append_data_size; +} + +template +inline void AppendBuffer::reserve(size_t min_capacity) +{ + m_buffer.reserve(m_size, min_capacity); +} + +template +inline void AppendBuffer::resize(size_t new_size) +{ + reserve(new_size); + m_size = new_size; +} + +template +inline void AppendBuffer::clear() noexcept +{ + m_size = 0; +} + +template +inline Buffer AppendBuffer::release() noexcept +{ + m_size = 0; + return std::move(m_buffer); +} + + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_BUFFER_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/buffer_stream.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/buffer_stream.hpp new file mode 100644 index 0000000..cb51ab6 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/buffer_stream.hpp @@ -0,0 +1,146 @@ +/************************************************************************* + * + * Copyright 2019 Realm Inc. + * + * 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 REALM_UTIL_BUFFER_STREAM_HPP +#define REALM_UTIL_BUFFER_STREAM_HPP + +#include +#include + +namespace realm { +namespace util { + + +template , class A = std::allocator> +class BasicResettableExpandableOutputStreambuf : public std::basic_stringbuf { +public: + using char_type = typename std::basic_stringbuf::char_type; + + /// Reset current writing position (std::basic_streambuf::pptr()) to the + /// beginning of the output buffer without reallocating buffer memory. + void reset() noexcept; + + //@{ + /// Get a pointer to the beginning of the output buffer + /// (std::basic_streambuf::pbase()). Note that this will change as the + /// buffer is reallocated. + char_type* data() noexcept; + const char_type* data() const noexcept; + //@} + + /// Get the number of bytes written to the output buffer since the creation + /// of the stream buffer, or since the last invocation of reset() + /// (std::basic_streambuf::pptr() - std::basic_streambuf::pbase()). + std::size_t size() const noexcept; +}; + + +template , class A = std::allocator> +class BasicResettableExpandableBufferOutputStream : public std::basic_ostream { +public: + using char_type = typename std::basic_ostream::char_type; + + BasicResettableExpandableBufferOutputStream(); + + /// Calls BasicResettableExpandableOutputStreambuf::reset(). + void reset() noexcept; + + //@{ + /// Calls BasicResettableExpandableOutputStreambuf::data(). + char_type* data() noexcept; + const char_type* data() const noexcept; + //@} + + /// Calls BasicResettableExpandableOutputStreambuf::size(). + std::size_t size() const noexcept; + +private: + BasicResettableExpandableOutputStreambuf m_streambuf; +}; + + +using ResettableExpandableBufferOutputStream = BasicResettableExpandableBufferOutputStream; + + +// Implementation + +template +inline void BasicResettableExpandableOutputStreambuf::reset() noexcept +{ + char_type* pbeg = this->pbase(); + char_type* pend = this->epptr(); + this->setp(pbeg, pend); +} + +template +inline typename BasicResettableExpandableOutputStreambuf::char_type* +BasicResettableExpandableOutputStreambuf::data() noexcept +{ + return this->pbase(); +} + +template +inline const typename BasicResettableExpandableOutputStreambuf::char_type* +BasicResettableExpandableOutputStreambuf::data() const noexcept +{ + return this->pbase(); +} + +template +inline std::size_t BasicResettableExpandableOutputStreambuf::size() const noexcept +{ + std::size_t size = std::size_t(this->pptr() - this->pbase()); + return size; +} + +template +inline BasicResettableExpandableBufferOutputStream::BasicResettableExpandableBufferOutputStream() + : std::basic_ostream(&m_streambuf) // Throws +{ +} + +template +inline void BasicResettableExpandableBufferOutputStream::reset() noexcept +{ + m_streambuf.reset(); +} + +template +inline typename BasicResettableExpandableBufferOutputStream::char_type* +BasicResettableExpandableBufferOutputStream::data() noexcept +{ + return m_streambuf.data(); +} + +template +inline const typename BasicResettableExpandableBufferOutputStream::char_type* +BasicResettableExpandableBufferOutputStream::data() const noexcept +{ + return m_streambuf.data(); +} + +template +inline std::size_t BasicResettableExpandableBufferOutputStream::size() const noexcept +{ + return m_streambuf.size(); +} + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_BUFFER_STREAM_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/call_with_tuple.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/call_with_tuple.hpp new file mode 100644 index 0000000..7d2eab0 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/call_with_tuple.hpp @@ -0,0 +1,66 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_UTIL_CALL_WITH_TUPLE_HPP +#define REALM_UTIL_CALL_WITH_TUPLE_HPP + +#include +#include + +namespace realm { +namespace _impl { + +/// \cond doxygen_skip +/// Doxygen warns about a recursive class relation, but this is intentional. + +template +struct Indexes { +}; +template +struct GenIndexes : GenIndexes { +}; +template +struct GenIndexes<0, I...> { + typedef Indexes type; +}; + +/// \endcond + +template +auto call_with_tuple(F func, std::tuple args, Indexes) -> decltype(func(std::get(args)...)) +{ + static_cast(args); // Prevent GCC warning when tuple is empty + return func(std::get(args)...); +} + +} // namespace _impl + +namespace util { + +template +auto call_with_tuple(F func, std::tuple args) + -> decltype(_impl::call_with_tuple(std::move(func), std::move(args), + typename _impl::GenIndexes::type())) +{ + return _impl::call_with_tuple(std::move(func), std::move(args), typename _impl::GenIndexes::type()); +} + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_CALL_WITH_TUPLE_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/cf_ptr.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/cf_ptr.hpp new file mode 100644 index 0000000..a1ec431 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/cf_ptr.hpp @@ -0,0 +1,108 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_UTIL_CF_PTR_HPP +#define REALM_UTIL_CF_PTR_HPP + +#include + +#if REALM_PLATFORM_APPLE + +#include + +namespace realm { +namespace util { + +template +class CFPtr { +public: + explicit CFPtr(Ref ref = nullptr) noexcept + : m_ref(ref) + { + } + + CFPtr(CFPtr&& rg) noexcept + : m_ref(rg.m_ref) + { + rg.m_ref = nullptr; + } + + ~CFPtr() noexcept + { + if (m_ref) + CFRelease(m_ref); + } + + CFPtr& operator=(CFPtr&& rg) noexcept + { + REALM_ASSERT(!m_ref || m_ref != rg.m_ref); + if (m_ref) + CFRelease(m_ref); + m_ref = rg.m_ref; + rg.m_ref = nullptr; + return *this; + } + + explicit operator bool() const noexcept + { + return bool(m_ref); + } + + Ref get() const noexcept + { + return m_ref; + } + + Ref release() noexcept + { + Ref ref = m_ref; + m_ref = nullptr; + return ref; + } + + void reset(Ref ref = nullptr) noexcept + { + REALM_ASSERT(!m_ref || m_ref != ref); + if (m_ref) + CFRelease(m_ref); + m_ref = ref; + } + +private: + Ref m_ref; +}; + +template +CFPtr adoptCF(Ref ptr) +{ + return CFPtr(ptr); +} + +template +CFPtr retainCF(Ref ptr) +{ + CFRetain(ptr); + return CFPtr(ptr); +} +} +} + + +#endif // REALM_PLATFORM_APPLE + +#endif // REALM_UTIL_CF_PTR_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/cf_str.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/cf_str.hpp new file mode 100644 index 0000000..d9f53a6 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/cf_str.hpp @@ -0,0 +1,54 @@ +/************************************************************************* + * + * Copyright 2020 Realm Inc. + * + * 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 REALM_UTIL_CF_STR_HPP +#define REALM_UTIL_CF_STR_HPP + +#include + +#if REALM_PLATFORM_APPLE + +#include + +namespace realm { +namespace util { + +inline std::string cfstring_to_std_string(CFStringRef cf_str) +{ + std::string ret; + // If the CFString happens to store UTF-8 we can read its data directly + if (const char* utf8 = CFStringGetCStringPtr(cf_str, kCFStringEncodingUTF8)) { + ret = utf8; + return ret; + } + + // Otherwise we need to convert the CFString to UTF-8 + CFIndex length = CFStringGetLength(cf_str); + CFIndex max_size = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1; + ret.resize(max_size); + CFStringGetCString(cf_str, &ret[0], max_size, kCFStringEncodingUTF8); + ret.resize(strlen(ret.c_str())); + return ret; +} + +} // namespace util +} // namespace realm + +#endif // REALM_PLATFORM_APPLE + +#endif // REALM_UTIL_CF_STR_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/circular_buffer.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/circular_buffer.hpp new file mode 100644 index 0000000..45bfbda --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/circular_buffer.hpp @@ -0,0 +1,1069 @@ + +#ifndef REALM_UTIL_CIRCULAR_BUFFER_HPP +#define REALM_UTIL_CIRCULAR_BUFFER_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace realm { +namespace util { + +/// \brief A container backed by a "circular buffer". +/// +/// This container is similar to std::deque in that it offers efficient element +/// insertion and removal at both ends. Insertion at either end occurs in +/// amortized constant time. Removal at either end occurs in constant time. +/// +/// As opposed to std::deque, this container allows for reservation of buffer +/// space, such that value insertion can be guaranteed to not reallocate buffer +/// memory, and to not throw. +/// +/// More specifically, a single insert operation, that inserts zero or more +/// values at either end, is guaranteed to not reallocate buffer memory if the +/// prior capacity (capacity()) is greater than, or equal to the prior size +/// (size()) plus the number of inserted values. Further more, such an operation +/// is guaranteed to not throw if the capacity is sufficient, and the relevant +/// constructor of the value type does not throw, and, in the case of inserting +/// a range of values specified as a pair of iterators, if no exception is +/// thrown while operating on those iterators. +/// +/// This container uses a single contiguous chunk of memory as backing storage, +/// but it allows for the logical sequence of values to wrap around from the +/// end, to the beginning of that chunk. Because the logical sequence of values +/// can have a storage-wise discontinuity of this kind, this container does not +/// meet the requirements of `ContiguousContainer` (as defined by C++17). +/// +/// When the first element is removed (pop_front()), iterators pointing to the +/// removed element will be invalidated. All other iterators, including "end +/// iterators" (end()), will remain valid. +/// +/// When the last element is removed (pop_back()), iterators pointing to the +/// removed element will become "end iterators" (end()), and "end iterators" +/// will be invalidated. All other iterators will remain valid. +/// +/// When an element is inserted at the front (push_front()), and the prior +/// capacity (capacity()) is strictly greater than the prior size (size()), all +/// iterators remain valid. +/// +/// When an element is inserted at the back (push_back()), and the prior +/// capacity (capacity()) is strictly greater than the prior size (size()), "end +/// iterators" (end()) become iterators to the inserted element, and all other +/// iterators remain valid. +/// +/// Operations pop_front(), pop_back(), and clear(), are guaranteed to leave the +/// capacity unchanged. +/// +/// Iterators are of the "random access" kind (std::random_access_iterator_tag). +template +class CircularBuffer { +private: + template + class Iter; + + template + using RequireIter = std::enable_if_t< + std::is_convertible::iterator_category, std::input_iterator_tag>::value>; + +public: + static_assert(std::is_nothrow_destructible::value, ""); + + using value_type = T; + using size_type = std::size_t; + using reference = value_type&; + using const_reference = const value_type&; + using iterator = Iter; + using const_iterator = Iter; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + CircularBuffer() noexcept; + CircularBuffer(const CircularBuffer&); + CircularBuffer(CircularBuffer&&) noexcept; + CircularBuffer(std::initializer_list); + explicit CircularBuffer(size_type size); + CircularBuffer(size_type size, const T& value); + template > + CircularBuffer(I begin, I end); + ~CircularBuffer() noexcept; + + CircularBuffer& operator=(const CircularBuffer&); + CircularBuffer& operator=(CircularBuffer&&) noexcept; + CircularBuffer& operator=(std::initializer_list); + + void assign(std::initializer_list); + void assign(size_type size, const T& value); + template > + void assign(I begin, I end); + + // Element access + + reference at(size_type); + const_reference at(size_type) const; + + reference operator[](size_type) noexcept; + const_reference operator[](size_type) const noexcept; + + reference front() noexcept; + const_reference front() const noexcept; + + reference back() noexcept; + const_reference back() const noexcept; + + // Iterators + + iterator begin() noexcept; + const_iterator begin() const noexcept; + const_iterator cbegin() const noexcept; + + iterator end() noexcept; + const_iterator end() const noexcept; + const_iterator cend() const noexcept; + + reverse_iterator rbegin() noexcept; + const_reverse_iterator rbegin() const noexcept; + const_reverse_iterator crbegin() const noexcept; + + reverse_iterator rend() noexcept; + const_reverse_iterator rend() const noexcept; + const_reverse_iterator crend() const noexcept; + + // Size / capacity + + bool empty() const noexcept; + size_type size() const noexcept; + size_type capacity() const noexcept; + + void reserve(size_type capacity); + void shrink_to_fit(); + + // Modifiers + + reference push_front(const T&); + reference push_back(const T&); + + reference push_front(T&&); + reference push_back(T&&); + + template + reference emplace_front(Args&&...); + template + reference emplace_back(Args&&...); + + void pop_front() noexcept; + void pop_back() noexcept; + + // FIXME: emplace(const_iterator i, ...) -> j = unwrap(i.m_index); if (j >= (m_size+1)/2) insert_near_back(j, + // ...); else insert_near_front(j, ...); + + void clear() noexcept; + void resize(size_type size); + void resize(size_type size, const T& value); + + void swap(CircularBuffer&) noexcept; + + // Comparison + + template + bool operator==(const CircularBuffer&) const noexcept(noexcept(std::declval() == std::declval())); + template + bool operator!=(const CircularBuffer&) const noexcept(noexcept(std::declval() == std::declval())); + template + bool operator<(const CircularBuffer&) const noexcept(noexcept(std::declval() < std::declval())); + template + bool operator>(const CircularBuffer&) const noexcept(noexcept(std::declval() < std::declval())); + template + bool operator<=(const CircularBuffer&) const noexcept(noexcept(std::declval() < std::declval())); + template + bool operator>=(const CircularBuffer&) const noexcept(noexcept(std::declval() < std::declval())); + +private: + using Strut = typename std::aligned_storage::type; + std::unique_ptr m_memory_owner; + + // Index of first element in allocated memory chunk. + // + // INVARIANT: m_allocated_size == 0 ? m_begin == 0 : m_begin < m_allocated_size + size_type m_begin = 0; + + // The number of elements within the allocated memory chunk, that are + // currently in use, i.e., the logical size of the circular buffer. + size_type m_size = 0; + + // Number of elements of type T that will fit into the currently allocated + // memory chunk. + // + // Except when m_size is zero, m_allocated_size must be strictly greater + // than m_size. This is required to ensure that the iterators returned by + // begin() and end() are equal only when the buffer is empty. + // + // INVARIANT: m_size == 0 || m_allocated_size > m_size + size_type m_allocated_size = 0; + + T* get_memory_ptr() noexcept; + + // Assumption: index < m_allocated_size + size_type circular_inc(size_type index) noexcept; + size_type circular_dec(size_type index) noexcept; + size_type wrap(size_type index) noexcept; + size_type unwrap(size_type index) noexcept; + + template + void copy(I begin, I end); + template + void copy(I begin, I end, std::input_iterator_tag); + template + void copy(I begin, I end, std::forward_iterator_tag); + + void destroy(size_type offset = 0) noexcept; + + void realloc(size_type new_allocated_size); +}; + + +template +void swap(CircularBuffer&, CircularBuffer&) noexcept; + + +// Implementation + +template +template +class CircularBuffer::Iter : public std::iterator { +public: + using difference_type = std::ptrdiff_t; + + Iter() noexcept {} + + template + Iter(const Iter& i) noexcept + { + operator=(i); + } + + template + Iter& operator=(const Iter& i) noexcept + { + // Check constness convertability + static_assert(std::is_convertible::value, ""); + m_buffer = i.m_buffer; + m_index = i.m_index; + return *this; + } + + U& operator*() const noexcept + { + T* memory = m_buffer->get_memory_ptr(); + return memory[m_index]; + } + + U* operator->() const noexcept + { + return &operator*(); + } + + U& operator[](difference_type i) const noexcept + { + Iter j = *this; + j += i; + return *j; + } + + Iter& operator++() noexcept + { + m_index = m_buffer->circular_inc(m_index); + return *this; + } + + Iter& operator--() noexcept + { + m_index = m_buffer->circular_dec(m_index); + return *this; + } + + Iter operator++(int) noexcept + { + size_type i = m_index; + operator++(); + return Iter{m_buffer, i}; + } + + Iter operator--(int) noexcept + { + size_type i = m_index; + operator--(); + return Iter{m_buffer, i}; + } + + Iter& operator+=(difference_type value) noexcept + { + // Care is needed to avoid unspecified arithmetic behaviour here. We can + // assume, however, that if `i` is the unwrapped (logical) index of the + // element pointed to by this iterator, then the mathematical value of i + // + value is representable in `size_type` (otherwise the resulting + // iterator would escape the boundaries of the buffer). We can therefore + // safely perform the addition in the unsigned domain of unwrapped + // element indexes, and rely on two's complement representation for + // negative values. + size_type i = m_buffer->unwrap(m_index); + i += size_type(value); + m_index = m_buffer->wrap(i); + return *this; + } + + Iter& operator-=(difference_type value) noexcept + { + // Care is needed to avoid unspecified arithmetic behaviour here. See + // the comment in the implementation of operator+=(). + size_type i = m_buffer->unwrap(m_index); + i -= size_type(value); + m_index = m_buffer->wrap(i); + return *this; + } + + Iter operator+(difference_type value) const noexcept + { + Iter i = *this; + i += value; + return i; + } + + Iter operator-(difference_type value) const noexcept + { + Iter i = *this; + i -= value; + return i; + } + + friend Iter operator+(difference_type value, const Iter& i) noexcept + { + Iter j = i; + j += value; + return j; + } + + template + difference_type operator-(const Iter& i) const noexcept + { + REALM_ASSERT(m_buffer == i.m_buffer); + size_type i_1 = m_buffer->unwrap(m_index); + size_type i_2 = i.m_buffer->unwrap(i.m_index); + return difference_type(size_type(i_1 - i_2)); + } + + template + bool operator==(const Iter& i) const noexcept + { + REALM_ASSERT(m_buffer == i.m_buffer); + return (m_index == i.m_index); + } + + template + bool operator!=(const Iter& i) const noexcept + { + return !operator==(i); + } + + template + bool operator<(const Iter& i) const noexcept + { + REALM_ASSERT(m_buffer == i.m_buffer); + size_type i_1 = m_buffer->unwrap(m_index); + size_type i_2 = i.m_buffer->unwrap(i.m_index); + return (i_1 < i_2); + } + + template + bool operator>(const Iter& i) const noexcept + { + return (i < *this); + } + + template + bool operator<=(const Iter& i) const noexcept + { + return !operator>(i); + } + + template + bool operator>=(const Iter& i) const noexcept + { + return !operator<(i); + } + +private: + CircularBuffer* m_buffer = nullptr; + + // Index of iterator position from beginning of allocated memory, i.e., from + // beginning of m_buffer->get_memory_ptr(). + size_type m_index = 0; + + Iter(CircularBuffer* buffer, size_type index) noexcept + : m_buffer{buffer} + , m_index{index} + { + } + + friend class CircularBuffer; + template + friend class Iter; +}; + +template +inline CircularBuffer::CircularBuffer() noexcept +{ +} + +template +inline CircularBuffer::CircularBuffer(const CircularBuffer& buffer) +{ + try { + copy(buffer.begin(), buffer.end()); // Throws + } + catch (...) { + // If an exception was thrown above, the destructor will not be called, + // so we need to manually destroy the copies that were already made. + destroy(); + throw; + } +} + +template +inline CircularBuffer::CircularBuffer(CircularBuffer&& buffer) noexcept + : m_memory_owner{std::move(buffer.m_memory_owner)} + , m_begin{buffer.m_begin} + , m_size{buffer.m_size} + , m_allocated_size{buffer.m_allocated_size} +{ + buffer.m_begin = 0; + buffer.m_size = 0; + buffer.m_allocated_size = 0; +} + +template +inline CircularBuffer::CircularBuffer(std::initializer_list list) +{ + try { + copy(list.begin(), list.end()); // Throws + } + catch (...) { + // If an exception was thrown above, the destructor will not be called, + // so we need to manually destroy the copies that were already made. + destroy(); + throw; + } +} + +template +inline CircularBuffer::CircularBuffer(size_type count) +{ + try { + resize(count); // Throws + } + catch (...) { + // If an exception was thrown above, the destructor will not be called, + // so we need to manually destroy the instances that were already + // created. + destroy(); + throw; + } +} + +template +inline CircularBuffer::CircularBuffer(size_type count, const T& value) +{ + try { + resize(count, value); // Throws + } + catch (...) { + // If an exception was thrown above, the destructor will not be called, + // so we need to manually destroy the copies that were already made. + destroy(); + throw; + } +} + +template +template +inline CircularBuffer::CircularBuffer(I begin, I end) +{ + try { + copy(begin, end); // Throws + } + catch (...) { + // If an exception was thrown above, the destructor will not be called, + // so we need to manually destroy the copies that were already made. + destroy(); + throw; + } +} + +template +inline CircularBuffer::~CircularBuffer() noexcept +{ + destroy(); +} + +template +inline auto CircularBuffer::operator=(const CircularBuffer& buffer) -> CircularBuffer& +{ + clear(); + copy(buffer.begin(), buffer.end()); // Throws + return *this; +} + +template +inline auto CircularBuffer::operator=(CircularBuffer&& buffer) noexcept -> CircularBuffer& +{ + destroy(); + m_memory_owner = std::move(buffer.m_memory_owner); + m_begin = buffer.m_begin; + m_size = buffer.m_size; + m_allocated_size = buffer.m_allocated_size; + buffer.m_begin = 0; + buffer.m_size = 0; + buffer.m_allocated_size = 0; + return *this; +} + +template +inline auto CircularBuffer::operator=(std::initializer_list list) -> CircularBuffer& +{ + clear(); + copy(list.begin(), list.end()); // Throws + return *this; +} + +template +inline void CircularBuffer::assign(std::initializer_list list) +{ + clear(); + copy(list.begin(), list.end()); // Throws +} + +template +inline void CircularBuffer::assign(size_type count, const T& value) +{ + clear(); + resize(count, value); // Throws +} + +template +template +inline void CircularBuffer::assign(I begin, I end) +{ + clear(); + copy(begin, end); // Throws +} + +template +inline auto CircularBuffer::at(size_type i) -> reference +{ + if (REALM_LIKELY(i < m_size)) + return operator[](i); + throw util::out_of_range{"Index"}; +} + +template +inline auto CircularBuffer::at(size_type i) const -> const_reference +{ + return const_cast(this)->at(i); // Throws +} + +template +inline auto CircularBuffer::operator[](size_type i) noexcept -> reference +{ + REALM_ASSERT(i < m_size); + T* memory = get_memory_ptr(); + size_type j = wrap(i); + return memory[j]; +} + +template +inline auto CircularBuffer::operator[](size_type i) const noexcept -> const_reference +{ + return const_cast(this)->operator[](i); +} + +template +inline auto CircularBuffer::front() noexcept -> reference +{ + return operator[](0); +} + +template +inline auto CircularBuffer::front() const noexcept -> const_reference +{ + return operator[](0); +} + +template +inline auto CircularBuffer::back() noexcept -> reference +{ + return operator[](m_size - 1); +} + +template +inline auto CircularBuffer::back() const noexcept -> const_reference +{ + return operator[](m_size - 1); +} + +template +inline auto CircularBuffer::begin() noexcept -> iterator +{ + return iterator{this, m_begin}; +} + +template +inline auto CircularBuffer::begin() const noexcept -> const_iterator +{ + return const_cast(this)->begin(); +} + +template +inline auto CircularBuffer::cbegin() const noexcept -> const_iterator +{ + return begin(); +} + +template +inline auto CircularBuffer::end() noexcept -> iterator +{ + size_type i = wrap(m_size); + return iterator{this, i}; +} + +template +inline auto CircularBuffer::end() const noexcept -> const_iterator +{ + return const_cast(this)->end(); +} + +template +inline auto CircularBuffer::cend() const noexcept -> const_iterator +{ + return end(); +} + +template +inline auto CircularBuffer::rbegin() noexcept -> reverse_iterator +{ + return std::reverse_iterator(end()); +} + +template +inline auto CircularBuffer::rbegin() const noexcept -> const_reverse_iterator +{ + return const_cast(this)->rbegin(); +} + +template +inline auto CircularBuffer::crbegin() const noexcept -> const_reverse_iterator +{ + return rbegin(); +} + +template +inline auto CircularBuffer::rend() noexcept -> reverse_iterator +{ + return std::reverse_iterator(begin()); +} + +template +inline auto CircularBuffer::rend() const noexcept -> const_reverse_iterator +{ + return const_cast(this)->rend(); +} + +template +inline auto CircularBuffer::crend() const noexcept -> const_reverse_iterator +{ + return rend(); +} + +template +inline bool CircularBuffer::empty() const noexcept +{ + return (m_size == 0); +} + +template +inline auto CircularBuffer::size() const noexcept -> size_type +{ + return m_size; +} + +template +void CircularBuffer::reserve(size_type capacity) +{ + if (capacity == 0) + return; + + // An extra element of capacity is needed such that the end iterator can + // always point one beyond the last element without becomeing equal to an + // iterator to the first element. + size_type min_allocated_size = capacity; + if (REALM_UNLIKELY(int_add_with_overflow_detect(min_allocated_size, 1))) + throw util::overflow_error{"Capacity"}; + + if (min_allocated_size <= m_allocated_size) + return; + + size_type new_allocated_size = m_allocated_size; + if (REALM_UNLIKELY(int_multiply_with_overflow_detect(new_allocated_size, 2))) + new_allocated_size = std::numeric_limits::max(); + if (new_allocated_size < min_allocated_size) + new_allocated_size = min_allocated_size; + realloc(new_allocated_size); // Throws +} + +template +inline void CircularBuffer::shrink_to_fit() +{ + if (m_size > 0) { + // An extra element of capacity is needed such that the end iterator can + // always point one beyond the last element without becomeing equal to + // an iterator to the first element. + size_type new_allocated_size = m_size + 1; + if (new_allocated_size < m_allocated_size) + realloc(new_allocated_size); // Throws + } + else { + m_memory_owner.reset(); + m_begin = 0; + m_allocated_size = 0; + } +} + +template +inline auto CircularBuffer::capacity() const noexcept -> size_type +{ + return (m_allocated_size > 0 ? m_allocated_size - 1 : 0); +} + +template +inline auto CircularBuffer::push_front(const T& value) -> reference +{ + return emplace_front(value); // Throws +} + +template +inline auto CircularBuffer::push_back(const T& value) -> reference +{ + return emplace_back(value); // Throws +} + +template +inline auto CircularBuffer::push_front(T&& value) -> reference +{ + return emplace_front(std::move(value)); // Throws +} + +template +inline auto CircularBuffer::push_back(T&& value) -> reference +{ + return emplace_back(std::move(value)); // Throws +} + +template +template +inline auto CircularBuffer::emplace_front(Args&&... args) -> reference +{ + size_type new_size = m_size + 1; + reserve(new_size); // Throws + REALM_ASSERT(m_allocated_size > 0); + T* memory = get_memory_ptr(); + size_type i = circular_dec(m_begin); + new (&memory[i]) T(std::forward(args)...); // Throws + m_begin = i; + m_size = new_size; + return memory[i]; +} + +template +template +inline auto CircularBuffer::emplace_back(Args&&... args) -> reference +{ + size_type new_size = m_size + 1; + reserve(new_size); // Throws + REALM_ASSERT(m_allocated_size > 0); + T* memory = get_memory_ptr(); + size_type i = wrap(m_size); + new (&memory[i]) T(std::forward(args)...); // Throws + m_size = new_size; + return memory[i]; +} + +template +inline void CircularBuffer::pop_front() noexcept +{ + REALM_ASSERT(m_size > 0); + T* memory = get_memory_ptr(); + memory[m_begin].~T(); + m_begin = circular_inc(m_begin); + --m_size; +} + +template +inline void CircularBuffer::pop_back() noexcept +{ + REALM_ASSERT(m_size > 0); + T* memory = get_memory_ptr(); + size_type new_size = m_size - 1; + size_type i = wrap(new_size); + memory[i].~T(); + m_size = new_size; +} + +template +inline void CircularBuffer::clear() noexcept +{ + destroy(); + m_begin = 0; + m_size = 0; +} + +template +inline void CircularBuffer::resize(size_type size) +{ + if (size <= m_size) { + size_type offset = size; + destroy(offset); + m_size = size; + return; + } + reserve(size); // Throws + T* memory = get_memory_ptr(); + size_type i = wrap(m_size); + do { + new (&memory[i]) T(); // Throws + i = circular_inc(i); + ++m_size; + } while (m_size < size); +} + +template +inline void CircularBuffer::resize(size_type size, const T& value) +{ + if (size <= m_size) { + size_type offset = size; + destroy(offset); + m_size = size; + return; + } + reserve(size); // Throws + T* memory = get_memory_ptr(); + size_type i = wrap(m_size); + do { + new (&memory[i]) T(value); // Throws + i = circular_inc(i); + ++m_size; + } while (m_size < size); +} + +template +inline void CircularBuffer::swap(CircularBuffer& buffer) noexcept +{ + std::swap(m_memory_owner, buffer.m_memory_owner); + std::swap(m_begin, buffer.m_begin); + std::swap(m_size, buffer.m_size); + std::swap(m_allocated_size, buffer.m_allocated_size); +} + +template +template +inline bool CircularBuffer::operator==(const CircularBuffer& buffer) const + noexcept(noexcept(std::declval() == std::declval())) +{ + return std::equal(begin(), end(), buffer.begin(), buffer.end()); // Throws +} + +template +template +inline bool CircularBuffer::operator!=(const CircularBuffer& buffer) const + noexcept(noexcept(std::declval() == std::declval())) +{ + return !operator==(buffer); // Throws +} + +template +template +inline bool CircularBuffer::operator<(const CircularBuffer& buffer) const + noexcept(noexcept(std::declval() < std::declval())) +{ + return std::lexicographical_compare(begin(), end(), buffer.begin(), buffer.end()); // Throws +} + +template +template +inline bool CircularBuffer::operator>(const CircularBuffer& buffer) const + noexcept(noexcept(std::declval() < std::declval())) +{ + return (buffer < *this); // Throws +} + +template +template +inline bool CircularBuffer::operator<=(const CircularBuffer& buffer) const + noexcept(noexcept(std::declval() < std::declval())) +{ + return !operator>(buffer); // Throws +} + +template +template +inline bool CircularBuffer::operator>=(const CircularBuffer& buffer) const + noexcept(noexcept(std::declval() < std::declval())) +{ + return !operator<(buffer); // Throws +} + +template +inline T* CircularBuffer::get_memory_ptr() noexcept +{ + return static_cast(static_cast(m_memory_owner.get())); +} + +template +inline auto CircularBuffer::circular_inc(size_type index) noexcept -> size_type +{ + size_type index_2 = index + 1; + if (REALM_LIKELY(index_2 < m_allocated_size)) + return index_2; + return 0; +} + +template +inline auto CircularBuffer::circular_dec(size_type index) noexcept -> size_type +{ + if (REALM_LIKELY(index > 0)) + return index - 1; + return m_allocated_size - 1; +} + +template +inline auto CircularBuffer::wrap(size_type index) noexcept -> size_type +{ + size_type top = m_allocated_size - m_begin; + if (index < top) + return m_begin + index; + return index - top; +} + +template +inline auto CircularBuffer::unwrap(size_type index) noexcept -> size_type +{ + if (index >= m_begin) + return index - m_begin; + return m_allocated_size - (m_begin - index); +} + +template +template +inline void CircularBuffer::copy(I begin, I end) +{ + using iterator_category = typename std::iterator_traits::iterator_category; + copy(begin, end, iterator_category{}); // Throws +} + +template +template +inline void CircularBuffer::copy(I begin, I end, std::input_iterator_tag) +{ + for (I j = begin; j != end; ++j) + push_back(*j); // Throws +} + +template +template +inline void CircularBuffer::copy(I begin, I end, std::forward_iterator_tag) +{ + REALM_ASSERT(m_begin == 0); + REALM_ASSERT(m_size == 0); + size_type size = std::distance(begin, end); + reserve(size); // Throws + T* memory = get_memory_ptr(); + for (I i = begin; i != end; ++i) { + new (&memory[m_size]) T(*i); // Throws + ++m_size; + } +} + +template +inline void CircularBuffer::destroy(size_type offset) noexcept +{ + T* memory = get_memory_ptr(); + size_type j = wrap(offset); + for (size_type i = offset; i < m_size; ++i) { + memory[j].~T(); + j = circular_inc(j); + } +} + +template +void CircularBuffer::realloc(size_type new_allocated_size) +{ + REALM_ASSERT(new_allocated_size > 1); + REALM_ASSERT(new_allocated_size > m_size); + + // Allocate new buffer + std::unique_ptr new_memory_owner = std::make_unique(new_allocated_size); // Throws + T* memory = get_memory_ptr(); + + // Move or copy elements to new buffer + { + T* new_memory = static_cast(static_cast(new_memory_owner.get())); + size_type i = 0; + try { + size_type j = m_begin; + while (i < m_size) { + new (&new_memory[i]) T(std::move_if_noexcept(memory[j])); // Throws + ++i; + j = circular_inc(j); + } + } + catch (...) { + // If an exception was thrown above, we know that elements were + // copied, and not moved (assuming that T is copy constructable if + // it is not nothrow move constructible), so we need to back out by + // destroying the copies that were already made. + for (size_type j = 0; j < i; ++j) + new_memory[j].~T(); + throw; + } + } + + // Destroy old elements + { + size_type j = m_begin; + for (size_type i = 0; i < m_size; ++i) { + memory[j].~T(); + j = circular_inc(j); + } + } + + m_memory_owner = std::move(new_memory_owner); + m_begin = 0; + m_allocated_size = new_allocated_size; +} + +template +inline void swap(CircularBuffer& a, CircularBuffer& b) noexcept +{ + a.swap(b); +} + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_CIRCULAR_BUFFER_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/config.h b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/config.h new file mode 100644 index 0000000..cdd4b78 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/config.h @@ -0,0 +1,24 @@ +// Version information +#define REALM_VERSION "" + +// Specific headers +#define HAVE_MALLOC_H 0 + +// Realm-specific configuration +/* #undef REALM_HAVE_READDIR64 */ +#define REALM_MAX_BPNODE_SIZE 1000 +#define REALM_ENABLE_ASSERTIONS 1 +#define REALM_ENABLE_ALLOC_SET_ZERO 0 +#define REALM_ENABLE_ENCRYPTION 1 +#define REALM_ENABLE_MEMDEBUG 0 +#define REALM_VALGRIND 0 +#define REALM_METRICS 1 +#define REALM_ASAN 0 +#define REALM_TSAN 0 + +#define REALM_INSTALL_PREFIX "/usr/local" +#define REALM_INSTALL_INCLUDEDIR "include" +#define REALM_INSTALL_BINDIR "bin" +#define REALM_INSTALL_LIBDIR "lib" +#define REALM_INSTALL_LIBEXECDIR "libexec" +#define REALM_INSTALL_EXEC_PREFIX "/usr/local" diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/copy_dir_recursive.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/copy_dir_recursive.hpp new file mode 100644 index 0000000..28a822e --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/copy_dir_recursive.hpp @@ -0,0 +1,29 @@ +#ifndef REALM_UTIL_COPY_DIR_RECURSIVE_HPP +#define REALM_UTIL_COPY_DIR_RECURSIVE_HPP + +#include + +namespace realm { +namespace util { + +/// Recursively copy the specified directory. +/// +/// It is not an error if the target directory already exists. It is also not an +/// error if the target directory is not empty. If the origin and target +/// directories contain a file of the same name, the one in the target directory +/// will be overwitten. Other files that already exist in the target directory +/// will be left alone. +/// +/// \param skip_special_files If true, entries in the origin directory that are +/// neither regular files nor subdirectories will be skipped (not copied). If +/// false (the default), this function will fail if such an entry is encoutered. +/// +/// FIXME: This function ought to be moved to in the +/// realm-core repository. +void copy_dir_recursive(const std::string& origin_path, const std::string& target_path, + bool skip_special_files = false); + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_COPY_DIR_RECURSIVE_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/demangle.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/demangle.hpp new file mode 100644 index 0000000..6387db6 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/demangle.hpp @@ -0,0 +1,37 @@ +#ifndef REALM_UTIL_DEMANGLE_HPP +#define REALM_UTIL_DEMANGLE_HPP + +#include +#include + +namespace realm { +namespace util { + + +/// Demangle the specified C++ ABI identifier. +/// +/// See for example +/// http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/namespaceabi.html +std::string demangle(const std::string&); + + +/// Get the demangled name of the specified type. +template +inline std::string get_type_name() +{ + return demangle(typeid(T).name()); +} + + +/// Get the demangled name of the type of the specified argument. +template +inline std::string get_type_name(const T& v) +{ + return demangle(typeid(v).name()); +} + + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_DEMANGLE_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/duplicating_logger.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/duplicating_logger.hpp new file mode 100644 index 0000000..a24d967 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/duplicating_logger.hpp @@ -0,0 +1,43 @@ + +#ifndef REALM_UTIL_DUPLICATING_LOGGER_HPP +#define REALM_UTIL_DUPLICATING_LOGGER_HPP + +#include + + +namespace realm { +namespace util { + +/// The log level threshold of a logger of this type will be decided by the +/// associated base logger. Therefore, the log level threshold specified via the +/// auxiliary logger will be ignored. +/// +/// Loggers of this type are thread-safe if the base logger and the auxiliary +/// loggers are both thread-safe. +class DuplicatingLogger : public Logger { +public: + explicit DuplicatingLogger(Logger& base_logger, Logger& aux_logger) noexcept; + +protected: + void do_log(Logger::Level, std::string message) override; + +private: + Logger& m_base_logger; + Logger& m_aux_logger; +}; + + +// Implementation + +inline DuplicatingLogger::DuplicatingLogger(Logger& base_logger, Logger& aux_logger) noexcept + : Logger{base_logger.level_threshold} + , m_base_logger{base_logger} + , m_aux_logger{aux_logger} +{ +} + + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_DUPLICATING_LOGGER_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/encrypted_file_mapping.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/encrypted_file_mapping.hpp new file mode 100644 index 0000000..6f5fd3c --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/encrypted_file_mapping.hpp @@ -0,0 +1,181 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_UTIL_ENCRYPTED_FILE_MAPPING_HPP +#define REALM_UTIL_ENCRYPTED_FILE_MAPPING_HPP + +#include +#include +#include + +#if REALM_ENABLE_ENCRYPTION + +typedef size_t (*Header_to_size)(const char* addr); + +#include + +namespace realm { +namespace util { + +struct SharedFileInfo; +class EncryptedFileMapping; + +class EncryptedFileMapping { +public: + // Adds the newly-created object to file.mappings iff it's successfully constructed + EncryptedFileMapping(SharedFileInfo& file, size_t file_offset, void* addr, size_t size, File::AccessMode access); + ~EncryptedFileMapping(); + + // Default implementations of copy/assign can trigger multiple destructions + EncryptedFileMapping(const EncryptedFileMapping&) = delete; + EncryptedFileMapping& operator=(const EncryptedFileMapping&) = delete; + + // Write all dirty pages to disk and mark them read-only + // Does not call fsync + void flush() noexcept; + + // Sync this file to disk + void sync() noexcept; + + // Make sure that memory in the specified range is synchronized with any + // changes made globally visible through call to write_barrier + void read_barrier(const void* addr, size_t size, Header_to_size header_to_size); + + // Ensures that any changes made to memory in the specified range + // becomes visible to any later calls to read_barrier() + void write_barrier(const void* addr, size_t size) noexcept; + + // Set this mapping to a new address and size + // Flushes any remaining dirty pages from the old mapping + void set(void* new_addr, size_t new_size, size_t new_file_offset); + + size_t collect_decryption_count() + { + return m_num_decrypted; + } + // reclaim any untouched pages - this is thread safe with respect to + // concurrent access/touching of pages - but must be called with the mutex locked. + void reclaim_untouched(size_t& progress_ptr, size_t& accumulated_savings) noexcept; + + bool contains_page(size_t page_in_file) const; + size_t get_local_index_of_address(const void* addr, size_t offset = 0) const; + + size_t get_end_index() + { + return m_first_page + m_page_state.size(); + } + size_t get_start_index() + { + return m_first_page; + } + +private: + SharedFileInfo& m_file; + + size_t m_page_shift; + size_t m_blocks_per_page; + + void* m_addr = nullptr; + + size_t m_first_page; + size_t m_num_decrypted; // 1 for every page decrypted + + enum PageState { + Touched = 1, // a ref->ptr translation has taken place + UpToDate = 2, // the page is fully up to date + PartiallyUpToDate = 4, // the page is valid for old translations, but requires re-decryption for new + Dirty = 8 // the page has been modified with respect to what's on file. + }; + std::vector m_page_state; + // little helpers: + inline void clear(PageState& ps, int p) + { + ps = PageState(ps & ~p); + } + inline bool is_not(PageState& ps, int p) + { + return (ps & p) == 0; + } + inline bool is(PageState& ps, int p) + { + return (ps & p) != 0; + } + inline void set(PageState& ps, int p) + { + ps = PageState(ps | p); + } + // 1K pages form a chunk - this array allows us to skip entire chunks during scanning + std::vector m_chunk_dont_scan; + static constexpr int page_to_chunk_shift = 10; + static constexpr size_t page_to_chunk_factor = size_t(1) << page_to_chunk_shift; + + File::AccessMode m_access; + +#ifdef REALM_DEBUG + std::unique_ptr m_validate_buffer; +#endif + + char* page_addr(size_t local_page_ndx) const noexcept; + + void mark_outdated(size_t local_page_ndx) noexcept; + bool copy_up_to_date_page(size_t local_page_ndx) noexcept; + void refresh_page(size_t local_page_ndx); + void write_page(size_t local_page_ndx) noexcept; + void write_and_update_all(size_t local_page_ndx, size_t begin_offset, size_t end_offset) noexcept; + void reclaim_page(size_t page_ndx); + void validate_page(size_t local_page_ndx) noexcept; + void validate() noexcept; +}; + +inline size_t EncryptedFileMapping::get_local_index_of_address(const void* addr, size_t offset) const +{ + REALM_ASSERT_EX(addr >= m_addr, addr, m_addr); + + size_t local_ndx = ((reinterpret_cast(addr) - reinterpret_cast(m_addr) + offset) >> m_page_shift); + REALM_ASSERT_EX(local_ndx < m_page_state.size(), local_ndx, m_page_state.size()); + return local_ndx; +} + +inline bool EncryptedFileMapping::contains_page(size_t page_in_file) const +{ + // first check for (page_in_file >= m_first_page) so that the following + // subtraction using unsigned types never wraps under 0 + return page_in_file >= m_first_page && page_in_file - m_first_page < m_page_state.size(); +} + + +} +} + +#endif // REALM_ENABLE_ENCRYPTION + +namespace realm { +namespace util { + +/// Thrown by EncryptedFileMapping if a file opened is non-empty and does not +/// contain valid encrypted data +struct DecryptionFailed : util::File::AccessError { + DecryptionFailed() + : util::File::AccessError("Decryption failed", std::string()) + { + } +}; +} +} + +#endif // REALM_UTIL_ENCRYPTED_FILE_MAPPING_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/enum.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/enum.hpp new file mode 100644 index 0000000..9efd136 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/enum.hpp @@ -0,0 +1,201 @@ + +#ifndef REALM_UTIL_ENUM_HPP +#define REALM_UTIL_ENUM_HPP + +#include +#include +#include +#include + + +namespace realm { +namespace util { + +/// This template class allows you to endow a fundamental `enum` type with +/// information about how to print out the individual values, and how to parse +/// them. +/// +/// Here is an example: +/// +/// // Declaration +/// +/// enum class Color { orange, purple, brown }; +/// +/// struct ColorSpec { static EnumAssoc map[]; }; +/// using ColorEnum = Enum; +/// +/// // Implementation +/// +/// EnumAssoc ColorSpec::map[] = { +/// { int(Color::orange), "orange" }, +/// { int(Color::purple), "purple" }, +/// { int(Color::brown), "brown" }, +/// { 0, 0 } +/// }; +/// +/// // Application +/// +/// ColorEnum color = Color::purple; +/// +/// std::cout << color; // Write a color +/// std::cin >> color; // Read a color +/// +/// The current implementation is restricted to enumeration types whose values +/// can all be represented in a regular integer. +template +class Enum { +public: + using base_enum_type = E; + + Enum(E = {}) noexcept; + + operator E() const noexcept; + + const std::string& str() const; + + bool str(const std::string*&) const noexcept; + + /// \return True if, and only if successful. + static bool parse(const std::string& string, E& value); + +private: + E m_value = E{}; +}; + +template +std::basic_ostream& operator<<(std::basic_ostream&, const Enum&); + +template +std::basic_istream& operator>>(std::basic_istream&, Enum&); + + +struct EnumAssoc { + const int value; + const char* const name; +}; + + +// Implementation + +} // namespace util + +namespace _impl { + +class EnumMapper { +public: + EnumMapper(const util::EnumAssoc*, bool ignore_case); + + bool parse(const std::string& string, int& value, bool ignore_case) const; + + std::map value_to_name; + std::map name_to_value; +}; + +template +const EnumMapper& get_enum_mapper() +{ + static EnumMapper mapper{S::map, ignore_case}; // Throws + return mapper; +} + +} // namespace _impl + +namespace util { + +template +inline Enum::Enum(E value) noexcept + : m_value{value} +{ +} + +template +inline Enum::operator E() const noexcept +{ + return m_value; +} + +template +inline const std::string& Enum::str() const +{ + return _impl::get_enum_mapper().val_to_name.at(m_value); // Throws +} + +template +inline bool Enum::str(const std::string*& string) const noexcept +{ + const auto& value_to_name = _impl::get_enum_mapper().value_to_name; + auto i = value_to_name.find(int(m_value)); + if (i == value_to_name.end()) + return false; + string = &i->second; + return true; +} + +template +inline bool Enum::parse(const std::string& string, E& value) +{ + int value_2; + if (!_impl::get_enum_mapper().parse(string, value_2, ignore_case)) // Throws + return false; + value = E(value_2); + return true; +} + +template +inline std::basic_ostream& operator<<(std::basic_ostream& out, const Enum& e) +{ + const std::string* string; + if (e.str(string)) { + out << *string; + } + else { + out << int(E(e)); + } + return out; +} + +template +std::basic_istream& operator>>(std::basic_istream& in, Enum& e) +{ + if (in.bad() || in.fail()) + return in; + std::string string; + const std::ctype& ctype = std::use_facet>(in.getloc()); + C underscore(ctype.widen('_')); + for (;;) { + C ch; + // Allow white-spaces to be skipped when stream is configured + // that way + if (string.empty()) { + in >> ch; + } + else { + in.get(ch); + } + if (!in) { + if (in.bad()) + return in; + in.clear(in.rdstate() & ~std::ios_base::failbit); + break; + } + if (!ctype.is(std::ctype_base::alnum, ch) && ch != underscore) { + in.unget(); + break; + } + char ch_2 = ctype.narrow(ch, '\0'); + string += ch_2; + } + E value = E{}; + if (!Enum::parse(string, value)) { // Throws + in.setstate(std::ios_base::badbit); + } + else { + e = value; + } + return in; +} + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_ENUM_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/errno.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/errno.hpp new file mode 100644 index 0000000..4907f36 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/errno.hpp @@ -0,0 +1,39 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_UTIL_ERRNO_HPP +#define REALM_UTIL_ERRNO_HPP + +#include + +#include + + +namespace realm { +namespace util { + +// Get the error message for a given error code, and append it to `prefix` +inline std::string get_errno_msg(const char* prefix, int err) +{ + return prefix + make_basic_system_error_code(err).message(); +} + +} // namespace util +} // namespace realm + +#endif diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/features.h b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/features.h new file mode 100644 index 0000000..b72dfe7 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/features.h @@ -0,0 +1,333 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_UTIL_FEATURES_H +#define REALM_UTIL_FEATURES_H + +#ifdef _MSC_VER +#pragma warning(disable : 4800) // Visual Studio int->bool performance warnings +#endif + +#if defined(_WIN32) && !defined(NOMINMAX) +#define NOMINMAX +#endif + +#ifndef REALM_NO_CONFIG +#include +#endif + +/* The maximum number of elements in a B+-tree node. Applies to inner nodes and + * to leaves. The minimum allowable value is 2. + */ +#ifndef REALM_MAX_BPNODE_SIZE +#define REALM_MAX_BPNODE_SIZE 1000 +#endif + + +#define REALM_QUOTE_2(x) #x +#define REALM_QUOTE(x) REALM_QUOTE_2(x) + +/* See these links for information about feature check macroes in GCC, + * Clang, and MSVC: + * + * http://gcc.gnu.org/projects/cxx0x.html + * http://clang.llvm.org/cxx_status.html + * http://clang.llvm.org/docs/LanguageExtensions.html#checks-for-standard-language-features + * http://msdn.microsoft.com/en-us/library/vstudio/hh567368.aspx + * http://sourceforge.net/p/predef/wiki/Compilers + */ + + +/* Compiler is GCC and version is greater than or equal to the specified version */ +#define REALM_HAVE_AT_LEAST_GCC(maj, min) \ + (__GNUC__ > (maj) || __GNUC__ == (maj) && __GNUC_MINOR__ >= (min)) + +#if defined(__clang__) +#define REALM_HAVE_CLANG_FEATURE(feature) __has_feature(feature) +#define REALM_HAVE_CLANG_WARNING(warning) __has_warning(warning) +#else +#define REALM_HAVE_CLANG_FEATURE(feature) 0 +#define REALM_HAVE_CLANG_WARNING(warning) 0 +#endif + +#ifdef __has_cpp_attribute +#define REALM_HAS_CPP_ATTRIBUTE(attr) __has_cpp_attribute(attr) +#else +#define REALM_HAS_CPP_ATTRIBUTE(attr) 0 +#endif + +#if REALM_HAS_CPP_ATTRIBUTE(clang::fallthrough) +#define REALM_FALLTHROUGH [[clang::fallthrough]] +#elif REALM_HAS_CPP_ATTRIBUTE(gnu::fallthrough) +#define REALM_FALLTHROUGH [[gnu::fallthrough]] +#elif REALM_HAS_CPP_ATTRIBUTE(fallthrough) +#define REALM_FALLTHROUGH [[fallthrough]] +#else +#define REALM_FALLTHROUGH +#endif + +// This should be renamed to REALM_UNREACHABLE as soon as REALM_UNREACHABLE is renamed to +// REALM_ASSERT_NOT_REACHED which will better reflect its nature +#if defined(__GNUC__) || defined(__clang__) +#define REALM_COMPILER_HINT_UNREACHABLE __builtin_unreachable +#else +#define REALM_COMPILER_HINT_UNREACHABLE abort +#endif + +#if defined(__GNUC__) // clang or GCC +#define REALM_PRAGMA(v) _Pragma(REALM_QUOTE_2(v)) +#elif defined(_MSC_VER) // VS +#define REALM_PRAGMA(v) __pragma(v) +#else +#define REALM_PRAGMA(v) +#endif + +#if defined(__clang__) +#define REALM_DIAG(v) REALM_PRAGMA(clang diagnostic v) +#elif defined(__GNUC__) +#define REALM_DIAG(v) REALM_PRAGMA(GCC diagnostic v) +#else +#define REALM_DIAG(v) +#endif + +#define REALM_DIAG_PUSH() REALM_DIAG(push) +#define REALM_DIAG_POP() REALM_DIAG(pop) + +#ifdef _MSC_VER +#define REALM_VS_WARNING_DISABLE #pragma warning (default: 4297) +#endif + +#if REALM_HAVE_CLANG_WARNING("-Wtautological-compare") || REALM_HAVE_AT_LEAST_GCC(6, 0) +#define REALM_DIAG_IGNORE_TAUTOLOGICAL_COMPARE() REALM_DIAG(ignored "-Wtautological-compare") +#else +#define REALM_DIAG_IGNORE_TAUTOLOGICAL_COMPARE() +#endif + +#ifdef _MSC_VER +# define REALM_DIAG_IGNORE_UNSIGNED_MINUS() REALM_PRAGMA(warning(disable:4146)) +#else +#define REALM_DIAG_IGNORE_UNSIGNED_MINUS() +#endif + +/* Compiler is MSVC (Microsoft Visual C++) */ +#if defined(_MSC_VER) && _MSC_VER >= 1600 +#define REALM_HAVE_AT_LEAST_MSVC_10_2010 1 +#endif +#if defined(_MSC_VER) && _MSC_VER >= 1700 +#define REALM_HAVE_AT_LEAST_MSVC_11_2012 1 +#endif +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#define REALM_HAVE_AT_LEAST_MSVC_12_2013 1 +#endif + + +/* The way to specify that a function never returns. */ +#if REALM_HAVE_AT_LEAST_GCC(4, 8) || REALM_HAVE_CLANG_FEATURE(cxx_attributes) +#define REALM_NORETURN [[noreturn]] +#elif __GNUC__ +#define REALM_NORETURN __attribute__((noreturn)) +#elif defined(_MSC_VER) +#define REALM_NORETURN __declspec(noreturn) +#else +#define REALM_NORETURN +#endif + + +/* The way to specify that a variable or type is intended to possibly + * not be used. Use it to suppress a warning from the compiler. */ +#if __GNUC__ +#define REALM_UNUSED __attribute__((unused)) +#else +#define REALM_UNUSED +#endif + +/* The way to specify that a function is deprecated + * not be used. Use it to suppress a warning from the compiler. */ +#if __GNUC__ +#define REALM_DEPRECATED(x) [[deprecated(x)]] +#else +#define REALM_DEPRECATED(x) __declspec(deprecated(x)) +#endif + + +#if __GNUC__ || defined __INTEL_COMPILER +#define REALM_UNLIKELY(expr) __builtin_expect(!!(expr), 0) +#define REALM_LIKELY(expr) __builtin_expect(!!(expr), 1) +#else +#define REALM_UNLIKELY(expr) (expr) +#define REALM_LIKELY(expr) (expr) +#endif + + +#if defined(__GNUC__) || defined(__HP_aCC) +#define REALM_FORCEINLINE inline __attribute__((always_inline)) +#elif defined(_MSC_VER) +#define REALM_FORCEINLINE __forceinline +#else +#define REALM_FORCEINLINE inline +#endif + + +#if REALM_HAS_CPP_ATTRIBUTE(gnu::cold) +#define REALM_COLD [[gnu::cold]] +#else +#define REALM_COLD +#endif + + +#if REALM_HAS_CPP_ATTRIBUTE(gnu::noinline) +#define REALM_NOINLINE [[gnu::noinline]] +#elif defined(__GNUC__) || defined(__HP_aCC) +#define REALM_NOINLINE __attribute__((noinline)) +#elif defined(_MSC_VER) +#define REALM_NOINLINE __declspec(noinline) +#else +#define REALM_NOINLINE +#endif + + +// FIXME: Change this to use [[nodiscard]] in C++17. +#if defined(__GNUC__) || defined(__HP_aCC) +#define REALM_NODISCARD __attribute__((warn_unused_result)) +#elif defined(_MSC_VER) +#define REALM_NODISCARD _Check_return_ +#else +#define REALM_NODISCARD +#endif + + +/* Thread specific data (only for POD types) */ +#if defined __clang__ +#define REALM_THREAD_LOCAL __thread +#else +#define REALM_THREAD_LOCAL thread_local +#endif + + +#if defined ANDROID || defined __ANDROID_API__ +#define REALM_ANDROID 1 +#else +#define REALM_ANDROID 0 +#endif + +#if defined _WIN32 +#include +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) +#define REALM_WINDOWS 1 +#define REALM_UWP 0 +#elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) +#define REALM_WINDOWS 0 +#define REALM_UWP 1 +#endif +#else +#define REALM_WINDOWS 0 +#define REALM_UWP 0 +#endif + +// Some documentation of the defines provided by Apple: +// http://developer.apple.com/library/mac/documentation/Porting/Conceptual/PortingUnix/compiling/compiling.html#//apple_ref/doc/uid/TP40002850-SW13 +#if defined __APPLE__ && defined __MACH__ +#define REALM_PLATFORM_APPLE 1 +/* Apple OSX and iOS (Darwin). */ +#include +#include +#if TARGET_OS_IPHONE == 1 && TARGET_OS_IOS == 1 +/* Device (iPhone or iPad) or simulator. */ +#define REALM_IOS 1 +#define REALM_IOS_DEVICE !TARGET_OS_SIMULATOR +#else +#define REALM_IOS 0 +#define REALM_IOS_DEVICE 0 +#endif +#if TARGET_OS_WATCH == 1 +/* Device (Apple Watch) or simulator. */ +#define REALM_WATCHOS 1 +#else +#define REALM_WATCHOS 0 +#endif +#if TARGET_OS_TV +/* Device (Apple TV) or simulator. */ +#define REALM_TVOS 1 +#else +#define REALM_TVOS 0 +#endif +#else +#define REALM_PLATFORM_APPLE 0 +#define REALM_IOS 0 +#define REALM_IOS_DEVICE 0 +#define REALM_WATCHOS 0 +#define REALM_TVOS 0 +#endif + +#if REALM_ANDROID || REALM_IOS || REALM_WATCHOS || REALM_TVOS || REALM_UWP +#define REALM_MOBILE 1 +#else +#define REALM_MOBILE 0 +#endif + + +#if defined(REALM_DEBUG) && !defined(REALM_COOKIE_CHECK) +#define REALM_COOKIE_CHECK +#endif + +#if !REALM_IOS && !REALM_WATCHOS && !REALM_TVOS && !defined(_WIN32) && !REALM_ANDROID +// #define REALM_ASYNC_DAEMON FIXME Async commits not supported +#endif + +// We're in i686 mode +#if defined(__i386) || defined(__i386__) || defined(__i686__) || defined(_M_I86) || defined(_M_IX86) +#define REALM_ARCHITECTURE_X86_32 1 +#else +#define REALM_ARCHITECTURE_X86_32 0 +#endif + +// We're in amd64 mode +#if defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \ + defined(_M_AMD64) +#define REALM_ARCHITECTURE_X86_64 1 +#else +#define REALM_ARCHITECTURE_X86_64 0 +#endif + +// Address Sanitizer +#if defined(__has_feature) // Clang +# if __has_feature(address_sanitizer) +# define REALM_SANITIZE_ADDRESS 1 +# else +# define REALM_SANITIZE_ADDRESS 0 +# endif +#elif defined(__SANITIZE_ADDRESS__) && __SANITIZE_ADDRESS__ // GCC +# define REALM_SANITIZE_ADDRESS 1 +#else +# define REALM_SANITIZE_ADDRESS 0 +#endif + +// Thread Sanitizer +#if defined(__has_feature) // Clang +# if __has_feature(thread_sanitizer) +# define REALM_SANITIZE_THREAD 1 +# else +# define REALM_SANITIZE_THREAD 0 +# endif +#elif defined(__SANITIZE_THREAD__) && __SANITIZE_THREAD__ // GCC +# define REALM_SANITIZE_THREAD 1 +#else +# define REALM_SANITIZE_THREAD 0 +#endif + +#endif /* REALM_UTIL_FEATURES_H */ diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/fifo_helper.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/fifo_helper.hpp new file mode 100644 index 0000000..6ca8d75 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/fifo_helper.hpp @@ -0,0 +1,43 @@ +/************************************************************************* + * + * Copyright 2019 Realm Inc. + * + * 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 REALM_UTIL_FIFO_HELPER_HPP +#define REALM_UTIL_FIFO_HELPER_HPP + +#include + +namespace realm { +namespace util { + +// Attempts to create a FIFO file at the location determined by `path`. +// If creating the FIFO at this location fails, an exception is thrown. +// If a FIFO already exists at the given location, this method does nothing. +void create_fifo(std::string path); // throws + +// Same as above, but returns `false` if the FIFO could not be created instead of throwing. +bool try_create_fifo(const std::string& path); + +// Ensure that a path representing a directory ends with `/` +inline std::string normalize_dir(const std::string& path) { + return (!path.empty() && path.back() != '/') ? path + '/' : path; +} + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_FIFO_HELPER_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/file.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/file.hpp new file mode 100644 index 0000000..d3e9489 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/file.hpp @@ -0,0 +1,1348 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_UTIL_FILE_HPP +#define REALM_UTIL_FILE_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef _WIN32 +#include // POSIX.1-2001 +#endif + +#include +#include +#include +#include +#include +#include + +#if defined(_MSVC_LANG) && _MSVC_LANG >= 201703L // compiling with MSVC and C++ 17 +#include +#define REALM_HAVE_STD_FILESYSTEM 1 +#if REALM_UWP +// workaround for linker issue described in https://github.com/microsoft/STL/issues/322 +// remove once the Windows SDK or STL fixes this. +#pragma comment(lib, "onecoreuap.lib") +#endif +#else +#define REALM_HAVE_STD_FILESYSTEM 0 +#endif + +#if REALM_IOS_DEVICE +#define REALM_FILELOCK_EMULATION +#endif + +namespace realm { +namespace util { + +class EncryptedFileMapping; + +/// Create the specified directory in the file system. +/// +/// \throw File::AccessError If the directory could not be created. If +/// the reason corresponds to one of the exception types that are +/// derived from File::AccessError, the derived exception type is +/// thrown (as long as the underlying system provides the information +/// to unambiguously distinguish that particular reason). +void make_dir(const std::string& path); + +/// Same as make_dir() except that this one returns false, rather than throwing +/// an exception, if the specified directory already existed. If the directory +// did not already exist and was newly created, this returns true. +bool try_make_dir(const std::string& path); + +/// Remove the specified empty directory path from the file system. It is an +/// error if the specified path is not a directory, or if it is a nonempty +/// directory. In so far as the specified path is a directory, std::remove(const +/// char*) is equivalent to this function. +/// +/// \throw File::AccessError If the directory could not be removed. If the +/// reason corresponds to one of the exception types that are derived from +/// File::AccessError, the derived exception type is thrown (as long as the +/// underlying system provides the information to unambiguously distinguish that +/// particular reason). +void remove_dir(const std::string& path); + +/// Same as remove_dir() except that this one returns false, rather +/// than throwing an exception, if the specified directory did not +/// exist. If the directory did exist, and was deleted, this function +/// returns true. +bool try_remove_dir(const std::string& path); + +/// Remove the specified directory after removing all its contents. Files +/// (nondirectory entries) will be removed as if by a call to File::remove(), +/// and empty directories as if by a call to remove_dir(). +/// +/// \throw File::AccessError If removal of the directory, or any of its contents +/// fail. +/// +/// remove_dir_recursive() assumes that no other process or thread is making +/// simultaneous changes in the directory. +void remove_dir_recursive(const std::string& path); + +/// Same as remove_dir_recursive() except that this one returns false, rather +/// than throwing an exception, if the specified directory did not +/// exist. If the directory did exist, and was deleted, this function +/// returns true. +/// +/// try_remove_dir_recursive() assumes that no other process or thread is making +/// simultaneous changes in the directory. +bool try_remove_dir_recursive(const std::string& path); + +/// Create a new unique directory for temporary files. The absolute +/// path to the new directory is returned without a trailing slash. +std::string make_temp_dir(); + +size_t page_size(); + + +/// This class provides a RAII abstraction over the concept of a file +/// descriptor (or file handle). +/// +/// Locks are automatically and immediately released when the File +/// instance is closed. +/// +/// You can use CloseGuard and UnlockGuard to acheive exception-safe +/// closing or unlocking prior to the File instance being detroyed. +/// +/// A single File instance must never be accessed concurrently by +/// multiple threads. +/// +/// You can write to a file via an std::ostream as follows: +/// +/// \code{.cpp} +/// +/// File::Streambuf my_streambuf(&my_file); +/// std::ostream out(&my_strerambuf); +/// out << 7945.9; +/// +/// \endcode +class File { +public: + enum Mode { + mode_Read, ///< access_ReadOnly, create_Never (fopen: rb) + mode_Update, ///< access_ReadWrite, create_Never (fopen: rb+) + mode_Write, ///< access_ReadWrite, create_Auto, flag_Trunc (fopen: wb+) + mode_Append ///< access_ReadWrite, create_Auto, flag_Append (fopen: ab+) + }; + + /// Equivalent to calling open(const std::string&, Mode) on a + /// default constructed instance. + explicit File(const std::string& path, Mode = mode_Read); + + /// Create an instance that is not initially attached to an open + /// file. + File() = default; + ~File() noexcept; + + File(File&&) noexcept; + File& operator=(File&&) noexcept; + + // Disable copying by l-value. Copying an open file will create a scenario + // where the same file descriptor will be opened once but closed twice. + File(const File&) = delete; + File& operator=(const File&) = delete; + + /// Calling this function on an instance that is already attached + /// to an open file has undefined behavior. + /// + /// \throw AccessError If the file could not be opened. If the + /// reason corresponds to one of the exception types that are + /// derived from AccessError, the derived exception type is thrown + /// (as long as the underlying system provides the information to + /// unambiguously distinguish that particular reason). + void open(const std::string& path, Mode = mode_Read); + + /// This function is idempotent, that is, it is valid to call it + /// regardless of whether this instance currently is attached to + /// an open file. + void close() noexcept; + + /// Check whether this File instance is currently attached to an + /// open file. + bool is_attached() const noexcept; + + enum AccessMode { + access_ReadOnly, + access_ReadWrite, + }; + + enum CreateMode { + create_Auto, ///< Create the file if it does not already exist. + create_Never, ///< Fail if the file does not already exist. + create_Must ///< Fail if the file already exists. + }; + + enum { + flag_Trunc = 1, ///< Truncate the file if it already exists. + flag_Append = 2 ///< Move to end of file before each write. + }; + + /// See open(const std::string&, Mode). + /// + /// Specifying access_ReadOnly together with a create mode that is + /// not create_Never, or together with a non-zero \a flags + /// argument, results in undefined behavior. Specifying flag_Trunc + /// together with create_Must results in undefined behavior. + void open(const std::string& path, AccessMode, CreateMode, int flags); + + /// Same as open(path, access_ReadWrite, create_Auto, 0), except + /// that this one returns an indication of whether a new file was + /// created, or an existing file was opened. + void open(const std::string& path, bool& was_created); + + /// Read data into the specified buffer and return the number of + /// bytes read. If the returned number of bytes is less than \a + /// size, then the end of the file has been reached. + /// + /// Calling this function on an instance, that is not currently + /// attached to an open file, has undefined behavior. + size_t read(char* data, size_t size); + static size_t read_static(FileDesc fd, char* data, size_t size); + + /// Write the specified data to this file. + /// + /// Calling this function on an instance, that is not currently + /// attached to an open file, has undefined behavior. + /// + /// Calling this function on an instance, that was opened in + /// read-only mode, has undefined behavior. + void write(const char* data, size_t size); + static void write_static(FileDesc fd, const char* data, size_t size); + + // Tells current file pointer of fd + static uint64_t get_file_pos(FileDesc fd); + + /// Calls write(s.data(), s.size()). + void write(const std::string& s) + { + write(s.data(), s.size()); + } + + /// Calls read(data, N). + template + size_t read(char (&data)[N]) + { + return read(data, N); + } + + /// Calls write(data(), N). + template + void write(const char (&data)[N]) + { + write(data, N); + } + + /// Plays the same role as off_t in POSIX + typedef int_fast64_t SizeType; + + /// Calling this function on an instance that is not attached to + /// an open file has undefined behavior. + SizeType get_size() const; + static SizeType get_size_static(FileDesc fd); + + /// If this causes the file to grow, then the new section will + /// have undefined contents. Setting the size with this function + /// does not necessarily allocate space on the target device. If + /// you want to ensure allocation, call alloc(). Calling this + /// function will generally affect the read/write offset + /// associated with this File instance. + /// + /// Calling this function on an instance that is not attached to + /// an open file has undefined behavior. Calling this function on + /// a file that is opened in read-only mode, is an error. + void resize(SizeType); + + /// Same effect as prealloc_if_supported(original_size, new_size); + /// + /// The downside is that this function is not guaranteed to have + /// atomic behaviour on all systems, that is, two processes, or + /// two threads should never call this function concurrently for + /// the same underlying file even though they access the file + /// through distinct File instances. + /// + /// \sa prealloc_if_supported() + void prealloc(size_t new_size); + + /// When supported by the system, allocate space on the target + /// device for the specified region of the file. If the region + /// extends beyond the current end of the file, the file size is + /// increased as necessary. + /// + /// On systems that do not support this operation, this function + /// has no effect. You may call is_prealloc_supported() to + /// determine if it is supported on your system. + /// + /// Calling this function on an instance, that is not attached to + /// an open file, has undefined behavior. Calling this function on + /// a file, that is opened in read-only mode, is an error. + /// + /// This function is guaranteed to have atomic behaviour, that is, + /// there is never any risk of the file size being reduced even + /// with concurrently executing invocations. + /// + /// \sa prealloc() + /// \sa is_prealloc_supported() + bool prealloc_if_supported(SizeType offset, size_t size); + + /// See prealloc_if_supported(). + static bool is_prealloc_supported(); + + /// Reposition the read/write offset of this File + /// instance. Distinct File instances have separate independent + /// offsets, as long as the cucrrent process is not forked. + void seek(SizeType); + static void seek_static(FileDesc, SizeType); + + /// Flush in-kernel buffers to disk. This blocks the caller until the + /// synchronization operation is complete. On POSIX systems this function + /// calls `fsync()`. On Apple platforms if calls `fcntl()` with command + /// `F_FULLFSYNC`. + void sync(); + + /// Place an exclusive lock on this file. This blocks the caller + /// until all other locks have been released. + /// + /// Locks acquired on distinct File instances have fully recursive + /// behavior, even if they are acquired in the same process (or + /// thread) and are attached to the same underlying file. + /// + /// Calling this function on an instance that is not attached to + /// an open file, or on an instance that is already locked has + /// undefined behavior. + void lock_exclusive(); + + /// Place an shared lock on this file. This blocks the caller + /// until all other exclusive locks have been released. + /// + /// Locks acquired on distinct File instances have fully recursive + /// behavior, even if they are acquired in the same process (or + /// thread) and are attached to the same underlying file. + /// + /// Calling this function on an instance that is not attached to + /// an open file, or on an instance that is already locked has + /// undefined behavior. + void lock_shared(); + + /// Non-blocking version of lock_exclusive(). Returns true iff it + /// succeeds. + bool try_lock_exclusive(); + + /// Non-blocking version of lock_shared(). Returns true iff it + /// succeeds. + bool try_lock_shared(); + + /// Release a previously acquired lock on this file. This function + /// is idempotent. + void unlock() noexcept; + + /// Set the encryption key used for this file. Must be called before any + /// mappings are created or any data is read from or written to the file. + /// + /// \param key A 64-byte encryption key, or null to disable encryption. + void set_encryption_key(const char* key); + + /// Get the encryption key set by set_encryption_key(), + /// null_ptr if no key set. + const char* get_encryption_key() const; + + /// Set the path used for emulating file locks. If not set explicitly, + /// the emulation will use the path of the file itself suffixed by ".fifo" + void set_fifo_path(const std::string& fifo_path); + enum { + /// If possible, disable opportunistic flushing of dirted + /// pages of a memory mapped file to physical medium. On some + /// systems this cannot be disabled. On other systems it is + /// the default behavior. An explicit call to sync_map() will + /// flush the buffers regardless of whether this flag is + /// specified or not. + map_NoSync = 1 + }; + + /// Map this file into memory. The file is mapped as shared + /// memory. This allows two processes to interact under exatly the + /// same rules as applies to the interaction via regular memory of + /// multiple threads inside a single process. + /// + /// This File instance does not need to remain in existence after + /// the mapping is established. + /// + /// Multiple concurrent mappings may be created from the same File + /// instance. + /// + /// Specifying access_ReadWrite for a file that is opened in + /// read-only mode, is an error. + /// + /// Calling this function on an instance that is not attached to + /// an open file, or one that is attached to an empty file has + /// undefined behavior. + /// + /// Calling this function with a size that is greater than the + /// size of the file has undefined behavior. + void* map(AccessMode, size_t size, int map_flags = 0, size_t offset = 0) const; + void* map_fixed(AccessMode, void* address, size_t size, int map_flags = 0, size_t offset = 0) const; + void* map_reserve(AccessMode, size_t size, size_t offset) const; + /// The same as unmap(old_addr, old_size) followed by map(a, + /// new_size, map_flags), but more efficient on some systems. + /// + /// The old address range must have been acquired by a call to + /// map() or remap() on this File instance, the specified access + /// mode and flags must be the same as the ones specified + /// previously, and this File instance must not have been reopend + /// in the meantime. Failing to adhere to these rules will result + /// in undefined behavior. + /// + /// If this function throws, the old address range will remain + /// mapped. + void* remap(void* old_addr, size_t old_size, AccessMode a, size_t new_size, int map_flags = 0, + size_t file_offset = 0) const; + +#if REALM_ENABLE_ENCRYPTION + void* map(AccessMode, size_t size, EncryptedFileMapping*& mapping, int map_flags = 0, size_t offset = 0) const; + void* map_fixed(AccessMode, void* address, size_t size, EncryptedFileMapping* mapping, int map_flags = 0, + size_t offset = 0) const; + void* map_reserve(AccessMode, size_t size, size_t offset, EncryptedFileMapping*& mapping) const; +#endif + /// Unmap the specified address range which must have been + /// previously returned by map(). + static void unmap(void* addr, size_t size) noexcept; + + /// Flush in-kernel buffers to disk. This blocks the caller until + /// the synchronization operation is complete. The specified + /// address range must be (a subset of) one that was previously returned by + /// map(). + static void sync_map(FileDesc fd, void* addr, size_t size); + + /// Check whether the specified file or directory exists. Note + /// that a file or directory that resides in a directory that the + /// calling process has no access to, will necessarily be reported + /// as not existing. + static bool exists(const std::string& path); + + /// Check whether the specified path exists and refers to a directory. If + /// the referenced file system object resides in an inaccessible directory, + /// this function returns false. + static bool is_dir(const std::string& path); + + /// Remove the specified file path from the file system. It is an error if + /// the specified path is a directory. If the specified file is a symbolic + /// link, the link is removed, leaving the liked file intact. In so far as + /// the specified path is not a directory, std::remove(const char*) is + /// equivalent to this function. + /// + /// The specified file must not be open by the calling process. If + /// it is, this function has undefined behaviour. Note that an + /// open memory map of the file counts as "the file being open". + /// + /// \throw AccessError If the specified directory entry could not + /// be removed. If the reason corresponds to one of the exception + /// types that are derived from AccessError, the derived exception + /// type is thrown (as long as the underlying system provides the + /// information to unambiguously distinguish that particular + /// reason). + static void remove(const std::string& path); + + /// Same as remove() except that this one returns false, rather + /// than throwing an exception, if the specified file does not + /// exist. If the file did exist, and was deleted, this function + /// returns true. + static bool try_remove(const std::string& path); + + /// Change the path of a directory entry. This can be used to + /// rename a file, and/or to move it from one directory to + /// another. This function is equivalent to std::rename(const + /// char*, const char*). + /// + /// \throw AccessError If the path of the directory entry could + /// not be changed. If the reason corresponds to one of the + /// exception types that are derived from AccessError, the derived + /// exception type is thrown (as long as the underlying system + /// provides the information to unambiguously distinguish that + /// particular reason). + static void move(const std::string& old_path, const std::string& new_path); + + /// Copy the file at the specified origin path to the specified target path. + static void copy(const std::string& origin_path, const std::string& target_path); + + /// Compare the two files at the specified paths for equality. Returns true + /// if, and only if they are equal. + static bool compare(const std::string& path_1, const std::string& path_2); + + /// Check whether two open file descriptors refer to the same + /// underlying file, that is, if writing via one of them, will + /// affect what is read from the other. In UNIX this boils down to + /// comparing inode numbers. + /// + /// Both instances have to be attached to open files. If they are + /// not, this function has undefined behavior. + bool is_same_file(const File&) const; + static bool is_same_file_static(FileDesc f1, FileDesc f2); + + // FIXME: Get rid of this method + bool is_removed() const; + + /// Resolve the specified path against the specified base directory. + /// + /// If \a path is absolute, or if \a base_dir is empty, \p path is returned + /// unmodified, otherwise \a path is resolved against \a base_dir. + /// + /// Examples (assuming POSIX): + /// + /// resolve("file", "dir") -> "dir/file" + /// resolve("../baz", "/foo/bar") -> "/foo/baz" + /// resolve("foo", ".") -> "./foo" + /// resolve(".", "/foo/") -> "/foo" + /// resolve("..", "foo") -> "." + /// resolve("../..", "foo") -> ".." + /// resolve("..", "..") -> "../.." + /// resolve("", "") -> "." + /// resolve("", "/") -> "/." + /// resolve("..", "/") -> "/." + /// resolve("..", "foo//bar") -> "foo" + /// + /// This function does not access the file system. + /// + /// \param path The path to be resolved. An empty string produces the same + /// result as as if "." was passed. The result has a trailing directory + /// separator (`/`) if, and only if this path has a trailing directory + /// separator. + /// + /// \param base_dir The base directory path, which may be relative or + /// absolute. A final directory separator (`/`) is optional. The empty + /// string is interpreted as a relative path. + static std::string resolve(const std::string& path, const std::string& base_dir); + + using ForEachHandler = util::FunctionRef; + + /// Scan the specified directory recursivle, and report each file + /// (nondirectory entry) via the specified handler. + /// + /// The first argument passed to the handler is the name of a file (not the + /// whole path), and the second argument is the directory in which that file + /// resides. The directory will be specified as a path, and relative to \a + /// dir_path. The directory will be the empty string for files residing + /// directly in \a dir_path. + /// + /// If the handler returns false, scanning will be aborted immediately, and + /// for_each() will return false. Otherwise for_each() will return true. + /// + /// Scanning is done as if by a recursive set of DirScanner objects. + static bool for_each(const std::string& dir_path, ForEachHandler handler); + + struct UniqueID { +#ifdef _WIN32 // Windows version +// FIXME: This is not implemented for Windows +#else + UniqueID() + : device(0) + , inode(0) + { + } + UniqueID(dev_t d, ino_t i) + : device(d) + , inode(i) + { + } + // NDK r10e has a bug in sys/stat.h dev_t ino_t are 4 bytes, + // but stat.st_dev and st_ino are 8 bytes. So we just use uint64 instead. + dev_t device; + uint_fast64_t inode; +#endif + }; + // Return the unique id for the current opened file descriptor. + // Same UniqueID means they are the same file. + UniqueID get_unique_id() const; + // Return the file descriptor for the file + FileDesc get_descriptor() const; + // Return the path of the open file, or an empty string if + // this file has never been opened. + std::string get_path() const; + // Return false if the file doesn't exist. Otherwise uid will be set. + static bool get_unique_id(const std::string& path, UniqueID& uid); + + class ExclusiveLock; + class SharedLock; + + template + class Map; + + class CloseGuard; + class UnlockGuard; + class UnmapGuard; + + class Streambuf; + + // Exceptions + class AccessError; + class PermissionDenied; + class NotFound; + class Exists; + +private: +#ifdef _WIN32 + void* m_fd = nullptr; + bool m_have_lock = false; // Only valid when m_fd is not null +#else + int m_fd = -1; +#ifdef REALM_FILELOCK_EMULATION + int m_pipe_fd = -1; // -1 if no pipe has been allocated for emulation + bool m_has_exclusive_lock = false; + std::string m_fifo_path; +#endif +#endif + std::unique_ptr m_encryption_key = nullptr; + std::string m_path; + + bool lock(bool exclusive, bool non_blocking); + void open_internal(const std::string& path, AccessMode, CreateMode, int flags, bool* success); + +#ifdef REALM_FILELOCK_EMULATION + bool has_shared_lock() const noexcept + { + return m_pipe_fd != -1; + } +#endif + + struct MapBase { + void* m_addr = nullptr; + mutable size_t m_size = 0; + size_t m_offset = 0; + FileDesc m_fd; + + MapBase() noexcept; + ~MapBase() noexcept; + + // Disable copying. Copying an opened MapBase will create a scenario + // where the same memory will be mapped once but unmapped twice. + MapBase(const MapBase&) = delete; + MapBase& operator=(const MapBase&) = delete; + + // Use + void map(const File&, AccessMode, size_t size, int map_flags, size_t offset = 0); + void remap(const File&, AccessMode, size_t size, int map_flags); + void unmap() noexcept; + void sync(); +#if REALM_ENABLE_ENCRYPTION + mutable util::EncryptedFileMapping* m_encrypted_mapping = nullptr; + inline util::EncryptedFileMapping* get_encrypted_mapping() const + { + return m_encrypted_mapping; + } +#else + inline util::EncryptedFileMapping* get_encrypted_mapping() const + { + return nullptr; + } +#endif + }; +}; + + +class File::ExclusiveLock { +public: + ExclusiveLock(File& f) + : m_file(f) + { + f.lock_exclusive(); + } + ~ExclusiveLock() noexcept + { + m_file.unlock(); + } + // Disable copying. It is not how this class should be used. + ExclusiveLock(const ExclusiveLock&) = delete; + ExclusiveLock& operator=(const ExclusiveLock&) = delete; + +private: + File& m_file; +}; + +class File::SharedLock { +public: + SharedLock(File& f) + : m_file(f) + { + f.lock_shared(); + } + ~SharedLock() noexcept + { + m_file.unlock(); + } + // Disable copying. It is not how this class should be used. + SharedLock(const SharedLock&) = delete; + SharedLock& operator=(const SharedLock&) = delete; + +private: + File& m_file; +}; + + +/// This class provides a RAII abstraction over the concept of a +/// memory mapped file. +/// +/// Once created, the Map instance makes no reference to the File +/// instance that it was based upon, and that File instance may be +/// destroyed before the Map instance is destroyed. +/// +/// Multiple concurrent mappings may be created from the same File +/// instance. +/// +/// You can use UnmapGuard to acheive exception-safe unmapping prior +/// to the Map instance being detroyed. +/// +/// A single Map instance must never be accessed concurrently by +/// multiple threads. +template +class File::Map : private MapBase { +public: + /// Equivalent to calling map() on a default constructed instance. + explicit Map(const File&, AccessMode = access_ReadOnly, size_t size = sizeof(T), int map_flags = 0); + + explicit Map(const File&, size_t offset, AccessMode = access_ReadOnly, size_t size = sizeof(T), + int map_flags = 0); + + /// Create an instance that is not initially attached to a memory + /// mapped file. + Map() noexcept; + + ~Map() noexcept; + + // Disable copying. Copying an opened Map will create a scenario + // where the same memory will be mapped once but unmapped twice. + Map(const Map&) = delete; + Map& operator=(const Map&) = delete; + + /// Move the mapping from another Map object to this Map object + File::Map& operator=(File::Map&& other) noexcept + { + if (m_addr) + unmap(); + m_addr = other.get_addr(); + m_size = other.m_size; + m_offset = other.m_offset; + m_fd = other.m_fd; + other.m_offset = 0; + other.m_addr = nullptr; + other.m_size = 0; +#if REALM_ENABLE_ENCRYPTION + m_encrypted_mapping = other.m_encrypted_mapping; + other.m_encrypted_mapping = nullptr; +#endif + return *this; + } + Map(Map&& other) noexcept + { + *this = std::move(other); + } + + /// See File::map(). + /// + /// Calling this function on a Map instance that is already + /// attached to a memory mapped file has undefined behavior. The + /// returned pointer is the same as what will subsequently be + /// returned by get_addr(). + T* map(const File&, AccessMode = access_ReadOnly, size_t size = sizeof(T), int map_flags = 0, size_t offset = 0); + + /// See File::unmap(). This function is idempotent, that is, it is + /// valid to call it regardless of whether this instance is + /// currently attached to a memory mapped file. + void unmap() noexcept; + + /// See File::remap(). + /// + /// Calling this function on a Map instance that is not currently + /// attached to a memory mapped file has undefined behavior. The + /// returned pointer is the same as what will subsequently be + /// returned by get_addr(). + T* remap(const File&, AccessMode = access_ReadOnly, size_t size = sizeof(T), int map_flags = 0); + + /// See File::sync_map(). + /// + /// Calling this function on an instance that is not currently + /// attached to a memory mapped file, has undefined behavior. + void sync(); + + /// Check whether this Map instance is currently attached to a + /// memory mapped file. + bool is_attached() const noexcept; + + /// Returns a pointer to the beginning of the memory mapped file, + /// or null if this instance is not currently attached. + T* get_addr() const noexcept; + + /// Returns the size of the mapped region, or zero if this + /// instance does not currently refer to a memory mapped + /// file. When this instance refers to a memory mapped file, the + /// returned value will always be identical to the size passed to + /// the constructor or to map(). + size_t get_size() const noexcept; + + /// Release the currently attached memory mapped file from this + /// Map instance. The address range may then be unmapped later by + /// a call to File::unmap(). + T* release() noexcept; + +#if REALM_ENABLE_ENCRYPTION + /// Get the encrypted file mapping corresponding to this mapping + inline EncryptedFileMapping* get_encrypted_mapping() const + { + return m_encrypted_mapping; + } +#else + inline EncryptedFileMapping* get_encrypted_mapping() const + { + return nullptr; + } +#endif + + friend class UnmapGuard; +}; + + +class File::CloseGuard { +public: + CloseGuard(File& f) noexcept + : m_file(&f) + { + } + ~CloseGuard() noexcept + { + if (m_file) + m_file->close(); + } + void release() noexcept + { + m_file = nullptr; + } + // Disallow the default implementation of copy/assign, this is not how this + // class is intended to be used. For example we could get unexpected + // behaviour if one CloseGuard is copied and released but the other is not. + CloseGuard(const CloseGuard&) = delete; + CloseGuard& operator=(const CloseGuard&) = delete; + +private: + File* m_file; +}; + + +class File::UnlockGuard { +public: + UnlockGuard(File& f) noexcept + : m_file(&f) + { + } + ~UnlockGuard() noexcept + { + if (m_file) + m_file->unlock(); + } + void release() noexcept + { + m_file = nullptr; + } + // Disallow the default implementation of copy/assign, this is not how this + // class is intended to be used. For example we could get unexpected + // behaviour if one UnlockGuard is copied and released but the other is not. + UnlockGuard(const UnlockGuard&) = delete; + UnlockGuard& operator=(const UnlockGuard&) = delete; + +private: + File* m_file; +}; + + +class File::UnmapGuard { +public: + template + UnmapGuard(Map& m) noexcept + : m_map(&m) + { + } + ~UnmapGuard() noexcept + { + if (m_map) + m_map->unmap(); + } + void release() noexcept + { + m_map = nullptr; + } + // Disallow the default implementation of copy/assign, this is not how this + // class is intended to be used. For example we could get unexpected + // behaviour if one UnmapGuard is copied and released but the other is not. + UnmapGuard(const UnmapGuard&) = delete; + UnmapGuard& operator=(const UnmapGuard&) = delete; + +private: + MapBase* m_map; +}; + + +/// Only output is supported at this point. +class File::Streambuf : public std::streambuf { +public: + explicit Streambuf(File*, size_t = 4096); + ~Streambuf() noexcept; + + // Disable copying + Streambuf(const Streambuf&) = delete; + Streambuf& operator=(const Streambuf&) = delete; + +private: + File& m_file; + std::unique_ptr const m_buffer; + + int_type overflow(int_type) override; + int sync() override; + pos_type seekpos(pos_type, std::ios_base::openmode) override; + void flush(); +}; + +/// Used for any I/O related exception. Note the derived exception +/// types that are used for various specific types of errors. +class File::AccessError : public ExceptionWithBacktrace { +public: + AccessError(const std::string& msg, const std::string& path); + + /// Return the associated file system path, or the empty string if there is + /// no associated file system path, or if the file system path is unknown. + const std::string& get_path() const; + + void set_path(std::string path) + { + m_path = std::move(path); + } + + const char* message() const noexcept + { + m_buffer = std::runtime_error::what(); + if (m_path.size() > 0) + m_buffer += (std::string(" Path: ") + m_path); + return m_buffer.c_str(); + } + +private: + std::string m_path; + mutable std::string m_buffer; +}; + + +/// Thrown if the user does not have permission to open or create +/// the specified file in the specified access mode. +class File::PermissionDenied : public AccessError { +public: + PermissionDenied(const std::string& msg, const std::string& path); +}; + + +/// Thrown if the directory part of the specified path was not +/// found, or create_Never was specified and the file did no +/// exist. +class File::NotFound : public AccessError { +public: + NotFound(const std::string& msg, const std::string& path); +}; + + +/// Thrown if create_Always was specified and the file did already +/// exist. +class File::Exists : public AccessError { +public: + Exists(const std::string& msg, const std::string& path); +}; + + +class DirScanner { +public: + DirScanner(const std::string& path, bool allow_missing = false); + ~DirScanner() noexcept; + bool next(std::string& name); + +private: +#ifndef _WIN32 + DIR* m_dirp; +#elif REALM_HAVE_STD_FILESYSTEM + std::filesystem::directory_iterator m_iterator; +#endif +}; + + +// Implementation: + +inline File::File(const std::string& path, Mode m) +{ + open(path, m); +} + +inline File::~File() noexcept +{ + close(); +} + +inline void File::set_fifo_path(const std::string& fifo_path) +{ +#ifdef REALM_FILELOCK_EMULATION + m_fifo_path = fifo_path; +#else + static_cast(fifo_path); +#endif +} + +inline File::File(File&& f) noexcept +{ +#ifdef _WIN32 + m_fd = f.m_fd; + m_have_lock = f.m_have_lock; + f.m_fd = nullptr; +#else + m_fd = f.m_fd; +#ifdef REALM_FILELOCK_EMULATION + m_pipe_fd = f.m_pipe_fd; + m_has_exclusive_lock = f.m_has_exclusive_lock; + f.m_has_exclusive_lock = false; + f.m_pipe_fd = -1; +#endif + f.m_fd = -1; +#endif + m_encryption_key = std::move(f.m_encryption_key); +} + +inline File& File::operator=(File&& f) noexcept +{ + close(); +#ifdef _WIN32 + m_fd = f.m_fd; + m_have_lock = f.m_have_lock; + f.m_fd = nullptr; +#else + m_fd = f.m_fd; + f.m_fd = -1; +#ifdef REALM_FILELOCK_EMULATION + m_pipe_fd = f.m_pipe_fd; + f.m_pipe_fd = -1; + m_has_exclusive_lock = f.m_has_exclusive_lock; + f.m_has_exclusive_lock = false; +#endif +#endif + m_encryption_key = std::move(f.m_encryption_key); + return *this; +} + +inline void File::open(const std::string& path, Mode m) +{ + AccessMode a = access_ReadWrite; + CreateMode c = create_Auto; + int flags = 0; + switch (m) { + case mode_Read: + a = access_ReadOnly; + c = create_Never; + break; + case mode_Update: + c = create_Never; + break; + case mode_Write: + flags = flag_Trunc; + break; + case mode_Append: + flags = flag_Append; + break; + } + open(path, a, c, flags); +} + +inline void File::open(const std::string& path, AccessMode am, CreateMode cm, int flags) +{ + open_internal(path, am, cm, flags, nullptr); +} + + +inline void File::open(const std::string& path, bool& was_created) +{ + while (1) { + bool success; + open_internal(path, access_ReadWrite, create_Must, 0, &success); + if (success) { + was_created = true; + return; + } + open_internal(path, access_ReadWrite, create_Never, 0, &success); + if (success) { + was_created = false; + return; + } + } +} + +inline bool File::is_attached() const noexcept +{ +#ifdef _WIN32 + return (m_fd != nullptr); +#else + return 0 <= m_fd; +#endif +} + +inline void File::lock_exclusive() +{ + lock(true, false); +} + +inline void File::lock_shared() +{ + lock(false, false); +} + +inline bool File::try_lock_exclusive() +{ + return lock(true, true); +} + +inline bool File::try_lock_shared() +{ + return lock(false, true); +} + +inline File::MapBase::MapBase() noexcept +{ + m_addr = nullptr; + m_size = 0; +} + +inline File::MapBase::~MapBase() noexcept +{ + unmap(); +} + + +template +inline File::Map::Map(const File& f, AccessMode a, size_t size, int map_flags) +{ + map(f, a, size, map_flags); +} + +template +inline File::Map::Map(const File& f, size_t offset, AccessMode a, size_t size, int map_flags) +{ + map(f, a, size, map_flags, offset); +} + +template +inline File::Map::Map() noexcept +{ +} + +template +inline File::Map::~Map() noexcept +{ +} + +template +inline T* File::Map::map(const File& f, AccessMode a, size_t size, int map_flags, size_t offset) +{ + MapBase::map(f, a, size, map_flags, offset); + return static_cast(m_addr); +} + +template +inline void File::Map::unmap() noexcept +{ + MapBase::unmap(); +} + +template +inline T* File::Map::remap(const File& f, AccessMode a, size_t size, int map_flags) +{ + //MapBase::remap(f, a, size, map_flags); + // missing sync() here? + unmap(); + map(f, a, size, map_flags); + + return static_cast(m_addr); +} + +template +inline void File::Map::sync() +{ + MapBase::sync(); +} + +template +inline bool File::Map::is_attached() const noexcept +{ + return (m_addr != nullptr); +} + +template +inline T* File::Map::get_addr() const noexcept +{ + return static_cast(m_addr); +} + +template +inline size_t File::Map::get_size() const noexcept +{ + return m_addr ? m_size : 0; +} + +template +inline T* File::Map::release() noexcept +{ + T* addr = static_cast(m_addr); + m_addr = nullptr; + m_fd = 0; + return addr; +} + + +inline File::Streambuf::Streambuf(File* f, size_t buffer_size) + : m_file(*f) + , m_buffer(new char[buffer_size]) +{ + char* b = m_buffer.get(); + setp(b, b + buffer_size); +} + +inline File::Streambuf::~Streambuf() noexcept +{ + try { + if (m_file.is_attached()) + flush(); + } + catch (...) { + // Errors deliberately ignored + } +} + +inline File::Streambuf::int_type File::Streambuf::overflow(int_type c) +{ + flush(); + if (c == traits_type::eof()) + return traits_type::not_eof(c); + *pptr() = traits_type::to_char_type(c); + pbump(1); + return c; +} + +inline int File::Streambuf::sync() +{ + flush(); + return 0; +} + +inline File::Streambuf::pos_type File::Streambuf::seekpos(pos_type pos, std::ios_base::openmode) +{ + flush(); + SizeType pos2 = 0; + if (int_cast_with_overflow_detect(std::streamsize(pos), pos2)) + throw util::overflow_error("Seek position overflow"); + m_file.seek(pos2); + return pos; +} + +inline void File::Streambuf::flush() +{ + size_t n = pptr() - pbase(); + if (n > 0) { + m_file.write(pbase(), n); + setp(m_buffer.get(), epptr()); + } +} + +inline File::AccessError::AccessError(const std::string& msg, const std::string& path) + : ExceptionWithBacktrace(msg) + , m_path(path) +{ +} + +inline const std::string& File::AccessError::get_path() const +{ + return m_path; +} + +inline File::PermissionDenied::PermissionDenied(const std::string& msg, const std::string& path) + : AccessError(msg, path) +{ +} + +inline File::NotFound::NotFound(const std::string& msg, const std::string& path) + : AccessError(msg, path) +{ +} + +inline File::Exists::Exists(const std::string& msg, const std::string& path) + : AccessError(msg, path) +{ +} + +inline bool operator==(const File::UniqueID& lhs, const File::UniqueID& rhs) +{ +#ifdef _WIN32 // Windows version + throw util::runtime_error("Not yet supported"); +#else // POSIX version + return lhs.device == rhs.device && lhs.inode == rhs.inode; +#endif +} + +inline bool operator!=(const File::UniqueID& lhs, const File::UniqueID& rhs) +{ + return !(lhs == rhs); +} + +inline bool operator<(const File::UniqueID& lhs, const File::UniqueID& rhs) +{ +#ifdef _WIN32 // Windows version + throw util::runtime_error("Not yet supported"); +#else // POSIX version + if (lhs.device < rhs.device) + return true; + if (lhs.device > rhs.device) + return false; + if (lhs.inode < rhs.inode) + return true; + return false; +#endif +} + +inline bool operator>(const File::UniqueID& lhs, const File::UniqueID& rhs) +{ + return rhs < lhs; +} + +inline bool operator<=(const File::UniqueID& lhs, const File::UniqueID& rhs) +{ + return !(lhs > rhs); +} + +inline bool operator>=(const File::UniqueID& lhs, const File::UniqueID& rhs) +{ + return !(lhs < rhs); +} + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_FILE_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/file_is_regular.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/file_is_regular.hpp new file mode 100644 index 0000000..ef30328 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/file_is_regular.hpp @@ -0,0 +1,18 @@ +#ifndef REALM_UTIL_FILE_IS_REGULAR_HPP +#define REALM_UTIL_FILE_IS_REGULAR_HPP + +#include + +namespace realm { +namespace util { + +/// Check whether the specified file is a reguler file. +/// +/// FIXME: This function ought to be moved to in the +/// realm-core repository. +bool file_is_regular(const std::string& path); + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_FILE_IS_REGULAR_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/file_mapper.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/file_mapper.hpp new file mode 100644 index 0000000..5c7f9f2 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/file_mapper.hpp @@ -0,0 +1,188 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_UTIL_FILE_MAPPER_HPP +#define REALM_UTIL_FILE_MAPPER_HPP + +#include +#include +#include +#include + +#include + +namespace realm { +namespace util { + +void* mmap(FileDesc fd, size_t size, File::AccessMode access, size_t offset, const char* encryption_key); +void* mmap_fixed(FileDesc fd, void* address_request, size_t size, File::AccessMode access, size_t offset, + const char* enc_key); +void* mmap_reserve(FileDesc fd, size_t size, size_t offset); +void munmap(void* addr, size_t size); +void* mremap(FileDesc fd, size_t file_offset, void* old_addr, size_t old_size, File::AccessMode a, size_t new_size, + const char* encryption_key); +void msync(FileDesc fd, void* addr, size_t size); +void* mmap_anon(size_t size); + +// A function which may be given to encryption_read_barrier. If present, the read barrier is a +// a barrier for a full array. If absent, the read barrier is a barrier only for the address +// range give as argument. If the barrier is for a full array, it will read the array header +// and determine the address range from the header. +using HeaderToSize = size_t (*)(const char* addr); +class EncryptedFileMapping; + +class PageReclaimGovernor { +public: + // Called by the page reclaimer with the current load (in bytes) and + // must return the target load (also in bytes). Returns no_match if no + // target can be set + static constexpr int64_t no_match = -1; + virtual std::function current_target_getter(size_t load) = 0; + virtual void report_target_result(int64_t) = 0; +}; + +// Set a page reclaim governor. The governor is an object with a method which will be called periodically +// and must return a 'target' amount of memory to hold decrypted pages. The page reclaim daemon +// will then try to release pages to meet the target. The governor is called with the current +// amount of data used, for the purpose of logging - or possibly for computing the target +// +// The governor is called approximately once per second. +// +// If no governor is installed, the page reclaim daemon will not start. +void set_page_reclaim_governor(PageReclaimGovernor* governor); + +// Use the default governor. The default governor is used automatically if nothing else is set, so +// this funciton is mostly useful for tests where changing back to the default could be desirable. +inline void set_page_reclaim_governor_to_default() +{ + set_page_reclaim_governor(nullptr); +} + +// Retrieves the number of in memory decrypted pages, across all open files. +size_t get_num_decrypted_pages(); + +// Retrieves the +// - amount of memory used for decrypted pages, across all open files. +// - current target for the reclaimer (desired number of decrypted pages) +// - current workload size for the reclaimer, across all open files. +struct decrypted_memory_stats_t { + size_t memory_size; + size_t reclaimer_target; + size_t reclaimer_workload; +}; + +decrypted_memory_stats_t get_decrypted_memory_stats(); + +#if REALM_ENABLE_ENCRYPTION + +void encryption_note_reader_start(SharedFileInfo& info, const void* reader_id); +void encryption_note_reader_end(SharedFileInfo& info, const void* reader_id) noexcept; + +SharedFileInfo* get_file_info_for_file(File& file); + +// This variant allows the caller to obtain direct access to the encrypted file mapping +// for optimization purposes. +void* mmap(FileDesc fd, size_t size, File::AccessMode access, size_t offset, const char* encryption_key, + EncryptedFileMapping*& mapping); +void* mmap_fixed(FileDesc fd, void* address_request, size_t size, File::AccessMode access, size_t offset, + const char* enc_key, EncryptedFileMapping* mapping); + +void* mmap_reserve(FileDesc fd, size_t size, File::AccessMode am, size_t offset, const char* enc_key, + EncryptedFileMapping*& mapping); + +void do_encryption_read_barrier(const void* addr, size_t size, HeaderToSize header_to_size, + EncryptedFileMapping* mapping); + +void do_encryption_write_barrier(const void* addr, size_t size, EncryptedFileMapping* mapping); + +void inline encryption_read_barrier(const void* addr, size_t size, EncryptedFileMapping* mapping, + HeaderToSize header_to_size = nullptr) +{ + if (REALM_UNLIKELY(mapping)) + do_encryption_read_barrier(addr, size, header_to_size, mapping); +} + +void inline encryption_write_barrier(const void* addr, size_t size, EncryptedFileMapping* mapping) +{ + if (REALM_UNLIKELY(mapping)) + do_encryption_write_barrier(addr, size, mapping); +} + + +extern util::Mutex& mapping_mutex; + +inline void do_encryption_read_barrier(const void* addr, size_t size, HeaderToSize header_to_size, + EncryptedFileMapping* mapping) +{ + UniqueLock lock(mapping_mutex); + mapping->read_barrier(addr, size, header_to_size); +} + +inline void do_encryption_write_barrier(const void* addr, size_t size, EncryptedFileMapping* mapping) +{ + LockGuard lock(mapping_mutex); + mapping->write_barrier(addr, size); +} + +#else + +void inline set_page_reclaim_governor(PageReclaimGovernor*) +{ +} + +size_t inline get_num_decrypted_pages() +{ + return 0; +} + +void inline encryption_read_barrier(const void*, size_t, EncryptedFileMapping*, HeaderToSize = nullptr) +{ +} + +void inline encryption_write_barrier(const void*, size_t) +{ +} + +void inline encryption_write_barrier(const void*, size_t, EncryptedFileMapping*) +{ +} + +#endif + +// helpers for encrypted Maps +template +void encryption_read_barrier(const File::Map& map, size_t index, size_t num_elements = 1) +{ + T* addr = map.get_addr(); + encryption_read_barrier(addr + index, sizeof(T) * num_elements, map.get_encrypted_mapping()); +} + +template +void encryption_write_barrier(const File::Map& map, size_t index, size_t num_elements = 1) +{ + T* addr = map.get_addr(); + encryption_write_barrier(addr + index, sizeof(T) * num_elements, map.get_encrypted_mapping()); +} + +File::SizeType encrypted_size_to_data_size(File::SizeType size) noexcept; +File::SizeType data_size_to_encrypted_size(File::SizeType size) noexcept; + +size_t round_up_to_page_size(size_t size) noexcept; +} +} +#endif diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/fixed_size_buffer.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/fixed_size_buffer.hpp new file mode 100644 index 0000000..8a512ee --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/fixed_size_buffer.hpp @@ -0,0 +1,135 @@ +/************************************************************************* + * + * Copyright 2019 Realm Inc. + * + * 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 REALM_UTIL_FIXED_SIZE_BUFFER_HPP +#define REALM_UTIL_FIXED_SIZE_BUFFER_HPP + +#include +#include +#include + +namespace realm { +namespace util { + +/// This is a buffer with a fixed size. You can only insert elements. +/// When the number of elements inserted matches the size of the buffer, +/// additional insertions will overwrite the oldest elements. +template +class FixedSizeBuffer { +public: + class iterator; + + FixedSizeBuffer(size_t sz) + : m_size(sz) + { + if (sz == 0) + throw std::runtime_error("FixedSizeBuffer size cannot be 0"); + m_buffer.reserve(sz); + } + size_t size() + { + return m_buffer.size(); + } + void insert(const T& val) + { + if (m_buffer.size() < m_size) { + m_buffer.emplace_back(val); + } + else { + m_buffer[m_oldest] = val; + ++m_oldest; + if (m_oldest == m_size) + m_oldest = 0; + } + } + T& at(size_t n) + { + auto idx = (n + m_oldest) % m_size; + return m_buffer[idx]; + } + T& operator[](size_t n) + { + return at(n); + } + iterator begin() + { + return iterator(*this, 0); + } + iterator end() + { + return iterator(*this, m_buffer.size()); + } + +private: + std::vector m_buffer; + size_t m_size; + size_t m_oldest = 0; +}; + +template +class FixedSizeBuffer::iterator { +public: + typedef std::forward_iterator_tag iterator_category; + typedef T value_type; + typedef ptrdiff_t difference_type; + typedef T* pointer; + typedef T& reference; + + iterator(FixedSizeBuffer& b, size_t ndx) + : m_cb(b) + , m_ndx(ndx) + { + } + pointer operator->() + { + return &m_cb[m_ndx]; + } + reference operator*() + { + return m_cb[m_ndx]; + } + iterator& operator++() + { + ++m_ndx; + return *this; + } + iterator operator++(int) + { + iterator tmp(*this); + operator++(); + return tmp; + } + bool operator!=(const iterator& rhs) + { + return m_ndx != rhs.m_ndx; + } + bool operator==(const iterator& rhs) + { + return m_ndx == rhs.m_ndx; + } + +private: + FixedSizeBuffer& m_cb; + size_t m_ndx; +}; + +} // namespace util +} // namespace realm + + +#endif /* REALM_UTIL_FIXED_SIZE_BUFFER_HPP */ diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/flat_map.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/flat_map.hpp new file mode 100644 index 0000000..3506307 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/flat_map.hpp @@ -0,0 +1,204 @@ + + +#ifndef REALM_UTIL_FLAT_MAP_HPP +#define REALM_UTIL_FLAT_MAP_HPP + +#include +#include // std::pair +#include // std::lower_bound etc. +#include + +#include + +namespace realm { +namespace util { + +template >, class Cmp = std::less<>> +struct FlatMap { + using value_type = std::pair; + using key_type = K; + using mapped_type = V; + FlatMap() {} + FlatMap(const FlatMap&) = default; + FlatMap(FlatMap&&) = default; + FlatMap& operator=(const FlatMap&) = default; + FlatMap& operator=(FlatMap&&) = default; + + V& at(K key) + { + auto it = lower_bound(key); + if (it == end() || it->first != key) + it = m_data.emplace(it, std::move(key), V{}); // Throws + return it->second; + } + + const V& at(const K& key) const + { + auto it = find(key); + if (it == end()) + throw util::out_of_range("no such key"); + return it->second; + } + + V& operator[](const K& key) + { + return at(key); // Throws + } + + using iterator = typename Container::iterator; + using const_iterator = typename Container::const_iterator; + iterator begin() noexcept + { + return m_data.begin(); + } + iterator end() noexcept + { + return m_data.end(); + } + const_iterator begin() const noexcept + { + return m_data.begin(); + } + const_iterator end() const noexcept + { + return m_data.end(); + } + + + bool empty() const noexcept + { + return m_data.empty(); + } + size_t size() const noexcept + { + return m_data.size(); + } + void clear() noexcept + { + m_data.clear(); + } + + std::pair insert(value_type value) + { + auto it = lower_bound(value.first); + if (it != end() && it->first == value.first) { + return std::make_pair(it, false); + } + return std::make_pair(m_data.emplace(it, std::move(value)), true); // Throws + } + + template + std::pair insert(P pair) + { + return insert(value_type{std::get<0>(pair), std::get<1>(pair)}); + } + + template + void insert(InputIt first, InputIt last) + { + for (auto it = first; it != last; ++it) { + insert(*it); + } + } + + template + std::pair emplace(Args&&... args) + { + value_type value{std::forward(args)...}; + return insert(std::move(value)); + } + + template + std::pair emplace_hint(const_iterator pos, Args&&... args) + { + static_cast(pos); // FIXME: TODO + return emplace(std::forward(args)...); + } + + iterator erase(const_iterator pos) noexcept(std::is_nothrow_move_assignable::value) + { + return m_data.erase(pos); + } + + iterator erase(const_iterator first, + const_iterator last) noexcept(std::is_nothrow_move_assignable::value) + { + return m_data.erase(first, last); + } + + size_t erase(const K& key) noexcept(std::is_nothrow_move_assignable::value) + { + auto it = find(key); + if (it != end()) { + erase(it); + return 1; + } + return 0; + } + + void swap(FlatMap& other) + { + m_data.swap(other.m_data); + } + + template + size_t count(const Key& key) const noexcept + { + return find(key) == end() ? 0 : 1; + } + + template + iterator find(const Key& key) noexcept + { + const FlatMap* This = this; + const_iterator pos = This->find(key); + return iterator{begin() + (pos - This->begin())}; + } + + template + const_iterator find(const Key& key) const noexcept + { + auto it = lower_bound(key); + if (it != end() && it->first != key) { + return end(); + } + return it; + } + + template + iterator lower_bound(const Key& key) noexcept + { + const FlatMap* This = this; + const_iterator pos = This->lower_bound(key); + return iterator{begin() + (pos - This->begin())}; + } + + template + const_iterator lower_bound(const Key& key) const noexcept + { + auto it = std::lower_bound(begin(), end(), key, [](const value_type& a, const Key& b) { + return Cmp{}(a.first, b); + }); + return it; + } + + // FIXME: Not implemented yet. + template + iterator upper_bound(const Key&) noexcept; + // FIXME: Not implemented yet. + template + const_iterator upper_bound(const Key&) const noexcept; + + void reserve(size_t size) + { + m_data.reserve(size); // Throws + } + +private: + Container m_data; +}; + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_FLAT_MAP_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/function_ref.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/function_ref.hpp new file mode 100644 index 0000000..7978d6b --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/function_ref.hpp @@ -0,0 +1,138 @@ +/************************************************************************* + * + * Copyright 2019 Realm Inc. + * + * 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 REALM_UTIL_FUNCTION_REF_HPP +#define REALM_UTIL_FUNCTION_REF_HPP + +#include +#include + +namespace realm { +namespace util { + +#ifdef _WIN32 +// VC++ warns about multiple copy constructors, but we want both const and +// non-const version to ensure they're a better match than the wrapping +// constructor. We could instead use enable_if to make the wrapping constructor +// ineligible, but that tends to do bad things to compile times. +#pragma warning(push) +#pragma warning(disable : 4521 4522) +#endif + +/// A lightweight non-owning reference to a callable. +/// +/// This type is similar to std::function, but unlike std::function holds a reference to the callable rather than +/// making a copy of it. This means that it will never require a heap allocation, and produces significantly smaller +/// binaries due to the template machinery being much simpler. This type should only ever be used as a function +/// parameter that is not stored past when the function returns. All other uses (including trying to store it in a +/// std::function) are very unlikely to be correct. +/// +/// This implements a subset of P0792R5, which hopefully will be incorportated into a future version of the standard +/// library. +template +class FunctionRef; +template +class FunctionRef { +public: + using ThisType = FunctionRef; + // A FunctionRef is never empty, and so cannot be default-constructed. + constexpr FunctionRef() noexcept = delete; + + // FunctionRef is copyable and moveable. +#if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && !defined(__clang__) + FunctionRef(ThisType&) noexcept = default; + FunctionRef(ThisType const&) noexcept = default; + ThisType& operator=(ThisType&) noexcept = default; + ThisType& operator=(const ThisType&) noexcept = default; + FunctionRef(ThisType&&) noexcept = default; + ThisType& operator=(ThisType&&) noexcept = default; +#else +#ifdef _WIN32 + // VC++ incorrectly rejects multiple versions of a defaulted special member function + constexpr FunctionRef(ThisType& o) noexcept + : m_obj(o.m_obj) + , m_callback(o.m_callback) + { + } + constexpr ThisType& operator=(ThisType& o) noexcept + { + m_obj = o.m_obj; + m_callback = o.m_callback; + return *this; + } + constexpr FunctionRef(ThisType const& o) noexcept + : m_obj(o.m_obj) + , m_callback(o.m_callback) + { + } + constexpr ThisType& operator=(ThisType const& o) noexcept + { + m_obj = o.m_obj; + m_callback = o.m_callback; + return *this; + } +#else + constexpr FunctionRef(ThisType&) noexcept = default; + constexpr ThisType& operator=(ThisType&) noexcept = default; + constexpr FunctionRef(ThisType const&) noexcept = default; + constexpr ThisType& operator=(const ThisType&) noexcept = default; +#endif + constexpr FunctionRef(ThisType&&) noexcept = default; + constexpr ThisType& operator=(ThisType&&) noexcept = default; +#endif + + // Construct a FunctionRef which wraps the given callable. + template + constexpr FunctionRef(F&& f) noexcept + : m_obj(const_cast(reinterpret_cast(std::addressof(f)))) + , m_callback([](void* obj, Args... args) -> Return { + return (*reinterpret_cast::type>(obj))(std::forward(args)...); + }) + { + } + + constexpr void swap(ThisType& rhs) noexcept + { + std::swap(m_obj, rhs.m_obj); + std::swap(m_callback, rhs.m_callback); + } + + Return operator()(Args... args) const + { + return m_callback(m_obj, std::forward(args)...); + } + +private: + void* m_obj; + Return (*m_callback)(void*, Args...); +}; + +template +constexpr void swap(FunctionRef& lhs, FunctionRef& rhs) noexcept +{ + lhs.swap(rhs); +} + +} // namespace util +} // namespace realm + +#ifdef _WIN32 +#pragma warning(pop) +#endif + +#endif diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/get_file_size.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/get_file_size.hpp new file mode 100644 index 0000000..28c70ac --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/get_file_size.hpp @@ -0,0 +1,25 @@ +#ifndef REALM_UTIL_GET_FILE_SIZE_HPP +#define REALM_UTIL_GET_FILE_SIZE_HPP + +#include + +namespace realm { +namespace util { + +/// FIXME: This function ought to be moved to in the +/// realm-core repository. +util::File::SizeType get_file_size(const std::string& path); + + +// Implementation + +inline util::File::SizeType get_file_size(const std::string& path) +{ + util::File file{path}; // Throws + return file.get_size(); // Throws +} + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_GET_FILE_SIZE_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/hex_dump.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/hex_dump.hpp new file mode 100644 index 0000000..b041372 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/hex_dump.hpp @@ -0,0 +1,54 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_UTIL_HEX_DUMP_HPP +#define REALM_UTIL_HEX_DUMP_HPP + +#include +#include +#include +#include +#include +#include + +#include + +namespace realm { +namespace util { + +template +std::string hex_dump(const T* data, size_t size, const char* separator = " ", int min_digits = -1) +{ + using U = std::make_unsigned_t; + + if (min_digits < 0) + min_digits = (std::numeric_limits::digits + 3) / 4; + + std::ostringstream out; + for (const T* i = data; i != data + size; ++i) { + if (i != data) + out << separator; + out << std::setw(min_digits) << std::setfill('0') << std::hex << std::uppercase << int64_t(U(*i)); + } + return out.str(); +} + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_HEX_DUMP_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/http.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/http.hpp new file mode 100644 index 0000000..2a18bd8 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/http.hpp @@ -0,0 +1,526 @@ + +#ifndef REALM_UTIL_HTTP_HPP +#define REALM_UTIL_HTTP_HPP + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace realm { +namespace util { +enum class HTTPParserError { + None = 0, + ContentTooLong, + HeaderLineTooLong, + MalformedResponse, + MalformedRequest, + BadRequest, +}; +std::error_code make_error_code(HTTPParserError); +} // namespace util +} // namespace realm + +namespace std { +template <> +struct is_error_code_enum : std::true_type { +}; +} // namespace std + +namespace realm { +namespace util { + +/// See: https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html +/// +/// It is guaranteed that the backing integer value of this enum corresponds +/// to the numerical code representing the status. +enum class HTTPStatus { + Unknown = 0, + + Continue = 100, + SwitchingProtocols = 101, + + Ok = 200, + Created = 201, + Accepted = 202, + NonAuthoritative = 203, + NoContent = 204, + ResetContent = 205, + PartialContent = 206, + + MultipleChoices = 300, + MovedPermanently = 301, + Found = 302, + SeeOther = 303, + NotModified = 304, + UseProxy = 305, + SwitchProxy = 306, + TemporaryRedirect = 307, + PermanentRedirect = 308, + + BadRequest = 400, + Unauthorized = 401, + PaymentRequired = 402, + Forbidden = 403, + NotFound = 404, + MethodNotAllowed = 405, + NotAcceptable = 406, + ProxyAuthenticationRequired = 407, + RequestTimeout = 408, + Conflict = 409, + Gone = 410, + LengthRequired = 411, + PreconditionFailed = 412, + PayloadTooLarge = 413, + UriTooLong = 414, + UnsupportedMediaType = 415, + RangeNotSatisfiable = 416, + ExpectationFailed = 417, + ImATeapot = 418, + MisdirectedRequest = 421, + UpgradeRequired = 426, + PreconditionRequired = 428, + TooManyRequests = 429, + RequestHeaderFieldsTooLarge = 431, + UnavailableForLegalReasons = 451, + + InternalServerError = 500, + NotImplemented = 501, + BadGateway = 502, + ServiceUnavailable = 503, + GatewayTimeout = 504, + HttpVersionNotSupported = 505, + VariantAlsoNegotiates = 506, + NotExtended = 510, + NetworkAuthenticationRequired = 511, +}; + +bool valid_http_status_code(unsigned int code); + +/// See: https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html +enum class HTTPMethod { + Options, + Get, + Head, + Post, + Put, + Delete, + Trace, + Connect, +}; + +struct HTTPAuthorization { + std::string scheme; + std::map values; +}; + +HTTPAuthorization parse_authorization(const std::string&); + +class HeterogeneousCaseInsensitiveCompare { +public: + using is_transparent = std::true_type; + template + bool operator()(const A& a, const B& b) const noexcept + { + return comp(StringView(a), StringView(b)); + } + +private: + bool comp(StringView a, StringView b) const noexcept + { + auto cmp = [](char lhs, char rhs) { + return std::tolower(lhs, std::locale::classic()) < std::tolower(rhs, std::locale::classic()); + }; + return std::lexicographical_compare(begin(a), end(a), begin(b), end(b), cmp); + } +}; + +/// Case-insensitive map suitable for storing HTTP headers. +using HTTPHeaders = std::map; + +struct HTTPRequest { + HTTPMethod method = HTTPMethod::Get; + HTTPHeaders headers; + std::string path; + + /// If the request object has a body, the Content-Length header MUST be + /// set to a string representation of the number of bytes in the body. + /// FIXME: Relax this restriction, and also support Transfer-Encoding + /// and other HTTP/1.1 features. + Optional body; +}; + +struct HTTPResponse { + HTTPStatus status = HTTPStatus::Unknown; + std::string reason; + HTTPHeaders headers; + + // A body is only read from the response stream if the server sent the + // Content-Length header. + // FIXME: Support other transfer methods, including Transfer-Encoding and + // HTTP/1.1 features. + Optional body; +}; + + +/// Serialize HTTP request to output stream. +std::ostream& operator<<(std::ostream&, const HTTPRequest&); +/// Serialize HTTP response to output stream. +std::ostream& operator<<(std::ostream&, const HTTPResponse&); +/// Serialize HTTP method to output stream ("GET", "POST", etc.). +std::ostream& operator<<(std::ostream&, HTTPMethod); +/// Serialize HTTP status to output stream, include reason string ("200 OK" etc.) +std::ostream& operator<<(std::ostream&, HTTPStatus); + + +struct HTTPParserBase { + util::Logger& logger; + + // FIXME: Generally useful? + struct CallocDeleter { + void operator()(void* ptr) + { + std::free(ptr); + } + }; + + HTTPParserBase(util::Logger& logger_2) + : logger{logger_2} + { + // Allocating read buffer with calloc to avoid accidentally spilling + // data from other sessions in case of a buffer overflow exploit. + m_read_buffer.reset(static_cast(std::calloc(read_buffer_size, 1))); + } + virtual ~HTTPParserBase() {} + + std::string m_write_buffer; + std::unique_ptr m_read_buffer; + Optional m_found_content_length; + static const size_t read_buffer_size = 8192; + static const size_t max_header_line_length = read_buffer_size; + + /// Parses the contents of m_read_buffer as a HTTP header line, + /// and calls on_header() as appropriate. on_header() will be called at + /// most once per invocation. + /// Returns false if the contents of m_read_buffer is not a valid HTTP + /// header line. + bool parse_header_line(size_t len); + + virtual std::error_code on_first_line(StringData line) = 0; + virtual void on_header(StringData key, StringData value) = 0; + virtual void on_body(StringData body) = 0; + virtual void on_complete(std::error_code = std::error_code{}) = 0; + + /// If the input matches a known HTTP method string, return the appropriate + /// HTTPMethod enum value. Otherwise, returns none. + static Optional parse_method_string(StringData method); + + /// Interpret line as the first line of an HTTP request. If the return value + /// is true, out_method and out_uri have been assigned the appropriate + /// values found in the request line. + static bool parse_first_line_of_request(StringData line, HTTPMethod& out_method, StringData& out_uri); + + /// Interpret line as the first line of an HTTP response. If the return + /// value is true, out_status and out_reason have been assigned the + /// appropriate values found in the response line. + static bool parse_first_line_of_response(StringData line, HTTPStatus& out_status, StringData& out_reason, + util::Logger& logger); + + void set_write_buffer(const HTTPRequest&); + void set_write_buffer(const HTTPResponse&); +}; + + +template +struct HTTPParser : protected HTTPParserBase { + explicit HTTPParser(Socket& socket, util::Logger& logger) + : HTTPParserBase(logger) + , m_socket(socket) + { + } + + void read_first_line() + { + auto handler = [this](std::error_code ec, size_t n) { + if (ec == error::operation_aborted) { + return; + } + if (ec) { + on_complete(ec); + return; + } + ec = on_first_line(StringData(m_read_buffer.get(), n)); + if (ec) { + on_complete(ec); + return; + } + read_headers(); + }; + m_socket.async_read_until(m_read_buffer.get(), max_header_line_length, '\n', std::move(handler)); + } + + void read_headers() + { + auto handler = [this](std::error_code ec, size_t n) { + if (ec == error::operation_aborted) { + return; + } + if (ec) { + on_complete(ec); + return; + } + if (n <= 2) { + read_body(); + return; + } + if (!parse_header_line(n)) { + on_complete(HTTPParserError::BadRequest); + return; + } + + // FIXME: Limit the total size of headers. Apache uses 8K. + read_headers(); + }; + m_socket.async_read_until(m_read_buffer.get(), max_header_line_length, '\n', std::move(handler)); + } + + void read_body() + { + if (m_found_content_length) { + // FIXME: Support longer bodies. + // FIXME: Support multipart and other body types (no body shaming). + if (*m_found_content_length > read_buffer_size) { + on_complete(HTTPParserError::ContentTooLong); + return; + } + + auto handler = [this](std::error_code ec, size_t n) { + if (ec == error::operation_aborted) { + return; + } + if (!ec) { + on_body(StringData(m_read_buffer.get(), n)); + } + on_complete(ec); + }; + m_socket.async_read(m_read_buffer.get(), *m_found_content_length, std::move(handler)); + } + else { + // No body, just finish. + on_complete(); + } + } + + void write_buffer(std::function handler) + { + m_socket.async_write(m_write_buffer.data(), m_write_buffer.size(), std::move(handler)); + } + + Socket& m_socket; +}; + + +template +struct HTTPClient : protected HTTPParser { + using Handler = void(HTTPResponse, std::error_code); + + explicit HTTPClient(Socket& socket, util::Logger& logger) + : HTTPParser(socket, logger) + { + } + + /// Serialize and send \a request over the connected socket asynchronously. + /// + /// When the response has been received, or an error occurs, \a handler will + /// be invoked with the appropriate parameters. The HTTPResponse object + /// passed to \a handler will only be complete in non-error conditions, but + /// may be partially populated. + /// + /// It is an error to start a request before the \a handler of a previous + /// request has been invoked. It is permitted to call async_request() from + /// the handler, unless an error has been reported representing a condition + /// where the underlying socket is no longer able to communicate (for + /// example, if it has been closed). + /// + /// If a request is already in progress, an exception will be thrown. + /// + /// This method is *NOT* thread-safe. + void async_request(const HTTPRequest& request, std::function handler) + { + if (REALM_UNLIKELY(m_handler)) { + throw util::runtime_error("Request already in progress."); + } + this->set_write_buffer(request); + m_handler = std::move(handler); + this->write_buffer([this](std::error_code ec, size_t bytes_written) { + static_cast(bytes_written); + if (ec == error::operation_aborted) { + return; + } + if (ec) { + this->on_complete(ec); + return; + } + this->read_first_line(); + }); + } + +private: + std::function m_handler; + HTTPResponse m_response; + + std::error_code on_first_line(StringData line) override final + { + HTTPStatus status; + StringData reason; + if (this->parse_first_line_of_response(line, status, reason, this->logger)) { + m_response.status = status; + m_response.reason = reason; + return std::error_code{}; + } + return HTTPParserError::MalformedResponse; + } + + void on_header(StringData key, StringData value) override final + { + // FIXME: Multiple headers with the same key should show up as a + // comma-separated list of their values, rather than overwriting. + m_response.headers[std::string(key)] = std::string(value); + } + + void on_body(StringData body) override final + { + m_response.body = std::string(body); + } + + void on_complete(std::error_code ec) override final + { + auto handler = std::move(m_handler); + m_handler = nullptr; + handler(std::move(m_response), ec); + } +}; + + +template +struct HTTPServer : protected HTTPParser { + using RequestHandler = void(HTTPRequest, std::error_code); + using RespondHandler = void(std::error_code); + + explicit HTTPServer(Socket& socket, util::Logger& logger) + : HTTPParser(socket, logger) + { + } + + /// Receive a request on the underlying socket asynchronously. + /// + /// This function starts an asynchronous read operation and keeps reading + /// until an HTTP request has been received. \a handler is invoked when a + /// request has been received, or an error occurs. + /// + /// After a request is received, callers MUST invoke async_send_response() + /// to provide the client with a valid HTTP response, unless the error + /// passed to the handler represents a condition where the underlying socket + /// is no longer able to communicate (for example, if it has been closed). + /// + /// It is an error to attempt to receive a request before any previous + /// requests have been fully responded to, i.e. the \a handler argument of + /// async_send_response() must have been invoked before attempting to + /// receive the next request. + /// + /// This function is *NOT* thread-safe. + void async_receive_request(std::function handler) + { + if (REALM_UNLIKELY(m_request_handler)) { + throw util::runtime_error("Response already in progress."); + } + m_request_handler = std::move(handler); + this->read_first_line(); + } + + /// Send an HTTP response to a client asynchronously. + /// + /// This function starts an asynchronous write operation on the underlying + /// socket. \a handler is invoked when the response has been written to the + /// socket, or an error occurs. + /// + /// It is an error to call async_receive_request() again before \a handler + /// has been invoked, and it is an error to call async_send_response() + /// before the \a handler of a previous invocation has been invoked. + /// + /// This function is *NOT* thread-safe. + void async_send_response(const HTTPResponse& response, std::function handler) + { + if (REALM_UNLIKELY(!m_request_handler)) { + throw util::runtime_error("No request in progress."); + } + if (m_respond_handler) { + // FIXME: Proper exception type. + throw util::runtime_error("Already responding to request"); + } + m_respond_handler = std::move(handler); + this->set_write_buffer(response); + this->write_buffer([this](std::error_code ec, size_t) { + if (ec == error::operation_aborted) { + return; + } + m_request_handler = nullptr; + auto handler = std::move(m_respond_handler); + handler(ec); + }); + ; + } + +private: + std::function m_request_handler; + std::function m_respond_handler; + HTTPRequest m_request; + + std::error_code on_first_line(StringData line) override final + { + HTTPMethod method; + StringData uri; + if (this->parse_first_line_of_request(line, method, uri)) { + m_request.method = method; + m_request.path = uri; + return std::error_code{}; + } + return HTTPParserError::MalformedRequest; + } + + void on_header(StringData key, StringData value) override final + { + // FIXME: Multiple headers with the same key should show up as a + // comma-separated list of their values, rather than overwriting. + m_request.headers[std::string(key)] = std::string(value); + } + + void on_body(StringData body) override final + { + m_request.body = std::string(body); + } + + void on_complete(std::error_code ec) override final + { + // Deliberately not nullifying m_request_handler so that we can + // check for invariants in async_send_response. + m_request_handler(std::move(m_request), ec); + } +}; + + +std::string make_http_host(bool is_ssl, StringView address, std::uint_fast16_t port); + +} // namespace util +} // namespace realm + + +#endif // REALM_UTIL_HTTP_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/inspect.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/inspect.hpp new file mode 100644 index 0000000..84a669d --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/inspect.hpp @@ -0,0 +1,76 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_UTIL_INSPECT_HPP +#define REALM_UTIL_INSPECT_HPP + +#include + +namespace realm { +namespace util { + +// LCOV_EXCL_START +// +// Because these are templated functions, every combination of output stream +// type and value(s) type(s) generates a new function. This makes LCOV/GCOVR +// report over 70 functions in this file, with only 6.6% function coverage, +// even though line coverage is at 100%. + +template +void inspect_value(OS& os, const T& value) +{ + os << value; +} + +template +void inspect_value(OS& os, const std::string& value) +{ + // FIXME: Escape the string. + os << "\"" << value << "\""; +} + +template +void inspect_value(OS& os, const char* value) +{ + // FIXME: Escape the string. + os << "\"" << value << "\""; +} + +template +void inspect_all(OS&) +{ + // No-op +} + +/// Convert all arguments to strings, and quote string arguments. +template +void inspect_all(OS& os, First&& first, Args&&... args) +{ + inspect_value(os, std::forward(first)); + if (sizeof...(Args) != 0) { + os << ", "; + } + inspect_all(os, std::forward(args)...); +} + +// LCOV_EXCL_STOP + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_INSPECT_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/interprocess_condvar.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/interprocess_condvar.hpp new file mode 100644 index 0000000..0e5b586 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/interprocess_condvar.hpp @@ -0,0 +1,151 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_UTIL_INTERPROCESS_CONDVAR +#define REALM_UTIL_INTERPROCESS_CONDVAR + + +#include +#include +#include +#include +#include +#include +#include + +// Condvar Emulation is required if RobustMutex emulation is enabled +#if defined(REALM_ROBUST_MUTEX_EMULATION) || defined(_WIN32) +#define REALM_CONDVAR_EMULATION +#endif + +namespace realm { +namespace util { + + +/// Condition variable for use in synchronization monitors. +/// This condition variable uses emulation based on named pipes +/// for the inter-process case, if enabled by REALM_CONDVAR_EMULATION. +/// +/// FIXME: This implementation will never release/delete pipes. This is unlikely +/// to be a problem as long as only a modest number of different database names +/// are in use +/// +/// A InterprocessCondVar is always process shared. +class InterprocessCondVar { +public: + InterprocessCondVar(); + ~InterprocessCondVar() noexcept; + + // Disable copying. Copying an open file will create a scenario + // where the same file descriptor will be opened once but closed twice. + InterprocessCondVar(const InterprocessCondVar&) = delete; + InterprocessCondVar& operator=(const InterprocessCondVar&) = delete; + +/// To use the InterprocessCondVar, you also must place a structure of type +/// InterprocessCondVar::SharedPart in memory shared by multiple processes +/// or in a memory mapped file, and use set_shared_part() to associate +/// the condition variable with it's shared part. You must initialize +/// the shared part using InterprocessCondVar::init_shared_part(), but only before +/// first use and only when you have exclusive access to the shared part. + +#ifdef REALM_CONDVAR_EMULATION + struct SharedPart { +#ifdef _WIN32 + // Number of waiting threads. + int32_t m_waiters_count; + size_t m_was_broadcast; +#else + uint64_t signal_counter; + uint64_t wait_counter; +#endif + }; +#else + typedef CondVar SharedPart; +#endif + + /// You need to bind the emulation to a SharedPart in shared/mmapped memory. + /// The SharedPart is assumed to have been initialized (possibly by another process) + /// earlier through a call to init_shared_part. + void set_shared_part(SharedPart& shared_part, std::string path, std::string condvar_name, std::string tmp_path); + + /// Initialize the shared part of a process shared condition variable. + /// A process shared condition variables may be represented by any number of + /// InterprocessCondVar instances in any number of different processes, + /// all sharing a common SharedPart instance, which must be in shared memory. + static void init_shared_part(SharedPart& shared_part); + + /// Release any system resources allocated for the shared part. This should + /// be used *only* when you are certain, that nobody is using it. + void release_shared_part(); + + /// Wait for someone to call notify() or notify_all() on this condition + /// variable. The call to wait() may return spuriously, so the caller should + /// always re-evaluate the condition on which to wait and loop on wait() + /// if necessary. + void wait(InterprocessMutex& m, const struct timespec* tp); + + /// If any threads are waiting for this condition, wake up at least one. + /// (Current implementation may actually wake all :-O ). The caller must + /// hold the lock associated with the condvar at the time of calling notify() + void notify() noexcept; + + /// Wake up every thread that is currently waiting on this condition. + /// The caller must hold the lock associated with the condvar at the time + /// of calling notify_all(). + void notify_all() noexcept; + + /// Cleanup and release system resources if possible. + void close() noexcept; + +private: + // non-zero if a shared part has been registered (always 0 on process local instances) + SharedPart* m_shared_part = nullptr; +#ifdef REALM_CONDVAR_EMULATION + // keep the path to allocated system resource so we can remove them again + std::string m_resource_path; + // pipe used for emulation. When using a named pipe, m_fd_read is read-write and m_fd_write is unused. + // When using an anonymous pipe (currently only for tvOS) m_fd_read is read-only and m_fd_write is write-only. + int m_fd_read = -1; + int m_fd_write = -1; + +#ifdef _WIN32 + // Semaphore used to queue up threads waiting for the condition to + // become signaled. + HANDLE m_sema = 0; + // An auto-reset event used by the broadcast/signal thread to wait + // for all the waiting thread(s) to wake up and be released from the + // semaphore. + HANDLE m_waiters_done = 0; + std::string m_name; + + // Serialize access to m_waiters_count + InterprocessMutex m_waiters_lockcount; +#endif + +#endif +}; + + +// Implementation: + + +} // namespace util +} // namespace realm + + +#endif diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/interprocess_mutex.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/interprocess_mutex.hpp new file mode 100644 index 0000000..76b5a85 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/interprocess_mutex.hpp @@ -0,0 +1,377 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_UTIL_INTERPROCESS_MUTEX +#define REALM_UTIL_INTERPROCESS_MUTEX + +#include +#include +#include +#include +#include +#include +#include + +// Enable this only on platforms where it might be needed +#if REALM_PLATFORM_APPLE || REALM_ANDROID +#define REALM_ROBUST_MUTEX_EMULATION +#endif + +namespace realm { +namespace util { + +// fwd decl to support friend decl below +class InterprocessCondVar; + + +/// Emulation of a Robust Mutex. +/// A Robust Mutex is an interprocess mutex which will automatically +/// release any locks held by a process when it crashes. Contrary to +/// Posix robust mutexes, this robust mutex is not capable of informing +/// participants that they have been granted a lock after a crash of +/// the process holding it (though it could be added if needed). + +class InterprocessMutex { +public: + InterprocessMutex(); + ~InterprocessMutex() noexcept; + + // Disable copying. Copying a locked Mutex will create a scenario + // where the same file descriptor will be locked once but unlocked twice. + InterprocessMutex(const InterprocessMutex&) = delete; + InterprocessMutex& operator=(const InterprocessMutex&) = delete; + +#if defined(REALM_ROBUST_MUTEX_EMULATION) || defined(_WIN32) + struct SharedPart { + }; +#else + using SharedPart = RobustMutex; +#endif + + /// You need to bind the emulation to a SharedPart in shared/mmapped memory. + /// The SharedPart is assumed to have been initialized (possibly by another process) + /// elsewhere. + void set_shared_part(SharedPart& shared_part, const std::string& path, const std::string& mutex_name); + void set_shared_part(SharedPart& shared_part, File&& lock_file); + + /// Destroy shared object. Potentially release system resources. Caller must + /// ensure that the shared_part is not in use at the point of call. + void release_shared_part(); + + /// Lock the mutex. If the mutex is already locked, wait for it to be unlocked. + void lock(); + + /// Non-blocking attempt to lock the mutex. Returns true if the lock is obtained. + /// If the lock can not be obtained return false immediately. + bool try_lock(); + + /// Unlock the mutex + void unlock(); + + /// Attempt to check if the mutex is valid (only relevant if not emulating) + bool is_valid() noexcept; + + static bool is_robust_on_this_platform() + { +#ifdef REALM_ROBUST_MUTEX_EMULATION + return true; // we're faking it! +#else + return RobustMutex::is_robust_on_this_platform(); +#endif + } + +private: +#ifdef REALM_ROBUST_MUTEX_EMULATION + struct LockInfo { + File m_file; + Mutex m_local_mutex; + LockInfo() {} + ~LockInfo() noexcept; + // Disable copying. + LockInfo(const LockInfo&) = delete; + LockInfo& operator=(const LockInfo&) = delete; + }; + /// InterprocessMutex created on the same file (same inode on POSIX) share the same LockInfo. + /// LockInfo will be saved in a static map as a weak ptr and use the UniqueID as the key. + /// Operations on the map need to be protected by s_mutex + static std::map>* s_info_map; + static Mutex* s_mutex; + /// We manually initialize these static variables when first needed, + /// creating them on the heap so that they last for the entire lifetime + /// of the process. The destructor of these is never called; the + /// process will clean up their memory when exiting. It is not enough + /// to count instances of InterprocessMutex and clean up these statics when + /// the count reaches zero because the program can create more + /// InterprocessMutex instances before the process ends, so we really need + /// these variables for the entire lifetime of the process. + static std::once_flag s_init_flag; + static void initialize_statics(); + + /// Only used for release_shared_part + std::string m_filename; + File::UniqueID m_fileuid; + std::shared_ptr m_lock_info; + + /// Free the lock info hold by this instance. + /// If it is the last reference, underly resources will be freed as well. + void free_lock_info(); +#else + SharedPart* m_shared_part = nullptr; + +#ifdef _WIN32 + HANDLE m_handle = 0; +#endif + +#endif + friend class InterprocessCondVar; +}; + +inline InterprocessMutex::InterprocessMutex() +{ +#ifdef REALM_ROBUST_MUTEX_EMULATION + std::call_once(s_init_flag, initialize_statics); +#endif +} + +inline InterprocessMutex::~InterprocessMutex() noexcept +{ +#ifdef _WIN32 + if (m_handle) { + bool b = CloseHandle(m_handle); + REALM_ASSERT_RELEASE(b); + } +#endif + +#ifdef REALM_ROBUST_MUTEX_EMULATION + free_lock_info(); +#endif +} + +#ifdef REALM_ROBUST_MUTEX_EMULATION +inline InterprocessMutex::LockInfo::~LockInfo() noexcept +{ + if (m_file.is_attached()) { + m_file.close(); + } +} + +inline void InterprocessMutex::free_lock_info() +{ + // It has not been initialized yet. + if (!m_lock_info) + return; + + std::lock_guard guard(*s_mutex); + + m_lock_info.reset(); + if ((*s_info_map)[m_fileuid].expired()) { + s_info_map->erase(m_fileuid); + } + m_filename.clear(); +} + +inline void InterprocessMutex::initialize_statics() +{ + s_mutex = new Mutex(); + s_info_map = new std::map>(); +} +#endif + +inline void InterprocessMutex::set_shared_part(SharedPart& shared_part, const std::string& path, + const std::string& mutex_name) +{ +#ifdef REALM_ROBUST_MUTEX_EMULATION + static_cast(shared_part); + + free_lock_info(); + + m_filename = path + "." + mutex_name + ".mx"; + + std::lock_guard guard(*s_mutex); + + // Try to get the file uid if the file exists + if (File::get_unique_id(m_filename, m_fileuid)) { + auto result = s_info_map->find(m_fileuid); + if (result != s_info_map->end()) { + // File exists and the lock info has been created in the map. + m_lock_info = result->second.lock(); + return; + } + } + + // LockInfo has not been created yet. + m_lock_info = std::make_shared(); + // Always use mod_Write to open file and retreive the uid in case other process + // deletes the file. + m_lock_info->m_file.open(m_filename, File::mode_Write); + // exFAT does not allocate a unique id for the file until it's non-empty + m_lock_info->m_file.resize(1); + m_fileuid = m_lock_info->m_file.get_unique_id(); + + (*s_info_map)[m_fileuid] = m_lock_info; +#elif defined(_WIN32) + if (m_handle) { + bool b = CloseHandle(m_handle); + REALM_ASSERT_RELEASE(b); + } + // replace backslashes because they're significant in object namespace names + std::string path_escaped = path; + std::replace(path_escaped.begin(), path_escaped.end(), '\\', '/'); + std::string name = "Local\\realm_named_intermutex_" + path_escaped + mutex_name; + + std::wstring wname(name.begin(), name.end()); + m_handle = CreateMutexW(0, false, wname.c_str()); + if (!m_handle) { + throw std::system_error(GetLastError(), std::system_category(), "Error opening mutex"); + } +#else + m_shared_part = &shared_part; + static_cast(path); + static_cast(mutex_name); +#endif +} + +inline void InterprocessMutex::set_shared_part(SharedPart& shared_part, File&& lock_file) +{ +#ifdef REALM_ROBUST_MUTEX_EMULATION + static_cast(shared_part); + + free_lock_info(); + + std::lock_guard guard(*s_mutex); + + m_fileuid = lock_file.get_unique_id(); + auto result = s_info_map->find(m_fileuid); + if (result == s_info_map->end()) { + m_lock_info = std::make_shared(); + m_lock_info->m_file = std::move(lock_file); + (*s_info_map)[m_fileuid] = m_lock_info; + } + else { + // File exists and the lock info has been created in the map. + m_lock_info = result->second.lock(); + lock_file.close(); + } +#else + m_shared_part = &shared_part; + static_cast(lock_file); +#endif +} + +inline void InterprocessMutex::release_shared_part() +{ +#ifdef REALM_ROBUST_MUTEX_EMULATION + if (!m_filename.empty()) + File::try_remove(m_filename); + + free_lock_info(); +#else + m_shared_part = nullptr; +#endif +} + +inline void InterprocessMutex::lock() +{ +#ifdef REALM_ROBUST_MUTEX_EMULATION + std::unique_lock mutex_lock(m_lock_info->m_local_mutex); + m_lock_info->m_file.lock_exclusive(); + mutex_lock.release(); +#else + +#ifdef _WIN32 + DWORD d = WaitForSingleObject(m_handle, INFINITE); + REALM_ASSERT_RELEASE(d != WAIT_FAILED); +#else + REALM_ASSERT(m_shared_part); + m_shared_part->lock([]() {}); +#endif +#endif +} + +inline bool InterprocessMutex::try_lock() +{ +#ifdef REALM_ROBUST_MUTEX_EMULATION + std::unique_lock mutex_lock(m_lock_info->m_local_mutex, std::try_to_lock_t()); + if (!mutex_lock.owns_lock()) { + return false; + } + bool success = m_lock_info->m_file.try_lock_exclusive(); + if (success) { + mutex_lock.release(); + return true; + } + else { + return false; + } +#else + +#ifdef _WIN32 + DWORD ret = WaitForSingleObject(m_handle, 0); + REALM_ASSERT_RELEASE(ret != WAIT_FAILED); + + if (ret == WAIT_OBJECT_0) { + return true; + } + else { + return false; + } +#else + REALM_ASSERT(m_shared_part); + return m_shared_part->try_lock([]() {}); +#endif +#endif +} + + +inline void InterprocessMutex::unlock() +{ +#ifdef REALM_ROBUST_MUTEX_EMULATION + m_lock_info->m_file.unlock(); + m_lock_info->m_local_mutex.unlock(); +#else +#ifdef _WIN32 + bool b = ReleaseMutex(m_handle); + REALM_ASSERT_RELEASE(b); +#else + REALM_ASSERT(m_shared_part); + m_shared_part->unlock(); +#endif +#endif +} + + +inline bool InterprocessMutex::is_valid() noexcept +{ +#ifdef REALM_ROBUST_MUTEX_EMULATION + return true; +#elif defined(_WIN32) + // There is no safe way of testing if the m_handle mutex handle is valid on Windows, without having bad side effects + // for the cases where it is indeed invalid. If m_handle contains an arbitrary value, it might by coincidence be equal + // to a real live handle of another kind. This excludes a try_lock implementation and many other ideas. + return true; +#else + REALM_ASSERT(m_shared_part); + return m_shared_part->is_valid(); +#endif +} + + +} // namespace util +} // namespace realm + +#endif // #ifndef REALM_UTIL_INTERPROCESS_MUTEX diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/json_parser.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/json_parser.hpp new file mode 100644 index 0000000..0a22e1d --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/json_parser.hpp @@ -0,0 +1,535 @@ +#ifndef REALM_UTIL_JSON_PARSER_HPP +#define REALM_UTIL_JSON_PARSER_HPP + +#include +#include +#include +#include + +#include + +namespace realm { +namespace util { + +/// A JSON parser that neither allocates heap memory nor throws exceptions. +/// +/// The parser takes as input a range of characters, and emits a stream of events +/// representing the structure of the JSON document. +/// +/// Parser errors are represented as `std::error_condition`s. +class JSONParser { +public: + using InputIterator = const char*; + + enum class EventType { number, string, boolean, null, array_begin, array_end, object_begin, object_end }; + + using Range = StringData; + + struct Event { + EventType type; + Range range; + Event(EventType type) + : type(type) + { + } + + union { + bool boolean; + double number; + }; + + StringData escaped_string_value() const noexcept; + + /// Unescape the string value into \a buffer. + /// The type of this event must be EventType::string. + /// + /// \param buffer is a pointer to a buffer big enough to hold the + /// unescaped string value. The unescaped string is guaranteed to be + /// shorter than the escaped string, so escaped_string_value().size() can + /// be used as an upper bound. Unicode sequences of the form "\uXXXX" + /// will be converted to UTF-8 sequences. Note that the escaped form of + /// a unicode point takes exactly 6 bytes, which is also the maximum + /// possible length of a UTF-8 encoded codepoint. + StringData unescape_string(char* buffer) const noexcept; + }; + + enum class Error { unexpected_token = 1, unexpected_end_of_stream = 2 }; + + JSONParser(StringData); + + /// Parse the input data, and call f repeatedly with an argument of type Event + /// representing the token that the parser encountered. + /// + /// The stream of events is "flat", which is to say that it is the responsibility + /// of the function f to keep track of any nested object structures as it deems + /// appropriate. + /// + /// This function is guaranteed to never throw, as long as f never throws. + template + std::error_condition parse(F&& f) noexcept(noexcept(f(std::declval()))); + + class ErrorCategory : public std::error_category { + public: + const char* name() const noexcept final; + std::string message(int) const final; + }; + static const ErrorCategory error_category; + +private: + enum Token : char { + object_begin = '{', + object_end = '}', + array_begin = '[', + array_end = ']', + colon = ':', + comma = ',', + dquote = '"', + escape = '\\', + minus = '-', + space = ' ', + tab = '\t', + cr = '\r', + lf = '\n', + }; + + InputIterator m_current; + InputIterator m_end; + + template + std::error_condition parse_object(F&& f) noexcept(noexcept(f(std::declval()))); + template + std::error_condition parse_pair(F&& f) noexcept(noexcept(f(std::declval()))); + template + std::error_condition parse_array(F&& f) noexcept(noexcept(f(std::declval()))); + template + std::error_condition parse_number(F&& f) noexcept(noexcept(f(std::declval()))); + template + std::error_condition parse_string(F&& f) noexcept(noexcept(f(std::declval()))); + template + std::error_condition parse_value(F&& f) noexcept(noexcept(f(std::declval()))); + template + std::error_condition parse_boolean(F&& f) noexcept(noexcept(f(std::declval()))); + template + std::error_condition parse_null(F&& f) noexcept(noexcept(f(std::declval()))); + + std::error_condition expect_token(char, Range& out_range) noexcept; + std::error_condition expect_token(Token, Range& out_range) noexcept; + + // Returns true unless EOF was reached. + bool peek_char(char& out_c) noexcept; + bool peek_token(Token& out_t) noexcept; + bool is_whitespace(Token t) noexcept; + void skip_whitespace() noexcept; +}; + +std::error_condition make_error_condition(JSONParser::Error e); + +} // namespace util +} // namespace realm + +namespace std { +template <> +struct is_error_condition_enum { + static const bool value = true; +}; +} // namespace std + +namespace realm { +namespace util { + +/// Implementation: + + +inline JSONParser::JSONParser(StringData input) + : m_current(input.data()) + , m_end(input.data() + input.size()) +{ +} + +template +std::error_condition JSONParser::parse(F&& f) noexcept(noexcept(f(std::declval()))) +{ + return parse_value(f); +} + +template +std::error_condition JSONParser::parse_object(F&& f) noexcept(noexcept(f(std::declval()))) +{ + Event event{EventType::object_begin}; + auto ec = expect_token(Token::object_begin, event.range); + if (ec) + return ec; + ec = f(event); + if (ec) + return ec; + + while (true) { + ec = expect_token(Token::object_end, event.range); + if (!ec) { + // End of object + event.type = EventType::object_end; + ec = f(event); + if (ec) + return ec; + break; + } + + if (ec != Error::unexpected_token) + return ec; + + ec = parse_pair(f); + if (ec) + return ec; + + skip_whitespace(); + + Token t; + if (peek_token(t)) { + if (t == Token::object_end) { + // Fine, will terminate on next iteration + } + else if (t == Token::comma) + ++m_current; // OK, because peek_char returned true + else + return Error::unexpected_token; + } + else { + return Error::unexpected_end_of_stream; + } + } + + return std::error_condition{}; +} + +template +std::error_condition JSONParser::parse_pair(F&& f) noexcept(noexcept(f(std::declval()))) +{ + skip_whitespace(); + + auto ec = parse_string(f); + if (ec) + return ec; + + skip_whitespace(); + + Token t; + if (peek_token(t)) { + if (t == Token::colon) { + ++m_current; + } + else { + return Error::unexpected_token; + } + } + + return parse_value(f); +} + +template +std::error_condition JSONParser::parse_array(F&& f) noexcept(noexcept(f(std::declval()))) +{ + Event event{EventType::array_begin}; + auto ec = expect_token(Token::array_begin, event.range); + if (ec) + return ec; + ec = f(event); + if (ec) + return ec; + + while (true) { + ec = expect_token(Token::array_end, event.range); + if (!ec) { + // End of array + event.type = EventType::array_end; + ec = f(event); + if (ec) + return ec; + break; + } + + if (ec != Error::unexpected_token) + return ec; + + ec = parse_value(f); + if (ec) + return ec; + + skip_whitespace(); + + Token t; + if (peek_token(t)) { + if (t == Token::array_end) { + // Fine, will terminate next iteration. + } + else if (t == Token::comma) + ++m_current; // OK, because peek_char returned true + else + return Error::unexpected_token; + } + else { + return Error::unexpected_end_of_stream; + } + } + + return std::error_condition{}; +} + +template +std::error_condition JSONParser::parse_number(F&& f) noexcept(noexcept(f(std::declval()))) +{ + static const size_t buffer_size = 64; + char buffer[buffer_size] = {0}; + size_t bytes_to_copy = std::min(m_end - m_current, buffer_size - 1); + if (bytes_to_copy == 0) + return Error::unexpected_end_of_stream; + + if (std::isspace(*m_current)) { + // JSON has a different idea of what constitutes whitespace than isspace(), + // but strtod() uses isspace() to skip initial whitespace. We have already + // skipped whitespace that JSON considers valid, so if there is any whitespace + // at m_current now, it is invalid according to JSON, and so is an error. + return Error::unexpected_token; + } + + switch (m_current[0]) { + case 'N': + // strtod() parses "NAN", JSON does not. + case 'I': + // strtod() parses "INF", JSON does not. + case 'p': + case 'P': + // strtod() may parse exponent notation, JSON does not. + return Error::unexpected_token; + case '0': + if (bytes_to_copy > 2 && (m_current[1] == 'x' || m_current[1] == 'X')) { + // strtod() parses hexadecimal, JSON does not. + return Error::unexpected_token; + } + } + + std::copy(m_current, m_current + bytes_to_copy, buffer); + + char* endp = nullptr; + Event event{EventType::number}; + event.number = std::strtod(buffer, &endp); + + if (endp == buffer) { + return Error::unexpected_token; + } + size_t num_bytes_consumed = endp - buffer; + m_current += num_bytes_consumed; + return f(event); +} + +template +std::error_condition JSONParser::parse_string(F&& f) noexcept(noexcept(f(std::declval()))) +{ + InputIterator p = m_current; + if (p >= m_end) + return Error::unexpected_end_of_stream; + + auto count_num_escapes_backwards = [](const char* p, const char* begin) -> size_t { + size_t result = 0; + for (; p > begin && *p == Token::escape; ++p) + ++result; + return result; + }; + + Token t = static_cast(*p); + InputIterator inner_end; + if (t == Token::dquote) { + inner_end = m_current; + do { + inner_end = std::find(inner_end + 1, m_end, Token::dquote); + if (inner_end == m_end) + return Error::unexpected_end_of_stream; + } while (count_num_escapes_backwards(inner_end - 1, m_current) % 2 == 1); + + Event event{EventType::string}; + event.range = Range(m_current, inner_end - m_current + 1); + m_current = inner_end + 1; + return f(event); + } + return Error::unexpected_token; +} + +template +std::error_condition JSONParser::parse_boolean(F&& f) noexcept(noexcept(f(std::declval()))) +{ + auto first_nonalpha = std::find_if_not(m_current, m_end, [](auto c) { + return std::isalpha(c); + }); + + Event event{EventType::boolean}; + event.range = Range(m_current, first_nonalpha - m_current); + if (event.range == "true") { + event.boolean = true; + m_current += 4; + return f(event); + } + else if (event.range == "false") { + event.boolean = false; + m_current += 5; + return f(event); + } + + return Error::unexpected_token; +} + +template +std::error_condition JSONParser::parse_null(F&& f) noexcept(noexcept(f(std::declval()))) +{ + auto first_nonalpha = std::find_if_not(m_current, m_end, [](auto c) { + return std::isalpha(c); + }); + + Event event{EventType::null}; + event.range = Range(m_current, first_nonalpha - m_current); + if (event.range == "null") { + m_current += 4; + return f(event); + } + + return Error::unexpected_token; +} + +template +std::error_condition JSONParser::parse_value(F&& f) noexcept(noexcept(f(std::declval()))) +{ + skip_whitespace(); + + if (m_current >= m_end) + return Error::unexpected_end_of_stream; + + if (*m_current == Token::object_begin) + return parse_object(f); + + if (*m_current == Token::array_begin) + return parse_array(f); + + if (*m_current == 't' || *m_current == 'f') + return parse_boolean(f); + + if (*m_current == 'n') + return parse_null(f); + + if (*m_current == Token::dquote) + return parse_string(f); + + return parse_number(f); +} + +inline bool JSONParser::is_whitespace(Token t) noexcept +{ + switch (t) { + case Token::space: + case Token::tab: + case Token::cr: + case Token::lf: + return true; + default: + return false; + } +} + +inline void JSONParser::skip_whitespace() noexcept +{ + while (m_current < m_end && is_whitespace(static_cast(*m_current))) + ++m_current; +} + +inline std::error_condition JSONParser::expect_token(char c, Range& out_range) noexcept +{ + skip_whitespace(); + if (m_current == m_end) + return Error::unexpected_end_of_stream; + if (*m_current == c) { + out_range = Range(m_current, 1); + ++m_current; + return std::error_condition{}; + } + return Error::unexpected_token; +} + +inline std::error_condition JSONParser::expect_token(Token t, Range& out_range) noexcept +{ + return expect_token(static_cast(t), out_range); +} + +inline bool JSONParser::peek_char(char& out_c) noexcept +{ + if (m_current < m_end) { + out_c = *m_current; + return true; + } + return false; +} + +inline bool JSONParser::peek_token(Token& out_t) noexcept +{ + if (m_current < m_end) { + out_t = static_cast(*m_current); + return true; + } + return false; +} + +inline StringData JSONParser::Event::escaped_string_value() const noexcept +{ + REALM_ASSERT(type == EventType::string); + REALM_ASSERT(range.size() >= 2); + return StringData(range.data() + 1, range.size() - 2); +} + +template +OS& operator<<(OS& os, JSONParser::EventType type) +{ + switch (type) { + case JSONParser::EventType::number: + os << "number"; + return os; + case JSONParser::EventType::string: + os << "string"; + return os; + case JSONParser::EventType::boolean: + os << "boolean"; + return os; + case JSONParser::EventType::null: + os << "null"; + return os; + case JSONParser::EventType::array_begin: + os << "["; + return os; + case JSONParser::EventType::array_end: + os << "]"; + return os; + case JSONParser::EventType::object_begin: + os << "{"; + return os; + case JSONParser::EventType::object_end: + os << "}"; + return os; + } + REALM_UNREACHABLE(); +} + +template +OS& operator<<(OS& os, const JSONParser::Event& e) +{ + os << e.type; + switch (e.type) { + case JSONParser::EventType::number: + return os << "(" << e.number << ")"; + case JSONParser::EventType::string: + return os << "(" << e.range << ")"; + case JSONParser::EventType::boolean: + return os << "(" << e.boolean << ")"; + default: + return os; + } +} + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_JSON_PARSER_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/load_file.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/load_file.hpp new file mode 100644 index 0000000..c12613a --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/load_file.hpp @@ -0,0 +1,17 @@ +#ifndef REALM_UTIL_LOAD_FILE_HPP +#define REALM_UTIL_LOAD_FILE_HPP + +#include + +namespace realm { +namespace util { + +// FIXME: These functions ought to be moved to in the +// realm-core repository. +std::string load_file(const std::string& path); +std::string load_file_and_chomp(const std::string& path); + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_LOAD_FILE_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/logger.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/logger.hpp new file mode 100644 index 0000000..0946208 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/logger.hpp @@ -0,0 +1,511 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_UTIL_LOGGER_HPP +#define REALM_UTIL_LOGGER_HPP + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace realm { +namespace util { + + +/// All Logger objects store a reference to a LevelThreshold object which it +/// uses to efficiently query about the current log level threshold +/// (`level_threshold.get()`). All messages logged with a level that is lower +/// than the current threshold will be dropped. For the sake of efficiency, this +/// test happens before the message is formatted. +/// +/// A logger is not inherently thread-safe, but specific implementations can be +/// (see ThreadSafeLogger). For a logger to be thread-safe, the implementation +/// of do_log() must be thread-safe and the referenced LevelThreshold object +/// must have a thread-safe get() method. +/// +/// Examples: +/// +/// logger.error("Overlong message from master coordinator"); +/// logger.info("Listening for peers on %1:%2", listen_address, listen_port); +class Logger { +public: + template + void trace(const char* message, Params&&...); + template + void debug(const char* message, Params&&...); + template + void detail(const char* message, Params&&...); + template + void info(const char* message, Params&&...); + template + void warn(const char* message, Params&&...); + template + void error(const char* message, Params&&...); + template + void fatal(const char* message, Params&&...); + + /// Specifies criticality when passed to log(). Functions as a criticality + /// threshold when returned from LevelThreshold::get(). + /// + /// error Be silent unless when there is an error. + /// warn Be silent unless when there is an error or a warning. + /// info Reveal information about what is going on, but in a + /// minimalistic fashion to avoid general overhead from logging + /// and to keep volume down. + /// detail Same as 'info', but prioritize completeness over minimalism. + /// debug Reveal information that can aid debugging, no longer paying + /// attention to efficiency. + /// trace A version of 'debug' that allows for very high volume + /// output. + enum class Level { all, trace, debug, detail, info, warn, error, fatal, off }; + + template + void log(Level, const char* message, Params&&...); + + /// Shorthand for `int(level) >= int(level_threshold.get())`. + bool would_log(Level level) const noexcept; + + class LevelThreshold; + + const LevelThreshold& level_threshold; + + virtual ~Logger() noexcept; + +protected: + Logger(const LevelThreshold&) noexcept; + + static void do_log(Logger&, Level, std::string message); + + virtual void do_log(Level, std::string message) = 0; + + static const char* get_level_prefix(Level) noexcept; + +private: + struct State; + + template + REALM_NOINLINE void do_log(Level, const char* message, Params&&...); + void log_impl(State&); + template + void log_impl(State&, Param&&, Params&&...); + template + static void subst(State&, Param&&); +}; + +template +std::basic_ostream& operator<<(std::basic_ostream&, Logger::Level); + +template +std::basic_istream& operator>>(std::basic_istream&, Logger::Level&); + +class Logger::LevelThreshold { +public: + virtual Level get() const noexcept = 0; +}; + + +/// A root logger that is not thread-safe and allows for the log level threshold +/// to be changed over time. The initial log level threshold is +/// Logger::Level::info. +class RootLogger : private Logger::LevelThreshold, public Logger { +public: + void set_level_threshold(Level) noexcept; + +protected: + RootLogger(); + +private: + Level m_level_threshold = Level::info; + Level get() const noexcept override final; +}; + + +/// A logger that writes to STDERR. This logger is not thread-safe. +/// +/// Since this class is a RootLogger, it contains modifiable a log level +/// threshold. +class StderrLogger : public RootLogger { +protected: + void do_log(Level, std::string) override final; +}; + + +/// A logger that writes to a stream. This logger is not thread-safe. +/// +/// Since this class is a RootLogger, it contains modifiable a log level +/// threshold. +class StreamLogger : public RootLogger { +public: + explicit StreamLogger(std::ostream&) noexcept; + +protected: + void do_log(Level, std::string) override final; + +private: + std::ostream& m_out; +}; + + +/// A logger that writes to a file. This logger is not thread-safe. +/// +/// Since this class is a RootLogger, it contains modifiable a log level +/// threshold. +class FileLogger : public StreamLogger { +public: + explicit FileLogger(std::string path); + explicit FileLogger(util::File); + +private: + util::File m_file; + util::File::Streambuf m_streambuf; + std::ostream m_out; +}; + + +/// A thread-safe logger. This logger ignores the level threshold of the base +/// logger. Instead, it introduces new a LevelThreshold object with a fixed +/// value to achieve thread safety. +class ThreadSafeLogger : private Logger::LevelThreshold, public Logger { +public: + explicit ThreadSafeLogger(Logger& base_logger, Level = Level::info); + +protected: + void do_log(Level, std::string) override final; + +private: + const Level m_level_threshold; // Immutable for thread safety + Logger& m_base_logger; + Mutex m_mutex; + Level get() const noexcept override final; +}; + + +/// A logger that adds a fixed prefix to each message. This logger inherits the +/// LevelThreshold object of the specified base logger. This logger is +/// thread-safe if, and only if the base logger is thread-safe. +class PrefixLogger : public Logger { +public: + PrefixLogger(std::string prefix, Logger& base_logger) noexcept; + +protected: + void do_log(Level, std::string) override final; + +private: + const std::string m_prefix; + Logger& m_base_logger; +}; + + +// Implementation + +struct Logger::State { + Logger::Level m_level; + std::string m_message; + std::string m_search; + int m_param_num = 1; + std::ostringstream m_formatter; + std::locale m_locale = std::locale::classic(); + State(Logger::Level level, const char* s) + : m_level(level) + , m_message(s) + , m_search(m_message) + { + m_formatter.imbue(m_locale); + } +}; + +template +inline void Logger::trace(const char* message, Params&&... params) +{ + log(Level::trace, message, std::forward(params)...); // Throws +} + +template +inline void Logger::debug(const char* message, Params&&... params) +{ + log(Level::debug, message, std::forward(params)...); // Throws +} + +template +inline void Logger::detail(const char* message, Params&&... params) +{ + log(Level::detail, message, std::forward(params)...); // Throws +} + +template +inline void Logger::info(const char* message, Params&&... params) +{ + log(Level::info, message, std::forward(params)...); // Throws +} + +template +inline void Logger::warn(const char* message, Params&&... params) +{ + log(Level::warn, message, std::forward(params)...); // Throws +} + +template +inline void Logger::error(const char* message, Params&&... params) +{ + log(Level::error, message, std::forward(params)...); // Throws +} + +template +inline void Logger::fatal(const char* message, Params&&... params) +{ + log(Level::fatal, message, std::forward(params)...); // Throws +} + +template +inline void Logger::log(Level level, const char* message, Params&&... params) +{ + if (would_log(level)) + do_log(level, message, std::forward(params)...); // Throws +} + +inline bool Logger::would_log(Level level) const noexcept +{ + return int(level) >= int(level_threshold.get()); +} + +inline Logger::~Logger() noexcept +{ +} + +inline Logger::Logger(const LevelThreshold& lt) noexcept + : level_threshold(lt) +{ +} + +inline void Logger::do_log(Logger& logger, Level level, std::string message) +{ + logger.do_log(level, std::move(message)); // Throws +} + +template +void Logger::do_log(Level level, const char* message, Params&&... params) +{ + State state(level, message); + log_impl(state, std::forward(params)...); // Throws +} + +inline void Logger::log_impl(State& state) +{ + do_log(state.m_level, std::move(state.m_message)); // Throws +} + +template +inline void Logger::log_impl(State& state, Param&& param, Params&&... params) +{ + subst(state, std::forward(param)); // Throws + log_impl(state, std::forward(params)...); // Throws +} + +template +void Logger::subst(State& state, Param&& param) +{ + state.m_formatter << "%" << state.m_param_num; + std::string key = state.m_formatter.str(); + state.m_formatter.str(std::string()); + std::string::size_type j = state.m_search.find(key); + if (j != std::string::npos) { + state.m_formatter << std::forward(param); + std::string str = state.m_formatter.str(); + state.m_formatter.str(std::string()); + state.m_message.replace(j, key.size(), str); + state.m_search.replace(j, key.size(), std::string(str.size(), '\0')); + } + ++state.m_param_num; +} + +template +std::basic_ostream& operator<<(std::basic_ostream& out, Logger::Level level) +{ + switch (level) { + case Logger::Level::all: + out << "all"; + return out; + case Logger::Level::trace: + out << "trace"; + return out; + case Logger::Level::debug: + out << "debug"; + return out; + case Logger::Level::detail: + out << "detail"; + return out; + case Logger::Level::info: + out << "info"; + return out; + case Logger::Level::warn: + out << "warn"; + return out; + case Logger::Level::error: + out << "error"; + return out; + case Logger::Level::fatal: + out << "fatal"; + return out; + case Logger::Level::off: + out << "off"; + return out; + } + REALM_ASSERT(false); + return out; +} + +template +std::basic_istream& operator>>(std::basic_istream& in, Logger::Level& level) +{ + std::basic_string str; + auto check = [&](const char* name) { + size_t n = strlen(name); + if (n != str.size()) + return false; + for (size_t i = 0; i < n; ++i) { + if (in.widen(name[i]) != str[i]) + return false; + } + return true; + }; + if (in >> str) { + if (check("all")) { + level = Logger::Level::all; + } + else if (check("trace")) { + level = Logger::Level::trace; + } + else if (check("debug")) { + level = Logger::Level::debug; + } + else if (check("detail")) { + level = Logger::Level::detail; + } + else if (check("info")) { + level = Logger::Level::info; + } + else if (check("warn")) { + level = Logger::Level::warn; + } + else if (check("error")) { + level = Logger::Level::error; + } + else if (check("fatal")) { + level = Logger::Level::fatal; + } + else if (check("off")) { + level = Logger::Level::off; + } + else { + in.setstate(std::ios_base::failbit); + } + } + return in; +} + +inline void RootLogger::set_level_threshold(Level new_level_threshold) noexcept +{ + m_level_threshold = new_level_threshold; +} + +inline RootLogger::RootLogger() + : Logger::LevelThreshold() + , Logger(static_cast(*this)) +{ +} + +inline Logger::Level RootLogger::get() const noexcept +{ + return m_level_threshold; +} + +inline void StderrLogger::do_log(Level level, std::string message) +{ + std::cerr << get_level_prefix(level) << message << '\n'; // Throws + std::cerr.flush(); // Throws +} + +inline StreamLogger::StreamLogger(std::ostream& out) noexcept + : m_out(out) +{ +} + +inline void StreamLogger::do_log(Level level, std::string message) +{ + m_out << get_level_prefix(level) << message << '\n'; // Throws + m_out.flush(); // Throws +} + +inline FileLogger::FileLogger(std::string path) + : StreamLogger(m_out) + , m_file(path, util::File::mode_Write) // Throws + , m_streambuf(&m_file) // Throws + , m_out(&m_streambuf) // Throws +{ +} + +inline FileLogger::FileLogger(util::File file) + : StreamLogger(m_out) + , m_file(std::move(file)) + , m_streambuf(&m_file) // Throws + , m_out(&m_streambuf) // Throws +{ +} + +inline ThreadSafeLogger::ThreadSafeLogger(Logger& base_logger, Level threshold) + : Logger::LevelThreshold() + , Logger(static_cast(*this)) + , m_level_threshold(threshold) + , m_base_logger(base_logger) +{ +} + +inline void ThreadSafeLogger::do_log(Level level, std::string message) +{ + LockGuard l(m_mutex); + Logger::do_log(m_base_logger, level, message); // Throws +} + +inline Logger::Level ThreadSafeLogger::get() const noexcept +{ + return m_level_threshold; +} + +inline PrefixLogger::PrefixLogger(std::string prefix, Logger& base_logger) noexcept + : Logger(base_logger.level_threshold) + , m_prefix(std::move(prefix)) + , m_base_logger(base_logger) +{ +} + +inline void PrefixLogger::do_log(Level level, std::string message) +{ + Logger::do_log(m_base_logger, level, m_prefix + message); // Throws +} + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_LOGGER_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/memory_stream.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/memory_stream.hpp new file mode 100644 index 0000000..81a4852 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/memory_stream.hpp @@ -0,0 +1,212 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_UTIL_MEMORY_STREAM_HPP +#define REALM_UTIL_MEMORY_STREAM_HPP + +#include +#include +#include +#include + +namespace realm { +namespace util { + +class MemoryInputStreambuf : public std::streambuf { +public: + MemoryInputStreambuf(); + ~MemoryInputStreambuf() noexcept; + + /// Behavior is undefined if the size of the specified buffer exceeds + /// PTRDIFF_MAX. + void set_buffer(const char* begin, const char* end) noexcept; + +private: + const char* m_begin; + const char* m_end; + const char* m_curr; + + int_type underflow() override; + int_type uflow() override; + int_type pbackfail(int_type) override; + std::streamsize showmanyc() override; + pos_type seekoff(off_type, std::ios_base::seekdir, std::ios_base::openmode) override; + pos_type seekpos(pos_type, std::ios_base::openmode) override; + + pos_type do_seekoff(off_type, std::ios_base::seekdir, std::ios_base::openmode); +}; + + +class MemoryOutputStreambuf : public std::streambuf { +public: + MemoryOutputStreambuf(); + ~MemoryOutputStreambuf() noexcept; + + /// Behavior is undefined if the size of the specified buffer exceeds + /// PTRDIFF_MAX. + void set_buffer(char* begin, char* end) noexcept; + + /// Returns the amount of data written to the buffer. + size_t size() const noexcept; +}; + + +class MemoryInputStream : public std::istream { +public: + MemoryInputStream(); + ~MemoryInputStream() noexcept; + + /// \{ Behavior is undefined if the size of the specified buffer exceeds + /// PTRDIFF_MAX. + void set_buffer(const char* begin, const char* end) noexcept; + template void set_buffer(const char (&buffer)[N]) noexcept; + void set_string(const std::string&) noexcept; + void set_c_string(const char* c_str) noexcept; + /// \} + +private: + MemoryInputStreambuf m_streambuf; +}; + + +class MemoryOutputStream : public std::ostream { +public: + MemoryOutputStream(); + ~MemoryOutputStream() noexcept; + + /// \{ Behavior is undefined if the size of the specified buffer exceeds + /// PTRDIFF_MAX. + void set_buffer(char* begin, char* end) noexcept; + template void set_buffer(char (&buffer)[N]) noexcept; + /// \} + + /// Returns the amount of data written to the underlying buffer. + size_t size() const noexcept; + +private: + MemoryOutputStreambuf m_streambuf; +}; + + +// Implementation + +inline MemoryInputStreambuf::MemoryInputStreambuf() + : m_begin(nullptr) + , m_end(nullptr) + , m_curr(nullptr) +{ +} + +inline MemoryInputStreambuf::~MemoryInputStreambuf() noexcept +{ +} + +inline void MemoryInputStreambuf::set_buffer(const char* b, const char* e) noexcept +{ + m_begin = b; + m_end = e; + m_curr = b; +} + + +inline MemoryOutputStreambuf::MemoryOutputStreambuf() +{ +} + +inline MemoryOutputStreambuf::~MemoryOutputStreambuf() noexcept +{ +} + +inline void MemoryOutputStreambuf::set_buffer(char* b, char* e) noexcept +{ + setp(b, e); +} + +inline size_t MemoryOutputStreambuf::size() const noexcept +{ + return pptr() - pbase(); +} + + +inline MemoryInputStream::MemoryInputStream() + : std::istream(&m_streambuf) +{ +} + +inline MemoryInputStream::~MemoryInputStream() noexcept +{ +} + +inline void MemoryInputStream::set_buffer(const char* b, const char* e) noexcept +{ + m_streambuf.set_buffer(b, e); + clear(); +} + +template inline void MemoryInputStream::set_buffer(const char (&buffer)[N]) noexcept +{ + const char* b = buffer; + const char* e = b + N; + set_buffer(b, e); +} + +inline void MemoryInputStream::set_string(const std::string& str) noexcept +{ + const char* b = str.data(); + const char* e = b + str.size(); + set_buffer(b, e); +} + +inline void MemoryInputStream::set_c_string(const char* c_str) noexcept +{ + const char* b = c_str; + const char* e = b + traits_type::length(c_str); + set_buffer(b, e); +} + + +inline MemoryOutputStream::MemoryOutputStream() + : std::ostream(&m_streambuf) +{ +} + +inline MemoryOutputStream::~MemoryOutputStream() noexcept +{ +} + +inline void MemoryOutputStream::set_buffer(char* b, char* e) noexcept +{ + m_streambuf.set_buffer(b, e); + clear(); +} + +template +inline void MemoryOutputStream::set_buffer(char (&buffer)[N]) noexcept +{ + set_buffer(buffer, buffer + N); +} + +inline size_t MemoryOutputStream::size() const noexcept +{ + return m_streambuf.size(); +} + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_MEMORY_STREAM_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/metered/deque.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/metered/deque.hpp new file mode 100644 index 0000000..66c9387 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/metered/deque.hpp @@ -0,0 +1,18 @@ +#ifndef REALM_UTIL_METERED_DEQUE_HPP +#define REALM_UTIL_METERED_DEQUE_HPP + +#include +#include + +namespace realm { +namespace util { +namespace metered { +/// Vector with metered allocation +template > +using deque = std::deque; +} // namespace metered +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_METERED_DEQUE_HPP + diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/metered/map.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/metered/map.hpp new file mode 100644 index 0000000..e88e20d --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/metered/map.hpp @@ -0,0 +1,22 @@ +#ifndef REALM_UTIL_METERED_MAP_HPP +#define REALM_UTIL_METERED_MAP_HPP + +#include +#include + +namespace realm { +namespace util { +namespace metered { +/// Map with metered allocation. Additionally, the default Compare is changed to +/// `std::less<>` instead of `std::less`, which allows heterogenous lookup. +template , + class Alloc = MeteredSTLAllocator>> +using map = std::map; +} // namespace metered +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_METERED_MAP_HPP + diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/metered/set.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/metered/set.hpp new file mode 100644 index 0000000..4863d3f --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/metered/set.hpp @@ -0,0 +1,19 @@ +#ifndef REALM_UTIL_METERED_SET_HPP +#define REALM_UTIL_METERED_SET_HPP + +#include +#include + +namespace realm { +namespace util { +namespace metered { +/// Set with metered allocation. Additionally, the default Compare is changed to +/// `std::less<>` instead of `std::less`, which allows heterogenous lookup. +template , class Alloc = MeteredSTLAllocator> +using set = std::set; +} // namespace metered +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_METERED_SET_HPP + diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/metered/string.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/metered/string.hpp new file mode 100644 index 0000000..c608f4e --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/metered/string.hpp @@ -0,0 +1,17 @@ +#ifndef REALM_UTIL_METERED_STRING_HPP +#define REALM_UTIL_METERED_STRING_HPP + +#include +#include + +namespace realm { +namespace util { +namespace metered { +/// String with metered allocation +using string = std::basic_string, MeteredSTLAllocator>; +} // namespace metered +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_METERED_STRING_HPP + diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/metered/unordered_map.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/metered/unordered_map.hpp new file mode 100644 index 0000000..1313ece --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/metered/unordered_map.hpp @@ -0,0 +1,22 @@ +#ifndef REALM_UTIL_METERED_UNORDERED_MAP_HPP +#define REALM_UTIL_METERED_UNORDERED_MAP_HPP + +#include +#include + +namespace realm { +namespace util { +namespace metered { +/// Unordered map with metered allocation +template , + class KeyEqual = std::equal_to, + class Alloc = MeteredSTLAllocator>> +using unordered_map = std::unordered_map; +} // namespace metered +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_METERED_UNORDERED_MAP_HPP + diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/metered/unordered_set.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/metered/unordered_set.hpp new file mode 100644 index 0000000..4eb5b75 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/metered/unordered_set.hpp @@ -0,0 +1,21 @@ +#ifndef REALM_UTIL_METERED_UNORDERED_SET_HPP +#define REALM_UTIL_METERED_UNORDERED_SET_HPP + +#include +#include + +namespace realm { +namespace util { +namespace metered { +/// Unordered set with metered allocation +template , + class KeyEqual = std::equal_to, + class Alloc = MeteredSTLAllocator> +using unordered_set = std::unordered_set; +} // namespace metered +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_METERED_UNORDERED_SET_HPP + diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/metered/vector.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/metered/vector.hpp new file mode 100644 index 0000000..dc5be80 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/metered/vector.hpp @@ -0,0 +1,18 @@ +#ifndef REALM_UTIL_METERED_VECTOR_HPP +#define REALM_UTIL_METERED_VECTOR_HPP + +#include +#include + +namespace realm { +namespace util { +namespace metered { +/// Vector with metered allocation +template > +using vector = std::vector; +} // namespace metered +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_METERED_VECTOR_HPP + diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/misc_errors.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/misc_errors.hpp new file mode 100644 index 0000000..9335ba9 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/misc_errors.hpp @@ -0,0 +1,49 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_UTIL_MISC_ERRORS_HPP +#define REALM_UTIL_MISC_ERRORS_HPP + +#include + + +namespace realm { +namespace util { +namespace error { + +enum misc_errors { + unknown = 1, +}; + +std::error_code make_error_code(misc_errors); + +} // namespace error +} // namespace util +} // namespace realm + +namespace std { + +template <> +class is_error_code_enum { +public: + static const bool value = true; +}; + +} // namespace std + +#endif // REALM_UTIL_MISC_ERRORS_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/misc_ext_errors.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/misc_ext_errors.hpp new file mode 100644 index 0000000..5bc20af --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/misc_ext_errors.hpp @@ -0,0 +1,54 @@ +#ifndef REALM_UTIL_MISC_EXT_ERRORS_HPP +#define REALM_UTIL_MISC_EXT_ERRORS_HPP + +#include + +namespace realm { +namespace util { + +/// FIXME: The intention is that this enum will be merged into, and subsumed by +/// util::MiscErrors in `` in the core library. +enum class MiscExtErrors { + /// End of input. + end_of_input = 1, + + /// Premature end of input. That is, end of input at an unexpected, or + /// illegal place in an input stream. + premature_end_of_input, + + /// Delimiter not found. + delim_not_found, + + /// Operation not supported + operation_not_supported, +}; + +class MiscExtErrorCategory : public std::error_category { +public: + const char* name() const noexcept override final; + std::string message(int) const override final; +}; + +/// The error category associated with MiscErrors. The name of this category is +/// `realm.util.misc_ext`. +extern MiscExtErrorCategory misc_ext_error_category; + +inline std::error_code make_error_code(MiscExtErrors err) +{ + return std::error_code(int(err), misc_ext_error_category); +} + +} // namespace util +} // namespace realm + +namespace std { + +template <> +class is_error_code_enum { +public: + static const bool value = true; +}; + +} // namespace std + +#endif // REALM_UTIL_MISC_EXT_ERRORS_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/miscellaneous.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/miscellaneous.hpp new file mode 100644 index 0000000..c45e4f3 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/miscellaneous.hpp @@ -0,0 +1,49 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_UTIL_MISCELLANEOUS_HPP +#define REALM_UTIL_MISCELLANEOUS_HPP + +#include + +namespace realm { +namespace util { + +// FIXME: Replace this with std::add_const_t when we switch over to C++14 by +// default. +/// \brief Adds const qualifier, unless T already has the const qualifier +template +using add_const_t = typename std::add_const::type; + +// FIXME: Replace this with std::as_const when we switch over to C++17 by +// default. +/// \brief Forms an lvalue reference to const T +template +constexpr add_const_t& as_const(T& v) noexcept +{ + return v; +} + +/// \brief Disallows rvalue arguments +template +add_const_t& as_const(const T&&) = delete; + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_MISCELLANEOUS_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/network.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/network.hpp new file mode 100644 index 0000000..615c1c6 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/network.hpp @@ -0,0 +1,3734 @@ +#ifndef REALM_UTIL_NETWORK_HPP +#define REALM_UTIL_NETWORK_HPP + +#include +#include +#include +#include +#include +#include + +#include + +#ifdef _WIN32 +#include +#include +#include +#include +#pragma comment(lib, "Ws2_32.lib") +#else +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +// Linux epoll +// +// Require Linux kernel version >= 2.6.27 such that we have epoll_create1(), +// `O_CLOEXEC`, and `EPOLLRDHUP`. +#if defined(__linux__) && !REALM_ANDROID +#include +#if !defined(REALM_HAVE_EPOLL) +#if !defined(REALM_DISABLE_UTIL_NETWORK_EPOLL) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) +#define REALM_HAVE_EPOLL 1 +#endif +#endif +#endif +#endif +#if !defined(REALM_HAVE_EPOLL) +#define REALM_HAVE_EPOLL 0 +#endif + +// FreeBSD Kqueue. +// +// Available on Mac OS X, FreeBSD, NetBSD, OpenBSD +#if (defined(__MACH__) && defined(__APPLE__)) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) +#if !defined(REALM_HAVE_KQUEUE) +#if !defined(REALM_DISABLE_UTIL_NETWORK_KQUEUE) +#define REALM_HAVE_KQUEUE 1 +#endif +#endif +#endif +#if !defined(REALM_HAVE_KQUEUE) +#define REALM_HAVE_KQUEUE 0 +#endif + + +// FIXME: Unfinished business around `Address::m_ip_v6_scope_id`. + + +namespace realm { +namespace util { + +/// \brief TCP/IP networking API. +/// +/// The design of this networking API is heavily inspired by the ASIO C++ +/// library (http://think-async.com). +/// +/// +/// ### Thread safety +/// +/// A *service context* is a set of objects consisting of an instance of +/// Service, and all the objects that are associated with that instance (\ref +/// Resolver, \ref Socket`, \ref Acceptor`, \ref DeadlineTimer, \ref Trigger, +/// and \ref ssl::Stream). +/// +/// In general, it is unsafe for two threads to call functions on the same +/// object, or on different objects in the same service context. This also +/// applies to destructors. Notable exceptions are the fully thread-safe +/// functions, such as Service::post(), Service::stop(), and Service::reset(). +/// +/// On the other hand, it is always safe for two threads to call functions on +/// objects belonging to different service contexts. +/// +/// One implication of these rules is that at most one thread must execute run() +/// at any given time, and if one thread is executing run(), then no other +/// thread is allowed to access objects in the same service context (with the +/// mentioned exceptions). +/// +/// Unless otherwise specified, free-standing objects, such as \ref +/// StreamProtocol, \ref Address, \ref Endpoint, and \ref Endpoint::List are +/// fully thread-safe as long as they are not mutated. If one thread is mutating +/// such an object, no other thread may access it. Note that these free-standing +/// objects are not associcated with an instance of Service, and are therefore +/// not part of a service context. +/// +/// +/// ### Comparison with ASIO +/// +/// There is a crucial difference between the two libraries in regards to the +/// guarantees that are provided about the cancelability of asynchronous +/// operations. The Realm networking library (this library) considers an +/// asynchronous operation to be complete precisely when the completion handler +/// starts to execute, and it guarantees that such an operation is cancelable up +/// until that point in time. In particular, if `cancel()` is called on a socket +/// or a deadline timer object before the completion handler starts to execute, +/// then that operation will be canceled, and will receive +/// `error::operation_aborted`. This guarantee is possible to provide (and free +/// of ambiguities) precisely because this library prohibits multiple threads +/// from executing the event loop concurrently, and because `cancel()` is +/// allowed to be called only from a completion handler (executed by the event +/// loop thread) or while no thread is executing the event loop. This guarantee +/// allows for safe destruction of sockets and deadline timers as long as the +/// completion handlers react appropriately to `error::operation_aborted`, in +/// particular, that they do not attempt to access the socket or deadline timer +/// object in such cases. +/// +/// ASIO, on the other hand, allows for an asynchronous operation to complete +/// and become **uncancellable** before the completion handler starts to +/// execute. For this reason, it is possible with ASIO to get the completion +/// handler of an asynchronous wait operation to start executing and receive an +/// error code other than "operation aborted" at a point in time where +/// `cancel()` has already been called on the deadline timer object, or even at +/// a point in timer where the deadline timer has been destroyed. This seems +/// like an inevitable consequence of the fact that ASIO allows for multiple +/// threads to execute the event loop concurrently. This generally forces ASIO +/// applications to invent ways of extending the lifetime of deadline timer and +/// socket objects until the completion handler starts executing. +/// +/// IMPORTANT: Even if ASIO is used in a way where at most one thread executes +/// the event loop, there is still no guarantee that an asynchronous operation +/// remains cancelable up until the point in time where the completion handler +/// starts to execute. +namespace network { + +std::string host_name(); + + +class StreamProtocol; +class Address; +class Endpoint; +class Service; +class Resolver; +class SocketBase; +class Socket; +class Acceptor; +class DeadlineTimer; +class Trigger; +class ReadAheadBuffer; +namespace ssl { +class Stream; +} // namespace ssl + + +/// \brief An IP protocol descriptor. +class StreamProtocol { +public: + static StreamProtocol ip_v4(); + static StreamProtocol ip_v6(); + + bool is_ip_v4() const; + bool is_ip_v6() const; + + int protocol() const; + int family() const; + + StreamProtocol(); + ~StreamProtocol() noexcept {} + +private: + int m_family; + int m_socktype; + int m_protocol; + + friend class Service; + friend class SocketBase; +}; + + +/// \brief An IP address (IPv4 or IPv6). +class Address { +public: + bool is_ip_v4() const; + bool is_ip_v6() const; + + template + friend std::basic_ostream& operator<<(std::basic_ostream&, const Address&); + + Address(); + ~Address() noexcept {} + +private: + using ip_v4_type = in_addr; + using ip_v6_type = in6_addr; + union union_type { + ip_v4_type m_ip_v4; + ip_v6_type m_ip_v6; + }; + union_type m_union; + std::uint_least32_t m_ip_v6_scope_id = 0; + bool m_is_ip_v6 = false; + + friend Address make_address(const char*, std::error_code&) noexcept; + friend class Endpoint; +}; + +Address make_address(const char* c_str); +Address make_address(const char* c_str, std::error_code& ec) noexcept; +Address make_address(const std::string&); +Address make_address(const std::string&, std::error_code& ec) noexcept; + + +/// \brief An IP endpoint. +/// +/// An IP endpoint is a triplet (`protocol`, `address`, `port`). +class Endpoint { +public: + using port_type = std::uint_fast16_t; + class List; + + StreamProtocol protocol() const; + Address address() const; + port_type port() const; + + Endpoint(); + Endpoint(const StreamProtocol&, port_type); + Endpoint(const Address&, port_type); + ~Endpoint() noexcept {} + + using data_type = sockaddr; + data_type* data(); + const data_type* data() const; + +private: + StreamProtocol m_protocol; + + using sockaddr_base_type = sockaddr; + using sockaddr_ip_v4_type = sockaddr_in; + using sockaddr_ip_v6_type = sockaddr_in6; + union sockaddr_union_type { + sockaddr_base_type m_base; + sockaddr_ip_v4_type m_ip_v4; + sockaddr_ip_v6_type m_ip_v6; + }; + sockaddr_union_type m_sockaddr_union; + + friend class Service; + friend class Resolver; + friend class SocketBase; + friend class Socket; +}; + + +/// \brief A list of IP endpoints. +class Endpoint::List { +public: + using iterator = const Endpoint*; + + iterator begin() const noexcept; + iterator end() const noexcept; + std::size_t size() const noexcept; + bool empty() const noexcept; + + List() noexcept = default; + List(List&&) noexcept = default; + ~List() noexcept = default; + + List& operator=(List&&) noexcept = default; + +private: + Buffer m_endpoints; + + friend class Service; +}; + + +/// \brief TCP/IP networking service. +class Service { +public: + Service(); + ~Service() noexcept; + + /// \brief Execute the event loop. + /// + /// Execute completion handlers of completed asynchronous operations, or + /// wait for more completion handlers to become ready for + /// execution. Handlers submitted via post() are considered immeditely + /// ready. If there are no completion handlers ready for execution, and + /// there are no asynchronous operations in progress, run() returns. + /// + /// All completion handlers, including handlers submitted via post() will be + /// executed from run(), that is, by the thread that executes run(). If no + /// thread executes run(), then the completion handlers will not be + /// executed. + /// + /// Exceptions thrown by completion handlers will always propagate back + /// through run(). + /// + /// Syncronous operations (e.g., Socket::connect()) execute independently of + /// the event loop, and do not require that any thread calls run(). + void run(); + + /// @{ \brief Stop event loop execution. + /// + /// stop() puts the event loop into the stopped mode. If a thread is + /// currently executing run(), it will be made to return in a timely + /// fashion, that is, without further blocking. If a thread is currently + /// blocked in run(), it will be unblocked. Handlers that can be executed + /// immediately, may, or may not be executed before run() returns, but new + /// handlers submitted by these, will not be executed before run() + /// returns. Also, if a handler is submitted by a call to post, and that + /// call happens after stop() returns, then that handler is guaranteed to + /// not be executed before run() returns (assuming that reset() is not called + /// before run() returns). + /// + /// The event loop will remain in the stopped mode until reset() is + /// called. If reset() is called before run() returns, it may, or may not + /// cause run() to resume normal operation without returning. + /// + /// Both stop() and reset() are thread-safe, that is, they may be called by + /// any thread. Also, both of these function may be called from completion + /// handlers (including posted handlers). + void stop() noexcept; + void reset() noexcept; + /// @} + + /// \brief Submit a handler to be executed by the event loop thread. + /// + /// Register the sepcified completion handler for immediate asynchronous + /// execution. The specified handler will be executed by an expression on + /// the form `handler()`. If the the handler object is movable, it will + /// never be copied. Otherwise, it will be copied as necessary. + /// + /// This function is thread-safe, that is, it may be called by any + /// thread. It may also be called from other completion handlers. + /// + /// The handler will never be called as part of the execution of post(). It + /// will always be called by a thread that is executing run(). If no thread + /// is currently executing run(), the handler will not be executed until a + /// thread starts executing run(). If post() is called while another thread + /// is executing run(), the handler may be called before post() returns. If + /// post() is called from another completion handler, the submitted handler + /// is guaranteed to not be called during the execution of post(). + /// + /// Completion handlers added through post() will be executed in the order + /// that they are added. More precisely, if post() is called twice to add + /// two handlers, A and B, and the execution of post(A) ends before the + /// beginning of the execution of post(B), then A is guaranteed to execute + /// before B. + template + void post(H handler); + + /// Argument `saturation` is the fraction of time that is not spent + /// sleeping. Argument `inefficiency` is the fraction of time not spent + /// sleeping, and not spent executing completion handlers. Both values are + /// guaranteed to always be in the range 0 to 1 (both inclusive). The value + /// passed as `inefficiency` is guaranteed to always be less than, or equal + /// to the value passed as `saturation`. + using EventLoopMetricsHandler = void(double saturation, double inefficiency); + + /// \brief Report event loop metrics via the specified handler. + /// + /// The handler will be called approximately every 30 seconds. + /// + /// report_event_loop_metrics() must be called prior to any invocation of + /// run(). report_event_loop_metrics() is not thread-safe. + /// + /// This feature is only available if + /// `REALM_UTIL_NETWORK_EVENT_LOOP_METRICS` was defined during + /// compilation. When the feature is not available, the specified handler + /// will never be called. + void report_event_loop_metrics(std::function); + +private: + enum class Want { nothing = 0, read, write }; + + template + class OperQueue; + class Descriptor; + class AsyncOper; + class ResolveOperBase; + class WaitOperBase; + class TriggerExecOperBase; + class PostOperBase; + template + class PostOper; + class IoOper; + class UnusedOper; // Allocated, but currently unused memory + + template + class BasicStreamOps; + + struct OwnersOperDeleter { + void operator()(AsyncOper*) const noexcept; + }; + struct LendersOperDeleter { + void operator()(AsyncOper*) const noexcept; + }; + using OwnersOperPtr = std::unique_ptr; + using LendersOperPtr = std::unique_ptr; + using LendersResolveOperPtr = std::unique_ptr; + using LendersWaitOperPtr = std::unique_ptr; + using LendersIoOperPtr = std::unique_ptr; + + class IoReactor; + class Impl; + const std::unique_ptr m_impl; + + template + static std::unique_ptr alloc(OwnersOperPtr&, Args&&...); + + using PostOperConstr = PostOperBase*(void* addr, std::size_t size, Impl&, void* cookie); + void do_post(PostOperConstr, std::size_t size, void* cookie); + template + static PostOperBase* post_oper_constr(void* addr, std::size_t size, Impl&, void* cookie); + static void recycle_post_oper(Impl&, PostOperBase*) noexcept; + static void trigger_exec(Impl&, TriggerExecOperBase&) noexcept; + static void reset_trigger_exec(Impl&, TriggerExecOperBase&) noexcept; + + using clock = std::chrono::steady_clock; + + friend class Resolver; + friend class SocketBase; + friend class Socket; + friend class Acceptor; + friend class DeadlineTimer; + friend class Trigger; + friend class ReadAheadBuffer; + friend class ssl::Stream; +}; + + +template +class Service::OperQueue { +public: + using LendersOperPtr = std::unique_ptr; + bool empty() const noexcept; + void push_back(LendersOperPtr) noexcept; + template + void push_back(OperQueue&) noexcept; + LendersOperPtr pop_front() noexcept; + void clear() noexcept; + OperQueue() noexcept = default; + OperQueue(OperQueue&&) noexcept; + ~OperQueue() noexcept; + +private: + Oper* m_back = nullptr; + template + friend class OperQueue; +}; + + +class Service::Descriptor { +public: +#ifdef _WIN32 + using native_handle_type = SOCKET; +#else + using native_handle_type = int; +#endif + + Impl& service_impl; + + Descriptor(Impl& service) noexcept; + ~Descriptor() noexcept; + + /// \param in_blocking_mode Must be true if, and only if the passed file + /// descriptor refers to a file description in which the file status flag + /// O_NONBLOCK is not set. + /// + /// The passed file descriptor must have the file descriptor flag FD_CLOEXEC + /// set. + void assign(native_handle_type fd, bool in_blocking_mode) noexcept; + void close() noexcept; + native_handle_type release() noexcept; + + bool is_open() const noexcept; + + native_handle_type native_handle() const noexcept; + bool in_blocking_mode() const noexcept; + + void accept(Descriptor&, StreamProtocol, Endpoint*, std::error_code&) noexcept; + std::size_t read_some(char* buffer, std::size_t size, std::error_code&) noexcept; + std::size_t write_some(const char* data, std::size_t size, std::error_code&) noexcept; + + /// \tparam Oper An operation type inherited from IoOper with an initate() + /// function that initiates the operation and figures out whether it needs + /// to read from, or write to the underlying descriptor to + /// proceed. `initiate()` must return Want::read if the operation needs to + /// read, or Want::write if the operation needs to write. If the operation + /// completes immediately (e.g. due to a failure during initialization), + /// `initiate()` must return Want::nothing. + template + void initiate_oper(std::unique_ptr, Args&&...); + + void ensure_blocking_mode(); + void ensure_nonblocking_mode(); + +private: + native_handle_type m_fd = -1; + bool m_in_blocking_mode; // Not in nonblocking mode + +#if REALM_HAVE_EPOLL || REALM_HAVE_KQUEUE + bool m_read_ready; + bool m_write_ready; + bool m_imminent_end_of_input; // Kernel has seen the end of input + bool m_is_registered; + OperQueue m_suspended_read_ops, m_suspended_write_ops; + + void deregister_for_async() noexcept; +#endif + + bool assume_read_would_block() const noexcept; + bool assume_write_would_block() const noexcept; + + void set_read_ready(bool) noexcept; + void set_write_ready(bool) noexcept; + + void set_nonblock_flag(bool value); + void add_initiated_oper(LendersIoOperPtr, Want); + + void do_close() noexcept; + native_handle_type do_release() noexcept; + + friend class IoReactor; +}; + + +class Resolver { +public: + class Query; + + Resolver(Service&); + ~Resolver() noexcept; + + /// Thread-safe. + Service& get_service() noexcept; + + /// @{ \brief Resolve the specified query to one or more endpoints. + Endpoint::List resolve(const Query&); + Endpoint::List resolve(const Query&, std::error_code&); + /// @} + + /// \brief Perform an asynchronous resolve operation. + /// + /// Initiate an asynchronous resolve operation. The completion handler will + /// be called when the operation completes. The operation completes when it + /// succeeds, or an error occurs. + /// + /// The completion handler is always executed by the event loop thread, + /// i.e., by a thread that is executing Service::run(). Conversely, the + /// completion handler is guaranteed to not be called while no thread is + /// executing Service::run(). The execution of the completion handler is + /// always deferred to the event loop, meaning that it never happens as a + /// synchronous side effect of the execution of async_resolve(), even when + /// async_resolve() is executed by the event loop thread. The completion + /// handler is guaranteed to be called eventually, as long as there is time + /// enough for the operation to complete or fail, and a thread is executing + /// Service::run() for long enough. + /// + /// The operation can be canceled by calling cancel(), and will be + /// automatically canceled if the resolver object is destroyed. If the + /// operation is canceled, it will fail with `error::operation_aborted`. The + /// operation remains cancelable up until the point in time where the + /// completion handler starts to execute. This means that if cancel() is + /// called before the completion handler starts to execute, then the + /// completion handler is guaranteed to have `error::operation_aborted` + /// passed to it. This is true regardless of whether cancel() is called + /// explicitly or implicitly, such as when the resolver is destroyed. + /// + /// The specified handler will be executed by an expression on the form + /// `handler(ec, endpoints)` where `ec` is the error code and `endpoints` is + /// an object of type `Endpoint::List`. If the the handler object is + /// movable, it will never be copied. Otherwise, it will be copied as + /// necessary. + /// + /// It is an error to start a new resolve operation (synchronous or + /// asynchronous) while an asynchronous resolve operation is in progress via + /// the same resolver object. An asynchronous resolve operation is + /// considered complete as soon as the completion handler starts to + /// execute. This means that a new resolve operation can be started from the + /// completion handler. + template + void async_resolve(Query, H handler); + + /// \brief Cancel all asynchronous operations. + /// + /// Cause all incomplete asynchronous operations, that are associated with + /// this resolver (at most one), to fail with `error::operation_aborted`. An + /// asynchronous operation is complete precisely when its completion handler + /// starts executing. + /// + /// Completion handlers of canceled operations will become immediately ready + /// to execute, but will never be executed directly as part of the execution + /// of cancel(). + /// + /// Cancellation happens automatically when the resolver object is destroyed. + void cancel() noexcept; + +private: + template + class ResolveOper; + + Service::Impl& m_service_impl; + + Service::OwnersOperPtr m_resolve_oper; + + void initiate_oper(Service::LendersResolveOperPtr); +}; + + +class Resolver::Query { +public: + enum { + /// Locally bound socket endpoint (server side) + passive = AI_PASSIVE, + + /// Ignore families without a configured non-loopback address + address_configured = AI_ADDRCONFIG + }; + + Query(std::string service_port, int init_flags = passive | address_configured); + Query(const StreamProtocol&, std::string service_port, int init_flags = passive | address_configured); + Query(std::string host_name, std::string service_port, int init_flags = address_configured); + Query(const StreamProtocol&, std::string host_name, std::string service_port, + int init_flags = address_configured); + + ~Query() noexcept; + + int flags() const; + StreamProtocol protocol() const; + std::string host() const; + std::string service() const; + +private: + int m_flags; + StreamProtocol m_protocol; + std::string m_host; // hostname + std::string m_service; // port + + friend class Service; +}; + + +class SocketBase { +public: + using native_handle_type = Service::Descriptor::native_handle_type; + + ~SocketBase() noexcept; + + /// Thread-safe. + Service& get_service() noexcept; + + bool is_open() const noexcept; + native_handle_type native_handle() const noexcept; + + /// @{ \brief Open the socket for use with the specified protocol. + /// + /// It is an error to call open() on a socket that is already open. + void open(const StreamProtocol&); + std::error_code open(const StreamProtocol&, std::error_code&); + /// @} + + /// \brief Close this socket. + /// + /// If the socket is open, it will be closed. If it is already closed (or + /// never opened), this function does nothing (idempotency). + /// + /// A socket is automatically closed when destroyed. + /// + /// When the socket is closed, any incomplete asynchronous operation will be + /// canceled (as if cancel() was called). + void close() noexcept; + + /// \brief Cancel all asynchronous operations. + /// + /// Cause all incomplete asynchronous operations, that are associated with + /// this socket, to fail with `error::operation_aborted`. An asynchronous + /// operation is complete precisely when its completion handler starts + /// executing. + /// + /// Completion handlers of canceled operations will become immediately ready + /// to execute, but will never be executed directly as part of the execution + /// of cancel(). + void cancel() noexcept; + + template + void get_option(O& opt) const; + + template + std::error_code get_option(O& opt, std::error_code&) const; + + template + void set_option(const O& opt); + + template + std::error_code set_option(const O& opt, std::error_code&); + + void bind(const Endpoint&); + std::error_code bind(const Endpoint&, std::error_code&); + + Endpoint local_endpoint() const; + Endpoint local_endpoint(std::error_code&) const; + + /// Release the ownership of this socket object over the native handle and + /// return the native handle to the caller. The caller assumes ownership + /// over the returned handle. The socket is left in a closed + /// state. Incomplete asynchronous operations will be canceled as if close() + /// had been called. + /// + /// If called on a closed socket, this function is a no-op, and returns the + /// same value as would be returned by native_handle() + native_handle_type release_native_handle() noexcept; + +private: + enum opt_enum { + opt_ReuseAddr, ///< `SOL_SOCKET`, `SO_REUSEADDR` + opt_Linger, ///< `SOL_SOCKET`, `SO_LINGER` + opt_NoDelay, ///< `IPPROTO_TCP`, `TCP_NODELAY` (disable the Nagle algorithm) + }; + + template + class Option; + +public: + using reuse_address = Option; + using no_delay = Option; + + // linger struct defined by POSIX sys/socket.h. + struct linger_opt; + using linger = Option; + +protected: + Service::Descriptor m_desc; + +private: + StreamProtocol m_protocol; + +protected: + Service::OwnersOperPtr m_read_oper; // Read or accept + Service::OwnersOperPtr m_write_oper; // Write or connect + + SocketBase(Service&); + + const StreamProtocol& get_protocol() const noexcept; + std::error_code do_assign(const StreamProtocol&, native_handle_type, std::error_code&); + void do_close() noexcept; + + void get_option(opt_enum, void* value_data, std::size_t& value_size, std::error_code&) const; + void set_option(opt_enum, const void* value_data, std::size_t value_size, std::error_code&); + void map_option(opt_enum, int& level, int& option_name) const; + + friend class Acceptor; +}; + + +template +class SocketBase::Option { +public: + Option(T value = T()); + T value() const; + +private: + T m_value; + + void get(const SocketBase&, std::error_code&); + void set(SocketBase&, std::error_code&) const; + + friend class SocketBase; +}; + +struct SocketBase::linger_opt { + linger_opt(bool enable, int timeout_seconds = 0) + { + m_linger.l_onoff = enable ? 1 : 0; + m_linger.l_linger = timeout_seconds; + } + + ::linger m_linger; + + operator ::linger() const + { + return m_linger; + } + + bool enabled() const + { + return m_linger.l_onoff != 0; + } + int timeout() const + { + return m_linger.l_linger; + } +}; + + +/// Switching between synchronous and asynchronous operations is allowed, but +/// only in a nonoverlapping fashion. That is, a synchronous operation is not +/// allowed to run concurrently with an asynchronous one on the same +/// socket. Note that an asynchronous operation is considered to be running +/// until its completion handler starts executing. +class Socket : public SocketBase { +public: + Socket(Service&); + + /// \brief Create a socket with an already-connected native socket handle. + /// + /// This constructor is shorthand for creating the socket with the + /// one-argument constructor, and then calling the two-argument assign() + /// with the specified protocol and native handle. + Socket(Service&, const StreamProtocol&, native_handle_type); + + ~Socket() noexcept; + + void connect(const Endpoint&); + std::error_code connect(const Endpoint&, std::error_code&); + + /// @{ \brief Perform a synchronous read operation. + /// + /// read() will not return until the specified buffer is full, or an error + /// occurs. Reaching the end of input before the buffer is filled, is + /// considered an error, and will cause the operation to fail with + /// MiscExtErrors::end_of_input. + /// + /// read_until() will not return until the specified buffer contains the + /// specified delimiter, or an error occurs. If the buffer is filled before + /// the delimiter is found, the operation fails with + /// MiscExtErrors::delim_not_found. Otherwise, if the end of input is + /// reached before the delimiter is found, the operation fails with + /// MiscExtErrors::end_of_input. If the operation succeeds, the last byte + /// placed in the buffer is the delimiter. + /// + /// The versions that take a ReadAheadBuffer argument will read through that + /// buffer. This allows for fewer larger reads on the underlying + /// socket. Since unconsumed data may be left in the read-ahead buffer after + /// a read operation returns, it is important that the same read-ahead + /// buffer is passed to the next read operation. + /// + /// The versions of read() and read_until() that do not take an + /// `std::error_code&` argument will throw std::system_error on failure. + /// + /// The versions that do take an `std::error_code&` argument will set \a ec + /// to `std::error_code()` on success, and to something else on failure. On + /// failure they will return the number of bytes placed in the specified + /// buffer before the error occured. + /// + /// \return The number of bytes places in the specified buffer upon return. + std::size_t read(char* buffer, std::size_t size); + std::size_t read(char* buffer, std::size_t size, std::error_code& ec); + std::size_t read(char* buffer, std::size_t size, ReadAheadBuffer&); + std::size_t read(char* buffer, std::size_t size, ReadAheadBuffer&, std::error_code& ec); + std::size_t read_until(char* buffer, std::size_t size, char delim, ReadAheadBuffer&); + std::size_t read_until(char* buffer, std::size_t size, char delim, ReadAheadBuffer&, std::error_code& ec); + /// @} + + /// @{ \brief Perform a synchronous write operation. + /// + /// write() will not return until all the specified bytes have been written + /// to the socket, or an error occurs. + /// + /// The versions of write() that does not take an `std::error_code&` + /// argument will throw std::system_error on failure. When it succeeds, it + /// always returns \a size. + /// + /// The versions that does take an `std::error_code&` argument will set \a + /// ec to `std::error_code()` on success, and to something else on + /// failure. On success it returns \a size. On faulure it returns the number + /// of bytes written before the failure occured. + std::size_t write(const char* data, std::size_t size); + std::size_t write(const char* data, std::size_t size, std::error_code& ec); + /// @} + + /// @{ \brief Read at least one byte from this socket. + /// + /// If \a size is zero, both versions of read_some() will return zero + /// without blocking. Read errors may or may not be detected in this case. + /// + /// Otherwise, if \a size is greater than zero, and at least one byte is + /// immediately available, that is, without blocking, then both versions + /// will read at least one byte (but generally as many immediately available + /// bytes as will fit into the specified buffer), and return without + /// blocking. + /// + /// Otherwise, both versions will block the calling thread until at least one + /// byte becomes available, or an error occurs. + /// + /// In this context, it counts as an error, if the end of input is reached + /// before at least one byte becomes available (see + /// MiscExtErrors::end_of_input). + /// + /// If no error occurs, both versions will return the number of bytes placed + /// in the specified buffer, which is generally as many as are immediately + /// available at the time when the first byte becomes available, although + /// never more than \a size. + /// + /// If no error occurs, the three-argument version will set \a ec to + /// indicate success. + /// + /// If an error occurs, the two-argument version will throw + /// `std::system_error`, while the three-argument version will set \a ec to + /// indicate the error, and return zero. + /// + /// As long as \a size is greater than zero, the two argument version will + /// always return a value that is greater than zero, while the three + /// argument version will return a value greater than zero when, and only + /// when \a ec is set to indicate success (no error, and no end of input). + std::size_t read_some(char* buffer, std::size_t size); + std::size_t read_some(char* buffer, std::size_t size, std::error_code& ec); + /// @} + + /// @{ \brief Write at least one byte to this socket. + /// + /// If \a size is zero, both versions of write_some() will return zero + /// without blocking. Write errors may or may not be detected in this case. + /// + /// Otherwise, if \a size is greater than zero, and at least one byte can be + /// written immediately, that is, without blocking, then both versions will + /// write at least one byte (but generally as many as can be written + /// immediately), and return without blocking. + /// + /// Otherwise, both versions will block the calling thread until at least one + /// byte can be written, or an error occurs. + /// + /// If no error occurs, both versions will return the number of bytes + /// written, which is generally as many as can be written immediately at the + /// time when the first byte can be written. + /// + /// If no error occurs, the three-argument version will set \a ec to + /// indicate success. + /// + /// If an error occurs, the two-argument version will throw + /// `std::system_error`, while the three-argument version will set \a ec to + /// indicate the error, and return zero. + /// + /// As long as \a size is greater than zero, the two argument version will + /// always return a value that is greater than zero, while the three + /// argument version will return a value greater than zero when, and only + /// when \a ec is set to indicate success. + std::size_t write_some(const char* data, std::size_t size); + std::size_t write_some(const char* data, std::size_t size, std::error_code&); + /// @} + + /// \brief Perform an asynchronous connect operation. + /// + /// Initiate an asynchronous connect operation. The completion handler is + /// called when the operation completes. The operation completes when the + /// connection is established, or an error occurs. + /// + /// The completion handler is always executed by the event loop thread, + /// i.e., by a thread that is executing Service::run(). Conversely, the + /// completion handler is guaranteed to not be called while no thread is + /// executing Service::run(). The execution of the completion handler is + /// always deferred to the event loop, meaning that it never happens as a + /// synchronous side effect of the execution of async_connect(), even when + /// async_connect() is executed by the event loop thread. The completion + /// handler is guaranteed to be called eventually, as long as there is time + /// enough for the operation to complete or fail, and a thread is executing + /// Service::run() for long enough. + /// + /// The operation can be canceled by calling cancel(), and will be + /// automatically canceled if the socket is closed. If the operation is + /// canceled, it will fail with `error::operation_aborted`. The operation + /// remains cancelable up until the point in time where the completion + /// handler starts to execute. This means that if cancel() is called before + /// the completion handler starts to execute, then the completion handler is + /// guaranteed to have `error::operation_aborted` passed to it. This is true + /// regardless of whether cancel() is called explicitly or implicitly, such + /// as when the socket is destroyed. + /// + /// If the socket is not already open, it will be opened as part of the + /// connect operation as if by calling `open(ep.protocol())`. If the opening + /// operation succeeds, but the connect operation fails, the socket will be + /// left in the opened state. + /// + /// The specified handler will be executed by an expression on the form + /// `handler(ec)` where `ec` is the error code. If the the handler object is + /// movable, it will never be copied. Otherwise, it will be copied as + /// necessary. + /// + /// It is an error to start a new connect operation (synchronous or + /// asynchronous) while an asynchronous connect operation is in progress. An + /// asynchronous connect operation is considered complete as soon as the + /// completion handler starts to execute. + /// + /// \param ep The remote endpoint of the connection to be established. + template + void async_connect(const Endpoint& ep, H handler); + + /// @{ \brief Perform an asynchronous read operation. + /// + /// Initiate an asynchronous buffered read operation on the associated + /// socket. The completion handler will be called when the operation + /// completes, or an error occurs. + /// + /// async_read() will continue reading until the specified buffer is full, + /// or an error occurs. If the end of input is reached before the buffer is + /// filled, the operation fails with MiscExtErrors::end_of_input. + /// + /// async_read_until() will continue reading until the specified buffer + /// contains the specified delimiter, or an error occurs. If the buffer is + /// filled before a delimiter is found, the operation fails with + /// MiscExtErrors::delim_not_found. Otherwise, if the end of input is + /// reached before a delimiter is found, the operation fails with + /// MiscExtErrors::end_of_input. Otherwise, if the operation succeeds, the + /// last byte placed in the buffer is the delimiter. + /// + /// The versions that take a ReadAheadBuffer argument will read through that + /// buffer. This allows for fewer larger reads on the underlying + /// socket. Since unconsumed data may be left in the read-ahead buffer after + /// a read operation completes, it is important that the same read-ahead + /// buffer is passed to the next read operation. + /// + /// The completion handler is always executed by the event loop thread, + /// i.e., by a thread that is executing Service::run(). Conversely, the + /// completion handler is guaranteed to not be called while no thread is + /// executing Service::run(). The execution of the completion handler is + /// always deferred to the event loop, meaning that it never happens as a + /// synchronous side effect of the execution of async_read() or + /// async_read_until(), even when async_read() or async_read_until() is + /// executed by the event loop thread. The completion handler is guaranteed + /// to be called eventually, as long as there is time enough for the + /// operation to complete or fail, and a thread is executing Service::run() + /// for long enough. + /// + /// The operation can be canceled by calling cancel() on the associated + /// socket, and will be automatically canceled if the associated socket is + /// closed. If the operation is canceled, it will fail with + /// `error::operation_aborted`. The operation remains cancelable up until + /// the point in time where the completion handler starts to execute. This + /// means that if cancel() is called before the completion handler starts to + /// execute, then the completion handler is guaranteed to have + /// `error::operation_aborted` passed to it. This is true regardless of + /// whether cancel() is called explicitly or implicitly, such as when the + /// socket is destroyed. + /// + /// The specified handler will be executed by an expression on the form + /// `handler(ec, n)` where `ec` is the error code, and `n` is the number of + /// bytes placed in the buffer (of type `std::size_t`). `n` is guaranteed to + /// be less than, or equal to \a size. If the the handler object is movable, + /// it will never be copied. Otherwise, it will be copied as necessary. + /// + /// It is an error to start a read operation before the associated socket is + /// connected. + /// + /// It is an error to start a new read operation (synchronous or + /// asynchronous) while an asynchronous read operation is in progress. An + /// asynchronous read operation is considered complete as soon as the + /// completion handler starts executing. This means that a new read + /// operation can be started from the completion handler of another + /// asynchronous buffered read operation. + template + void async_read(char* buffer, std::size_t size, H handler); + template + void async_read(char* buffer, std::size_t size, ReadAheadBuffer&, H handler); + template + void async_read_until(char* buffer, std::size_t size, char delim, ReadAheadBuffer&, H handler); + /// @} + + /// \brief Perform an asynchronous write operation. + /// + /// Initiate an asynchronous write operation. The completion handler is + /// called when the operation completes. The operation completes when all + /// the specified bytes have been written to the socket, or an error occurs. + /// + /// The completion handler is always executed by the event loop thread, + /// i.e., by a thread that is executing Service::run(). Conversely, the + /// completion handler is guaranteed to not be called while no thread is + /// executing Service::run(). The execution of the completion handler is + /// always deferred to the event loop, meaning that it never happens as a + /// synchronous side effect of the execution of async_write(), even when + /// async_write() is executed by the event loop thread. The completion + /// handler is guaranteed to be called eventually, as long as there is time + /// enough for the operation to complete or fail, and a thread is executing + /// Service::run() for long enough. + /// + /// The operation can be canceled by calling cancel(), and will be + /// automatically canceled if the socket is closed. If the operation is + /// canceled, it will fail with `error::operation_aborted`. The operation + /// remains cancelable up until the point in time where the completion + /// handler starts to execute. This means that if cancel() is called before + /// the completion handler starts to execute, then the completion handler is + /// guaranteed to have `error::operation_aborted` passed to it. This is true + /// regardless of whether cancel() is called explicitly or implicitly, such + /// as when the socket is destroyed. + /// + /// The specified handler will be executed by an expression on the form + /// `handler(ec, n)` where `ec` is the error code, and `n` is the number of + /// bytes written (of type `std::size_t`). If the the handler object is + /// movable, it will never be copied. Otherwise, it will be copied as + /// necessary. + /// + /// It is an error to start an asynchronous write operation before the + /// socket is connected. + /// + /// It is an error to start a new write operation (synchronous or + /// asynchronous) while an asynchronous write operation is in progress. An + /// asynchronous write operation is considered complete as soon as the + /// completion handler starts to execute. This means that a new write + /// operation can be started from the completion handler of another + /// asynchronous write operation. + template + void async_write(const char* data, std::size_t size, H handler); + + template + void async_read_some(char* buffer, std::size_t size, H handler); + template + void async_write_some(const char* data, std::size_t size, H handler); + + enum shutdown_type { +#ifdef _WIN32 + /// Shutdown the receiving side of the socket. + shutdown_receive = SD_RECEIVE, + + /// Shutdown the sending side of the socket. + shutdown_send = SD_SEND, + + /// Shutdown both sending and receiving side of the socket. + shutdown_both = SD_BOTH +#else + shutdown_receive = SHUT_RD, + shutdown_send = SHUT_WR, + shutdown_both = SHUT_RDWR +#endif + }; + + /// @{ \brief Shut down the connected sockets sending and/or receiving + /// side. + /// + /// It is an error to call this function when the socket is not both open + /// and connected. + void shutdown(shutdown_type); + std::error_code shutdown(shutdown_type, std::error_code&); + /// @} + + /// @{ \brief Initialize socket with an already-connected native socket + /// handle. + /// + /// The specified native handle must refer to a socket that is already fully + /// open and connected. + /// + /// If the assignment operation succeeds, this socket object has taken + /// ownership of the specified native handle, and the handle will be closed + /// when the socket object is destroyed, (or when close() is called). If the + /// operation fails, the caller still owns the specified native handle. + /// + /// It is an error to call connect() or async_connect() on a socket object + /// that is initialized this way (unless it is first closed). + /// + /// It is an error to call this function on a socket object that is already + /// open. + void assign(const StreamProtocol&, native_handle_type); + std::error_code assign(const StreamProtocol&, native_handle_type, std::error_code&); + /// @} + + /// Returns a reference to this socket, as this socket is the lowest layer + /// of a stream. + Socket& lowest_layer() noexcept; + +private: + using Want = Service::Want; + using StreamOps = Service::BasicStreamOps; + + class ConnectOperBase; + template + class ConnectOper; + + using LendersConnectOperPtr = std::unique_ptr; + + // `ec` untouched on success, but no immediate completion + bool initiate_async_connect(const Endpoint&, std::error_code& ec); + // `ec` untouched on success + std::error_code finalize_async_connect(std::error_code& ec) noexcept; + + // See Service::BasicStreamOps for details on these these 6 functions. + void do_init_read_async(std::error_code&, Want&) noexcept; + void do_init_write_async(std::error_code&, Want&) noexcept; + std::size_t do_read_some_sync(char* buffer, std::size_t size, std::error_code&) noexcept; + std::size_t do_write_some_sync(const char* data, std::size_t size, std::error_code&) noexcept; + std::size_t do_read_some_async(char* buffer, std::size_t size, std::error_code&, Want&) noexcept; + std::size_t do_write_some_async(const char* data, std::size_t size, std::error_code&, Want&) noexcept; + + friend class Service::BasicStreamOps; + friend class Service::BasicStreamOps; + friend class ReadAheadBuffer; + friend class ssl::Stream; +}; + + +/// Switching between synchronous and asynchronous operations is allowed, but +/// only in a nonoverlapping fashion. That is, a synchronous operation is not +/// allowed to run concurrently with an asynchronous one on the same +/// acceptor. Note that an asynchronous operation is considered to be running +/// until its completion handler starts executing. +class Acceptor : public SocketBase { +public: + Acceptor(Service&); + ~Acceptor() noexcept; + + static constexpr int max_connections = SOMAXCONN; + + void listen(int backlog = max_connections); + std::error_code listen(int backlog, std::error_code&); + + void accept(Socket&); + void accept(Socket&, Endpoint&); + std::error_code accept(Socket&, std::error_code&); + std::error_code accept(Socket&, Endpoint&, std::error_code&); + + /// @{ \brief Perform an asynchronous accept operation. + /// + /// Initiate an asynchronous accept operation. The completion handler will + /// be called when the operation completes. The operation completes when the + /// connection is accepted, or an error occurs. If the operation succeeds, + /// the specified local socket will have become connected to a remote + /// socket. + /// + /// The completion handler is always executed by the event loop thread, + /// i.e., by a thread that is executing Service::run(). Conversely, the + /// completion handler is guaranteed to not be called while no thread is + /// executing Service::run(). The execution of the completion handler is + /// always deferred to the event loop, meaning that it never happens as a + /// synchronous side effect of the execution of async_accept(), even when + /// async_accept() is executed by the event loop thread. The completion + /// handler is guaranteed to be called eventually, as long as there is time + /// enough for the operation to complete or fail, and a thread is executing + /// Service::run() for long enough. + /// + /// The operation can be canceled by calling cancel(), and will be + /// automatically canceled if the acceptor is closed. If the operation is + /// canceled, it will fail with `error::operation_aborted`. The operation + /// remains cancelable up until the point in time where the completion + /// handler starts to execute. This means that if cancel() is called before + /// the completion handler starts to execute, then the completion handler is + /// guaranteed to have `error::operation_aborted` passed to it. This is true + /// regardless of whether cancel() is called explicitly or implicitly, such + /// as when the acceptor is destroyed. + /// + /// The specified handler will be executed by an expression on the form + /// `handler(ec)` where `ec` is the error code. If the the handler object is + /// movable, it will never be copied. Otherwise, it will be copied as + /// necessary. + /// + /// It is an error to start a new accept operation (synchronous or + /// asynchronous) while an asynchronous accept operation is in progress. An + /// asynchronous accept operation is considered complete as soon as the + /// completion handler starts executing. This means that a new accept + /// operation can be started from the completion handler. + /// + /// \param sock This is the local socket, that upon successful completion + /// will have become connected to the remote socket. It must be in the + /// closed state (Socket::is_open()) when async_accept() is called. + /// + /// \param ep Upon completion, the remote peer endpoint will have been + /// assigned to this variable. + template + void async_accept(Socket& sock, H handler); + template + void async_accept(Socket& sock, Endpoint& ep, H handler); + /// @} + +private: + using Want = Service::Want; + + class AcceptOperBase; + template + class AcceptOper; + + using LendersAcceptOperPtr = std::unique_ptr; + + std::error_code accept(Socket&, Endpoint*, std::error_code&); + Want do_accept_async(Socket&, Endpoint*, std::error_code&) noexcept; + + template + void async_accept(Socket&, Endpoint*, H); +}; + + +/// \brief A timer object supporting asynchronous wait operations. +class DeadlineTimer { +public: + DeadlineTimer(Service&); + ~DeadlineTimer() noexcept; + + /// Thread-safe. + Service& get_service() noexcept; + + /// \brief Perform an asynchronous wait operation. + /// + /// Initiate an asynchronous wait operation. The completion handler becomes + /// ready to execute when the expiration time is reached, or an error occurs + /// (cancellation counts as an error here). The expiration time is the time + /// of initiation plus the specified delay. The error code passed to the + /// complition handler will **never** indicate success, unless the + /// expiration time was reached. + /// + /// The completion handler is always executed by the event loop thread, + /// i.e., by a thread that is executing Service::run(). Conversely, the + /// completion handler is guaranteed to not be called while no thread is + /// executing Service::run(). The execution of the completion handler is + /// always deferred to the event loop, meaning that it never happens as a + /// synchronous side effect of the execution of async_wait(), even when + /// async_wait() is executed by the event loop thread. The completion + /// handler is guaranteed to be called eventually, as long as there is time + /// enough for the operation to complete or fail, and a thread is executing + /// Service::run() for long enough. + /// + /// The operation can be canceled by calling cancel(), and will be + /// automatically canceled if the timer is destroyed. If the operation is + /// canceled, it will fail with `error::operation_aborted`. The operation + /// remains cancelable up until the point in time where the completion + /// handler starts to execute. This means that if cancel() is called before + /// the completion handler starts to execute, then the completion handler is + /// guaranteed to have `error::operation_aborted` passed to it. This is true + /// regardless of whether cancel() is called explicitly or implicitly, such + /// as when the timer is destroyed. + /// + /// The specified handler will be executed by an expression on the form + /// `handler(ec)` where `ec` is the error code. If the the handler object is + /// movable, it will never be copied. Otherwise, it will be copied as + /// necessary. + /// + /// It is an error to start a new asynchronous wait operation while an + /// another one is in progress. An asynchronous wait operation is in + /// progress until its completion handler starts executing. + template + void async_wait(std::chrono::duration delay, H handler); + + /// \brief Cancel an asynchronous wait operation. + /// + /// If an asynchronous wait operation, that is associated with this deadline + /// timer, is in progress, cause it to fail with + /// `error::operation_aborted`. An asynchronous wait operation is in + /// progress until its completion handler starts executing. + /// + /// Completion handlers of canceled operations will become immediately ready + /// to execute, but will never be executed directly as part of the execution + /// of cancel(). + /// + /// Cancellation happens automatically when the timer object is destroyed. + void cancel() noexcept; + +private: + template + class WaitOper; + + using clock = Service::clock; + + Service::Impl& m_service_impl; + Service::OwnersOperPtr m_wait_oper; + + void initiate_oper(Service::LendersWaitOperPtr); +}; + + +/// \brief Register a function whose invocation can be triggered repeatedly. +/// +/// While the function is always executed by the event loop thread, the +/// triggering of its execution can be done by any thread, and the triggering +/// operation is guaranteed to never throw. +/// +/// The function is guaranteed to not be called after the Trigger object is +/// destroyed. +/// +/// It is safe to destroy the Trigger object during execution of the function. +/// +/// Note that even though the trigger() function is thread-safe, the Trigger +/// object, as a whole, is not. In particular, construction and destruction must +/// not be considered thread-safe. +/// +/// ### Relation to post() +/// +/// For a particular execution of trigger() and a particular invocation of +/// Service::post(), if the execution of trigger() ends before the execution of +/// Service::post() begins, then it is guaranteed that the function associated +/// with the trigger gets to execute at least once after the execution of +/// trigger() begins, and before the post handler gets to execute. +class Trigger { +public: + template + Trigger(Service&, F func); + ~Trigger() noexcept; + + Trigger() noexcept = default; + Trigger(Trigger&&) noexcept = default; + Trigger& operator=(Trigger&&) noexcept = default; + + /// \brief Trigger another invocation of the associated function. + /// + /// An invocation of trigger() puts the Trigger object into the triggered + /// state. It remains in the triggered state until shortly before the + /// function starts to execute. While the Trigger object is in the triggered + /// state, trigger() has no effect. This means that the number of executions + /// of the function will generally be less that the number of times + /// trigger() is invoked(). + /// + /// A particular invocation of trigger() ensures that there will be at least + /// one invocation of the associated function whose execution begins after + /// the beginning of the execution of trigger(), so long as the event loop + /// thread does not exit prematurely from run(). + /// + /// If trigger() is invoked from the event loop thread, the next execution + /// of the associated function will not begin until after trigger returns(), + /// effectively preventing reentrancy for the associated function. + /// + /// If trigger() is invoked from another thread, the associated function may + /// start to execute before trigger() returns. + /// + /// Note that the associated function can retrigger itself, i.e., if the + /// associated function calls trigger(), then that will lead to another + /// invocation of the associated function, but not until the first + /// invocation ends (no reentrance). + /// + /// This function is thread-safe. + void trigger() noexcept; + +private: + template + class ExecOper; + + util::bind_ptr m_exec_oper; +}; + + +class ReadAheadBuffer { +public: + ReadAheadBuffer(); + + /// Discard any buffered data. + void clear() noexcept; + +private: + using Want = Service::Want; + + char* m_begin = nullptr; + char* m_end = nullptr; + static constexpr std::size_t s_size = 1024; + const std::unique_ptr m_buffer; + + bool empty() const noexcept; + bool read(char*& begin, char* end, int delim, std::error_code&) noexcept; + template + void refill_sync(S& stream, std::error_code&) noexcept; + template + bool refill_async(S& stream, std::error_code&, Want&) noexcept; + + template + friend class Service::BasicStreamOps; +}; + + +enum class ResolveErrors { + /// Host not found (authoritative). + host_not_found = 1, + + /// Host not found (non-authoritative). + host_not_found_try_again, + + /// The query is valid but does not have associated address data. + no_data, + + /// A non-recoverable error occurred. + no_recovery, + + /// The service is not supported for the given socket type. + service_not_found, + + /// The socket type is not supported. + socket_type_not_supported +}; + +class ResolveErrorCategory : public std::error_category { +public: + const char* name() const noexcept override final; + std::string message(int) const override final; +}; + +/// The error category associated with ResolveErrors. The name of this category is +/// `realm.util.network.resolve`. +extern ResolveErrorCategory resolve_error_category; + +inline std::error_code make_error_code(ResolveErrors err) +{ + return std::error_code(int(err), resolve_error_category); +} + +} // namespace network +} // namespace util +} // namespace realm + +namespace std { + +template <> +class is_error_code_enum { +public: + static const bool value = true; +}; + +} // namespace std + +namespace realm { +namespace util { +namespace network { + + +// Implementation + +// ---------------- StreamProtocol ---------------- + +inline StreamProtocol StreamProtocol::ip_v4() +{ + StreamProtocol prot; + prot.m_family = AF_INET; + return prot; +} + +inline StreamProtocol StreamProtocol::ip_v6() +{ + StreamProtocol prot; + prot.m_family = AF_INET6; + return prot; +} + +inline bool StreamProtocol::is_ip_v4() const +{ + return m_family == AF_INET; +} + +inline bool StreamProtocol::is_ip_v6() const +{ + return m_family == AF_INET6; +} + +inline int StreamProtocol::family() const +{ + return m_family; +} + +inline int StreamProtocol::protocol() const +{ + return m_protocol; +} + +inline StreamProtocol::StreamProtocol() + : m_family{AF_UNSPEC} + , // Allow both IPv4 and IPv6 + m_socktype{SOCK_STREAM} + , // Or SOCK_DGRAM for UDP + m_protocol{0} // Any protocol +{ +} + +// ---------------- Address ---------------- + +inline bool Address::is_ip_v4() const +{ + return !m_is_ip_v6; +} + +inline bool Address::is_ip_v6() const +{ + return m_is_ip_v6; +} + +template +inline std::basic_ostream& operator<<(std::basic_ostream& out, const Address& addr) +{ + // FIXME: Not taking `addr.m_ip_v6_scope_id` into account. What does ASIO + // do? + union buffer_union { + char ip_v4[INET_ADDRSTRLEN]; + char ip_v6[INET6_ADDRSTRLEN]; + }; + char buffer[sizeof(buffer_union)]; + int af = addr.m_is_ip_v6 ? AF_INET6 : AF_INET; +#ifdef _WIN32 + void* src = const_cast(reinterpret_cast(&addr.m_union)); +#else + const void* src = &addr.m_union; +#endif + const char* ret = ::inet_ntop(af, src, buffer, sizeof buffer); + if (ret == 0) { + std::error_code ec = make_basic_system_error_code(errno); + throw std::system_error(ec); + } + out << ret; + return out; +} + +inline Address::Address() +{ + m_union.m_ip_v4 = ip_v4_type(); +} + +inline Address make_address(const char* c_str) +{ + std::error_code ec; + Address addr = make_address(c_str, ec); + if (ec) + throw std::system_error(ec); + return addr; +} + +inline Address make_address(const std::string& str) +{ + std::error_code ec; + Address addr = make_address(str, ec); + if (ec) + throw std::system_error(ec); + return addr; +} + +inline Address make_address(const std::string& str, std::error_code& ec) noexcept +{ + return make_address(str.c_str(), ec); +} + +// ---------------- Endpoint ---------------- + +inline StreamProtocol Endpoint::protocol() const +{ + return m_protocol; +} + +inline Address Endpoint::address() const +{ + Address addr; + if (m_protocol.is_ip_v4()) { + addr.m_union.m_ip_v4 = m_sockaddr_union.m_ip_v4.sin_addr; + } + else { + addr.m_union.m_ip_v6 = m_sockaddr_union.m_ip_v6.sin6_addr; + addr.m_ip_v6_scope_id = m_sockaddr_union.m_ip_v6.sin6_scope_id; + addr.m_is_ip_v6 = true; + } + return addr; +} + +inline Endpoint::port_type Endpoint::port() const +{ + return ntohs(m_protocol.is_ip_v4() ? m_sockaddr_union.m_ip_v4.sin_port : m_sockaddr_union.m_ip_v6.sin6_port); +} + +inline Endpoint::data_type* Endpoint::data() +{ + return &m_sockaddr_union.m_base; +} + +inline const Endpoint::data_type* Endpoint::data() const +{ + return &m_sockaddr_union.m_base; +} + +inline Endpoint::Endpoint() + : Endpoint{StreamProtocol::ip_v4(), 0} +{ +} + +inline Endpoint::Endpoint(const StreamProtocol& protocol, port_type port) + : m_protocol{protocol} +{ + int family = m_protocol.family(); + if (family == AF_INET) { + m_sockaddr_union.m_ip_v4 = sockaddr_ip_v4_type(); // Clear + m_sockaddr_union.m_ip_v4.sin_family = AF_INET; + m_sockaddr_union.m_ip_v4.sin_port = htons(port); + m_sockaddr_union.m_ip_v4.sin_addr.s_addr = INADDR_ANY; + } + else if (family == AF_INET6) { + m_sockaddr_union.m_ip_v6 = sockaddr_ip_v6_type(); // Clear + m_sockaddr_union.m_ip_v6.sin6_family = AF_INET6; + m_sockaddr_union.m_ip_v6.sin6_port = htons(port); + } + else { + m_sockaddr_union.m_ip_v4 = sockaddr_ip_v4_type(); // Clear + m_sockaddr_union.m_ip_v4.sin_family = AF_UNSPEC; + m_sockaddr_union.m_ip_v4.sin_port = htons(port); + m_sockaddr_union.m_ip_v4.sin_addr.s_addr = INADDR_ANY; + } +} + +inline Endpoint::Endpoint(const Address& addr, port_type port) +{ + if (addr.m_is_ip_v6) { + m_protocol = StreamProtocol::ip_v6(); + m_sockaddr_union.m_ip_v6.sin6_family = AF_INET6; + m_sockaddr_union.m_ip_v6.sin6_port = htons(port); + m_sockaddr_union.m_ip_v6.sin6_flowinfo = 0; + m_sockaddr_union.m_ip_v6.sin6_addr = addr.m_union.m_ip_v6; + m_sockaddr_union.m_ip_v6.sin6_scope_id = addr.m_ip_v6_scope_id; + } + else { + m_protocol = StreamProtocol::ip_v4(); + m_sockaddr_union.m_ip_v4.sin_family = AF_INET; + m_sockaddr_union.m_ip_v4.sin_port = htons(port); + m_sockaddr_union.m_ip_v4.sin_addr = addr.m_union.m_ip_v4; + } +} + +inline Endpoint::List::iterator Endpoint::List::begin() const noexcept +{ + return m_endpoints.data(); +} + +inline Endpoint::List::iterator Endpoint::List::end() const noexcept +{ + return m_endpoints.data() + m_endpoints.size(); +} + +inline std::size_t Endpoint::List::size() const noexcept +{ + return m_endpoints.size(); +} + +inline bool Endpoint::List::empty() const noexcept +{ + return m_endpoints.size() == 0; +} + +// ---------------- Service::OperQueue ---------------- + +template +inline bool Service::OperQueue::empty() const noexcept +{ + return !m_back; +} + +template +inline void Service::OperQueue::push_back(LendersOperPtr op) noexcept +{ + REALM_ASSERT(!op->m_next); + if (m_back) { + op->m_next = m_back->m_next; + m_back->m_next = op.get(); + } + else { + op->m_next = op.get(); + } + m_back = op.release(); +} + +template +template +inline void Service::OperQueue::push_back(OperQueue& q) noexcept +{ + if (!q.m_back) + return; + if (m_back) + std::swap(m_back->m_next, q.m_back->m_next); + m_back = q.m_back; + q.m_back = nullptr; +} + +template +inline auto Service::OperQueue::pop_front() noexcept -> LendersOperPtr +{ + Oper* op = nullptr; + if (m_back) { + op = static_cast(m_back->m_next); + if (op != m_back) { + m_back->m_next = op->m_next; + } + else { + m_back = nullptr; + } + op->m_next = nullptr; + } + return LendersOperPtr(op); +} + +template +inline void Service::OperQueue::clear() noexcept +{ + if (m_back) { + LendersOperPtr op(m_back); + while (op->m_next != m_back) + op.reset(static_cast(op->m_next)); + m_back = nullptr; + } +} + +template +inline Service::OperQueue::OperQueue(OperQueue&& q) noexcept + : m_back{q.m_back} +{ + q.m_back = nullptr; +} + +template +inline Service::OperQueue::~OperQueue() noexcept +{ + clear(); +} + +// ---------------- Service::Descriptor ---------------- + +inline Service::Descriptor::Descriptor(Impl& s) noexcept + : service_impl{s} +{ +} + +inline Service::Descriptor::~Descriptor() noexcept +{ + if (is_open()) + close(); +} + +inline void Service::Descriptor::assign(native_handle_type fd, bool in_blocking_mode) noexcept +{ + REALM_ASSERT(!is_open()); + m_fd = fd; + m_in_blocking_mode = in_blocking_mode; +#if REALM_HAVE_EPOLL || REALM_HAVE_KQUEUE + m_read_ready = false; + m_write_ready = false; + m_imminent_end_of_input = false; + m_is_registered = false; +#endif +} + +inline void Service::Descriptor::close() noexcept +{ + REALM_ASSERT(is_open()); +#if REALM_HAVE_EPOLL || REALM_HAVE_KQUEUE + if (m_is_registered) + deregister_for_async(); + m_is_registered = false; +#endif + do_close(); +} + +inline auto Service::Descriptor::release() noexcept -> native_handle_type +{ + REALM_ASSERT(is_open()); +#if REALM_HAVE_EPOLL || REALM_HAVE_KQUEUE + if (m_is_registered) + deregister_for_async(); + m_is_registered = false; +#endif + return do_release(); +} + +inline bool Service::Descriptor::is_open() const noexcept +{ + return (m_fd != -1); +} + +inline auto Service::Descriptor::native_handle() const noexcept -> native_handle_type +{ + return m_fd; +} + +inline bool Service::Descriptor::in_blocking_mode() const noexcept +{ + return m_in_blocking_mode; +} + +template +inline void Service::Descriptor::initiate_oper(std::unique_ptr op, Args&&... args) +{ + Service::Want want = op->initiate(std::forward(args)...); // Throws + add_initiated_oper(std::move(op), want); // Throws +} + +inline void Service::Descriptor::ensure_blocking_mode() +{ + // Assuming that descriptors are either used mostly in blocking mode, or + // mostly in nonblocking mode. + if (REALM_UNLIKELY(!m_in_blocking_mode)) { + bool value = false; + set_nonblock_flag(value); // Throws + m_in_blocking_mode = true; + } +} + +inline void Service::Descriptor::ensure_nonblocking_mode() +{ + // Assuming that descriptors are either used mostly in blocking mode, or + // mostly in nonblocking mode. + if (REALM_UNLIKELY(m_in_blocking_mode)) { + bool value = true; + set_nonblock_flag(value); // Throws + m_in_blocking_mode = false; + } +} + +inline bool Service::Descriptor::assume_read_would_block() const noexcept +{ +#if REALM_HAVE_EPOLL || REALM_HAVE_KQUEUE + return !m_in_blocking_mode && !m_read_ready; +#else + return false; +#endif +} + +inline bool Service::Descriptor::assume_write_would_block() const noexcept +{ +#if REALM_HAVE_EPOLL || REALM_HAVE_KQUEUE + return !m_in_blocking_mode && !m_write_ready; +#else + return false; +#endif +} + +inline void Service::Descriptor::set_read_ready(bool value) noexcept +{ +#if REALM_HAVE_EPOLL || REALM_HAVE_KQUEUE + m_read_ready = value; +#else + // No-op + static_cast(value); +#endif +} + +inline void Service::Descriptor::set_write_ready(bool value) noexcept +{ +#if REALM_HAVE_EPOLL || REALM_HAVE_KQUEUE + m_write_ready = value; +#else + // No-op + static_cast(value); +#endif +} + +// ---------------- Service ---------------- + +class Service::AsyncOper { +public: + bool in_use() const noexcept; + bool is_complete() const noexcept; + bool is_canceled() const noexcept; + void cancel() noexcept; + /// Every object of type \ref AsyncOper must be destroyed either by a call + /// to this function or to recycle(). This function recycles the operation + /// object (commits suicide), even if it throws. + virtual void recycle_and_execute() = 0; + /// Every object of type \ref AsyncOper must be destroyed either by a call + /// to recycle_and_execute() or to this function. This function destroys the + /// object (commits suicide). + virtual void recycle() noexcept = 0; + /// Must be called when the owner dies, and the object is in use (not an + /// instance of UnusedOper). + virtual void orphan() noexcept = 0; + +protected: + AsyncOper(std::size_t size, bool in_use) noexcept; + virtual ~AsyncOper() noexcept {} + void set_is_complete(bool value) noexcept; + template + void do_recycle_and_execute(bool orphaned, H& handler, Args&&...); + void do_recycle(bool orphaned) noexcept; + +private: + std::size_t m_size; // Allocated number of bytes + bool m_in_use = false; + // Set to true when the operation completes successfully or fails. If the + // operation is canceled before this happens, it will never be set to + // true. Always false when not in use + bool m_complete = false; + // Set to true when the operation is canceled. Always false when not in use. + bool m_canceled = false; + AsyncOper* m_next = nullptr; // Always null when not in use + template + void do_recycle_and_execute_helper(bool orphaned, bool& was_recycled, H handler, Args...); + friend class Service; +}; + +class Service::ResolveOperBase : public AsyncOper { +public: + ResolveOperBase(std::size_t size, Resolver& resolver, Resolver::Query query) noexcept + : AsyncOper{size, true} + , m_resolver{&resolver} + , m_query{std::move(query)} + { + } + void complete() noexcept + { + set_is_complete(true); + } + void recycle() noexcept override final + { + bool orphaned = !m_resolver; + REALM_ASSERT(orphaned); + // Note: do_recycle() commits suicide. + do_recycle(orphaned); + } + void orphan() noexcept override final + { + m_resolver = nullptr; + } + +protected: + Resolver* m_resolver; + Resolver::Query m_query; + Endpoint::List m_endpoints; + std::error_code m_error_code; + friend class Service; +}; + +class Service::WaitOperBase : public AsyncOper { +public: + WaitOperBase(std::size_t size, DeadlineTimer& timer, clock::time_point expiration_time) noexcept + : AsyncOper{size, true} + , // Second argument is `in_use` + m_timer{&timer} + , m_expiration_time{expiration_time} + { + } + void complete() noexcept + { + set_is_complete(true); + } + void recycle() noexcept override final + { + bool orphaned = !m_timer; + REALM_ASSERT(orphaned); + // Note: do_recycle() commits suicide. + do_recycle(orphaned); + } + void orphan() noexcept override final + { + m_timer = nullptr; + } + +protected: + DeadlineTimer* m_timer; + clock::time_point m_expiration_time; + friend class Service; +}; + +class Service::TriggerExecOperBase : public AsyncOper, public AtomicRefCountBase { +public: + TriggerExecOperBase(Impl& service) noexcept + : AsyncOper{0, false} + , // First arg is `size` (unused), second arg is `in_use` + m_service{&service} + { + } + void recycle() noexcept override final + { + REALM_ASSERT(in_use()); + REALM_ASSERT(!m_service); + // Note: Potential suicide when `self` goes out of scope + util::bind_ptr self{this, bind_ptr_base::adopt_tag{}}; + } + void orphan() noexcept override final + { + REALM_ASSERT(m_service); + m_service = nullptr; + } + void trigger() noexcept + { + REALM_ASSERT(m_service); + Service::trigger_exec(*m_service, *this); + } + +protected: + Impl* m_service; +}; + +class Service::PostOperBase : public AsyncOper { +public: + PostOperBase(std::size_t size, Impl& service) noexcept + : AsyncOper{size, true} + , // Second argument is `in_use` + m_service{service} + { + } + void recycle() noexcept override final + { + // Service::recycle_post_oper() destroys this operation object + Service::recycle_post_oper(m_service, this); + } + void orphan() noexcept override final + { + REALM_ASSERT(false); // Never called + } + +protected: + Impl& m_service; +}; + +template +class Service::PostOper : public PostOperBase { +public: + PostOper(std::size_t size, Impl& service, H handler) + : PostOperBase{size, service} + , m_handler{std::move(handler)} + { + } + void recycle_and_execute() override final + { + // Recycle the operation object before the handler is exceuted, such + // that the memory is available for a new post operation that might be + // initiated during the execution of the handler. + bool was_recycled = false; + try { + H handler = std::move(m_handler); // Throws + // Service::recycle_post_oper() destroys this operation object + Service::recycle_post_oper(m_service, this); + was_recycled = true; + handler(); // Throws + } + catch (...) { + if (!was_recycled) { + // Service::recycle_post_oper() destroys this operation object + Service::recycle_post_oper(m_service, this); + } + throw; + } + } + +private: + H m_handler; +}; + +class Service::IoOper : public AsyncOper { +public: + IoOper(std::size_t size) noexcept + : AsyncOper{size, true} // Second argument is `in_use` + { + } + virtual Descriptor& descriptor() noexcept = 0; + /// Advance this operation and figure out out whether it needs to read from, + /// or write to the underlying descriptor to advance further. This function + /// must return Want::read if the operation needs to read, or Want::write if + /// the operation needs to write to advance further. If the operation + /// completes (due to success or failure), this function must return + /// Want::nothing. + virtual Want advance() noexcept = 0; +}; + +class Service::UnusedOper : public AsyncOper { +public: + UnusedOper(std::size_t size) noexcept + : AsyncOper{size, false} // Second argument is `in_use` + { + } + void recycle_and_execute() override final + { + // Must never be called + REALM_ASSERT(false); + } + void recycle() noexcept override final + { + // Must never be called + REALM_ASSERT(false); + } + void orphan() noexcept override final + { + // Must never be called + REALM_ASSERT(false); + } +}; + +// `S` must be a stream class with the following member functions: +// +// Socket& lowest_layer() noexcept; +// +// void do_init_read_async(std::error_code& ec, Want& want) noexcept; +// void do_init_write_async(std::error_code& ec, Want& want) noexcept; +// +// std::size_t do_read_some_sync(char* buffer, std::size_t size, +// std::error_code& ec) noexcept; +// std::size_t do_write_some_sync(const char* data, std::size_t size, +// std::error_code& ec) noexcept; +// std::size_t do_read_some_async(char* buffer, std::size_t size, +// std::error_code& ec, Want& want) noexcept; +// std::size_t do_write_some_async(const char* data, std::size_t size, +// std::error_code& ec, Want& want) noexcept; +// +// If an error occurs during any of these 6 functions, the `ec` argument must be +// set accordingly. Otherwise the `ec` argument must be set to +// `std::error_code()`. +// +// The do_init_*_async() functions must update the `want` argument to indicate +// how the operation must be initiated: +// +// Want::read Wait for read readiness, then call do_*_some_async(). +// Want::write Wait for write readiness, then call do_*_some_async(). +// Want::nothing Call do_*_some_async() immediately without waiting for +// read or write readiness. +// +// If end-of-input occurs while reading, do_read_some_*() must fail, set `ec` to +// MiscExtErrors::end_of_input, and return zero. +// +// If an error occurs during reading or writing, do_*_some_sync() must set `ec` +// accordingly (to something other than `std::system_error()`) and return +// zero. Otherwise they must set `ec` to `std::system_error()` and return the +// number of bytes read or written, which **must** be at least 1. If the +// underlying socket is in nonblocking mode, and no bytes could be immediately +// read or written, these functions must fail with +// `error::resource_unavailable_try_again`. +// +// If an error occurs during reading or writing, do_*_some_async() must set `ec` +// accordingly (to something other than `std::system_error()`), `want` to +// `Want::nothing`, and return zero. Otherwise they must set `ec` to +// `std::system_error()` and return the number of bytes read or written, which +// must be zero if no bytes could be immediately read or written. Note, in this +// case it is not an error if the underlying socket is in nonblocking mode, and +// no bytes could be immediately read or written. When these functions succeed, +// but return zero because no bytes could be immediately read or written, they +// must set `want` to something other than `Want::nothing`. +// +// If no error occurs, do_*_some_async() must set `want` to indicate how the +// operation should proceed if additional data needs to be read or written, or +// if no bytes were transferred: +// +// Want::read Wait for read readiness, then call do_*_some_async() again. +// Want::write Wait for write readiness, then call do_*_some_async() again. +// Want::nothing Call do_*_some_async() again without waiting for read or +// write readiness. +// +// NOTE: If, for example, do_read_some_async() sets `want` to `Want::write`, it +// means that the stream needs to write data to the underlying TCP socket before +// it is able to deliver any additional data to the caller. While such a +// situation will never occur on a raw TCP socket, it can occur on an SSL stream +// (Secure Socket Layer). +// +// When do_*_some_async() returns `n`, at least one of the following conditions +// must be true: +// +// n > 0 Bytes were transferred. +// ec != std::error_code() An error occured. +// want != Want::nothing Wait for read/write readiness. +// +// This is of critical importance, as it is the only way we can avoid falling +// into a busy loop of repeated invocations of do_*_some_async(). +// +// NOTE: do_*_some_async() are allowed to set `want` to `Want::read` or +// `Want::write`, even when they succesfully transfer a nonzero number of bytes. +template +class Service::BasicStreamOps { +public: + class StreamOper; + class ReadOperBase; + class WriteOperBase; + class BufferedReadOperBase; + template + class ReadOper; + template + class WriteOper; + template + class BufferedReadOper; + + using LendersReadOperPtr = std::unique_ptr; + using LendersWriteOperPtr = std::unique_ptr; + using LendersBufferedReadOperPtr = std::unique_ptr; + + // Synchronous read + static std::size_t read(S& stream, char* buffer, std::size_t size, std::error_code& ec) + { + REALM_ASSERT(!stream.lowest_layer().m_read_oper || !stream.lowest_layer().m_read_oper->in_use()); + stream.lowest_layer().m_desc.ensure_blocking_mode(); // Throws + char* begin = buffer; + char* end = buffer + size; + char* curr = begin; + for (;;) { + if (curr == end) { + ec = std::error_code(); // Success + break; + } + char* buffer_2 = curr; + std::size_t size_2 = std::size_t(end - curr); + std::size_t n = stream.do_read_some_sync(buffer_2, size_2, ec); + if (REALM_UNLIKELY(ec)) + break; + REALM_ASSERT(n > 0); + REALM_ASSERT(n <= size_2); + curr += n; + } + std::size_t n = std::size_t(curr - begin); + return n; + } + + // Synchronous write + static std::size_t write(S& stream, const char* data, std::size_t size, std::error_code& ec) + { + REALM_ASSERT(!stream.lowest_layer().m_write_oper || !stream.lowest_layer().m_write_oper->in_use()); + stream.lowest_layer().m_desc.ensure_blocking_mode(); // Throws + const char* begin = data; + const char* end = data + size; + const char* curr = begin; + for (;;) { + if (curr == end) { + ec = std::error_code(); // Success + break; + } + const char* data_2 = curr; + std::size_t size_2 = std::size_t(end - curr); + std::size_t n = stream.do_write_some_sync(data_2, size_2, ec); + if (REALM_UNLIKELY(ec)) + break; + REALM_ASSERT(n > 0); + REALM_ASSERT(n <= size_2); + curr += n; + } + std::size_t n = std::size_t(curr - begin); + return n; + } + + // Synchronous read + static std::size_t buffered_read(S& stream, char* buffer, std::size_t size, int delim, ReadAheadBuffer& rab, + std::error_code& ec) + { + REALM_ASSERT(!stream.lowest_layer().m_read_oper || !stream.lowest_layer().m_read_oper->in_use()); + stream.lowest_layer().m_desc.ensure_blocking_mode(); // Throws + char* begin = buffer; + char* end = buffer + size; + char* curr = begin; + for (;;) { + bool complete = rab.read(curr, end, delim, ec); + if (complete) + break; + + rab.refill_sync(stream, ec); + if (REALM_UNLIKELY(ec)) + break; + } + std::size_t n = (curr - begin); + return n; + } + + // Synchronous read + static std::size_t read_some(S& stream, char* buffer, std::size_t size, std::error_code& ec) + { + REALM_ASSERT(!stream.lowest_layer().m_read_oper || !stream.lowest_layer().m_read_oper->in_use()); + stream.lowest_layer().m_desc.ensure_blocking_mode(); // Throws + return stream.do_read_some_sync(buffer, size, ec); + } + + // Synchronous write + static std::size_t write_some(S& stream, const char* data, std::size_t size, std::error_code& ec) + { + REALM_ASSERT(!stream.lowest_layer().m_write_oper || !stream.lowest_layer().m_write_oper->in_use()); + stream.lowest_layer().m_desc.ensure_blocking_mode(); // Throws + return stream.do_write_some_sync(data, size, ec); + } + + template + static void async_read(S& stream, char* buffer, std::size_t size, bool is_read_some, H handler) + { + char* begin = buffer; + char* end = buffer + size; + LendersReadOperPtr op = Service::alloc>(stream.lowest_layer().m_read_oper, stream, is_read_some, + begin, end, std::move(handler)); // Throws + stream.lowest_layer().m_desc.initiate_oper(std::move(op)); // Throws + } + + template + static void async_write(S& stream, const char* data, std::size_t size, bool is_write_some, H handler) + { + const char* begin = data; + const char* end = data + size; + LendersWriteOperPtr op = Service::alloc>( + stream.lowest_layer().m_write_oper, stream, is_write_some, begin, end, std::move(handler)); // Throws + stream.lowest_layer().m_desc.initiate_oper(std::move(op)); // Throws + } + + template + static void async_buffered_read(S& stream, char* buffer, std::size_t size, int delim, ReadAheadBuffer& rab, + H handler) + { + char* begin = buffer; + char* end = buffer + size; + LendersBufferedReadOperPtr op = + Service::alloc>(stream.lowest_layer().m_read_oper, stream, begin, end, delim, rab, + std::move(handler)); // Throws + stream.lowest_layer().m_desc.initiate_oper(std::move(op)); // Throws + } +}; + +template +class Service::BasicStreamOps::StreamOper : public IoOper { +public: + StreamOper(std::size_t size, S& stream) noexcept + : IoOper{size} + , m_stream{&stream} + { + } + void recycle() noexcept override final + { + bool orphaned = !m_stream; + REALM_ASSERT(orphaned); + // Note: do_recycle() commits suicide. + do_recycle(orphaned); + } + void orphan() noexcept override final + { + m_stream = nullptr; + } + Descriptor& descriptor() noexcept override final + { + return m_stream->lowest_layer().m_desc; + } + +protected: + S* m_stream; + std::error_code m_error_code; +}; + +template +class Service::BasicStreamOps::ReadOperBase : public StreamOper { +public: + ReadOperBase(std::size_t size, S& stream, bool is_read_some, char* begin, char* end) noexcept + : StreamOper{size, stream} + , m_is_read_some{is_read_some} + , m_begin{begin} + , m_end{end} + { + } + Want initiate() + { + auto& s = *this; + REALM_ASSERT(this == s.m_stream->lowest_layer().m_read_oper.get()); + REALM_ASSERT(!s.is_complete()); + REALM_ASSERT(s.m_curr <= s.m_end); + Want want = Want::nothing; + if (REALM_UNLIKELY(s.m_curr == s.m_end)) { + s.set_is_complete(true); // Success + } + else { + s.m_stream->lowest_layer().m_desc.ensure_nonblocking_mode(); // Throws + s.m_stream->do_init_read_async(s.m_error_code, want); + if (want == Want::nothing) { + if (REALM_UNLIKELY(s.m_error_code)) { + s.set_is_complete(true); // Failure + } + else { + want = advance(); + } + } + } + return want; + } + Want advance() noexcept override final + { + auto& s = *this; + REALM_ASSERT(!s.is_complete()); + REALM_ASSERT(!s.is_canceled()); + REALM_ASSERT(!s.m_error_code); + REALM_ASSERT(s.m_curr < s.m_end); + REALM_ASSERT(!s.m_is_read_some || s.m_curr == m_begin); + for (;;) { + // Read into callers buffer + char* buffer = s.m_curr; + std::size_t size = std::size_t(s.m_end - s.m_curr); + Want want = Want::nothing; + std::size_t n = s.m_stream->do_read_some_async(buffer, size, s.m_error_code, want); + REALM_ASSERT(n > 0 || s.m_error_code || want != Want::nothing); // No busy loop, please + bool got_nothing = (n == 0); + if (got_nothing) { + if (REALM_UNLIKELY(s.m_error_code)) { + s.set_is_complete(true); // Failure + return Want::nothing; + } + // Got nothing, but want something + return want; + } + REALM_ASSERT(!s.m_error_code); + // Check for completion + REALM_ASSERT(n <= size); + s.m_curr += n; + if (s.m_is_read_some || s.m_curr == s.m_end) { + s.set_is_complete(true); // Success + return Want::nothing; + } + if (want != Want::nothing) + return want; + REALM_ASSERT(n < size); + } + } + +protected: + const bool m_is_read_some; + char* const m_begin; // May be dangling after cancellation + char* const m_end; // May be dangling after cancellation + char* m_curr = m_begin; // May be dangling after cancellation +}; + +template +class Service::BasicStreamOps::WriteOperBase : public StreamOper { +public: + WriteOperBase(std::size_t size, S& stream, bool is_write_some, const char* begin, const char* end) noexcept + : StreamOper{size, stream} + , m_is_write_some{is_write_some} + , m_begin{begin} + , m_end{end} + { + } + Want initiate() + { + auto& s = *this; + REALM_ASSERT(this == s.m_stream->lowest_layer().m_write_oper.get()); + REALM_ASSERT(!s.is_complete()); + REALM_ASSERT(s.m_curr <= s.m_end); + Want want = Want::nothing; + if (REALM_UNLIKELY(s.m_curr == s.m_end)) { + s.set_is_complete(true); // Success + } + else { + s.m_stream->lowest_layer().m_desc.ensure_nonblocking_mode(); // Throws + s.m_stream->do_init_write_async(s.m_error_code, want); + if (want == Want::nothing) { + if (REALM_UNLIKELY(s.m_error_code)) { + s.set_is_complete(true); // Failure + } + else { + want = advance(); + } + } + } + return want; + } + Want advance() noexcept override final + { + auto& s = *this; + REALM_ASSERT(!s.is_complete()); + REALM_ASSERT(!s.is_canceled()); + REALM_ASSERT(!s.m_error_code); + REALM_ASSERT(s.m_curr < s.m_end); + REALM_ASSERT(!s.m_is_write_some || s.m_curr == s.m_begin); + for (;;) { + // Write from callers buffer + const char* data = s.m_curr; + std::size_t size = std::size_t(s.m_end - s.m_curr); + Want want = Want::nothing; + std::size_t n = s.m_stream->do_write_some_async(data, size, s.m_error_code, want); + REALM_ASSERT(n > 0 || s.m_error_code || want != Want::nothing); // No busy loop, please + bool wrote_nothing = (n == 0); + if (wrote_nothing) { + if (REALM_UNLIKELY(s.m_error_code)) { + s.set_is_complete(true); // Failure + return Want::nothing; + } + // Wrote nothing, but want something written + return want; + } + REALM_ASSERT(!s.m_error_code); + // Check for completion + REALM_ASSERT(n <= size); + s.m_curr += n; + if (s.m_is_write_some || s.m_curr == s.m_end) { + s.set_is_complete(true); // Success + return Want::nothing; + } + if (want != Want::nothing) + return want; + REALM_ASSERT(n < size); + } + } + +protected: + const bool m_is_write_some; + const char* const m_begin; // May be dangling after cancellation + const char* const m_end; // May be dangling after cancellation + const char* m_curr = m_begin; // May be dangling after cancellation +}; + +template +class Service::BasicStreamOps::BufferedReadOperBase : public StreamOper { +public: + BufferedReadOperBase(std::size_t size, S& stream, char* begin, char* end, int delim, + ReadAheadBuffer& rab) noexcept + : StreamOper{size, stream} + , m_read_ahead_buffer{rab} + , m_begin{begin} + , m_end{end} + , m_delim{delim} + { + } + Want initiate() + { + auto& s = *this; + REALM_ASSERT(this == s.m_stream->lowest_layer().m_read_oper.get()); + REALM_ASSERT(!s.is_complete()); + Want want = Want::nothing; + bool complete = s.m_read_ahead_buffer.read(s.m_curr, s.m_end, s.m_delim, s.m_error_code); + if (complete) { + s.set_is_complete(true); // Success or failure + } + else { + s.m_stream->lowest_layer().m_desc.ensure_nonblocking_mode(); // Throws + s.m_stream->do_init_read_async(s.m_error_code, want); + if (want == Want::nothing) { + if (REALM_UNLIKELY(s.m_error_code)) { + s.set_is_complete(true); // Failure + } + else { + want = advance(); + } + } + } + return want; + } + Want advance() noexcept override final + { + auto& s = *this; + REALM_ASSERT(!s.is_complete()); + REALM_ASSERT(!s.is_canceled()); + REALM_ASSERT(!s.m_error_code); + REALM_ASSERT(s.m_read_ahead_buffer.empty()); + REALM_ASSERT(s.m_curr < s.m_end); + for (;;) { + // Fill read-ahead buffer from stream (is empty now) + Want want = Want::nothing; + bool nonempty = s.m_read_ahead_buffer.refill_async(*s.m_stream, s.m_error_code, want); + REALM_ASSERT(nonempty || s.m_error_code || want != Want::nothing); // No busy loop, please + bool got_nothing = !nonempty; + if (got_nothing) { + if (REALM_UNLIKELY(s.m_error_code)) { + s.set_is_complete(true); // Failure + return Want::nothing; + } + // Got nothing, but want something + return want; + } + // Transfer buffered data to callers buffer + bool complete = s.m_read_ahead_buffer.read(s.m_curr, s.m_end, s.m_delim, s.m_error_code); + if (complete) { + s.set_is_complete(true); // Success or failure (delim_not_found) + return Want::nothing; + } + if (want != Want::nothing) + return want; + } + } + +protected: + ReadAheadBuffer& m_read_ahead_buffer; // May be dangling after cancellation + char* const m_begin; // May be dangling after cancellation + char* const m_end; // May be dangling after cancellation + char* m_curr = m_begin; // May be dangling after cancellation + const int m_delim; +}; + +template +template +class Service::BasicStreamOps::ReadOper : public ReadOperBase { +public: + ReadOper(std::size_t size, S& stream, bool is_read_some, char* begin, char* end, H handler) + : ReadOperBase{size, stream, is_read_some, begin, end} + , m_handler{std::move(handler)} + { + } + void recycle_and_execute() override final + { + auto& s = *this; + REALM_ASSERT(s.is_complete() || s.is_canceled()); + REALM_ASSERT(s.is_complete() == + (s.m_error_code || s.m_curr == s.m_end || (s.m_is_read_some && s.m_curr != s.m_begin))); + REALM_ASSERT(s.m_curr >= s.m_begin); + bool orphaned = !s.m_stream; + std::error_code ec = s.m_error_code; + if (s.is_canceled()) + ec = error::operation_aborted; + std::size_t num_bytes_transferred = std::size_t(s.m_curr - s.m_begin); + // Note: do_recycle_and_execute() commits suicide. + s.template do_recycle_and_execute(orphaned, s.m_handler, ec, + num_bytes_transferred); // Throws + } + +private: + H m_handler; +}; + +template +template +class Service::BasicStreamOps::WriteOper : public WriteOperBase { +public: + WriteOper(std::size_t size, S& stream, bool is_write_some, const char* begin, const char* end, H handler) + : WriteOperBase{size, stream, is_write_some, begin, end} + , m_handler{std::move(handler)} + { + } + void recycle_and_execute() override final + { + auto& s = *this; + REALM_ASSERT(s.is_complete() || s.is_canceled()); + REALM_ASSERT(s.is_complete() == + (s.m_error_code || s.m_curr == s.m_end || (s.m_is_write_some && s.m_curr != s.m_begin))); + REALM_ASSERT(s.m_curr >= s.m_begin); + bool orphaned = !s.m_stream; + std::error_code ec = s.m_error_code; + if (s.is_canceled()) + ec = error::operation_aborted; + std::size_t num_bytes_transferred = std::size_t(s.m_curr - s.m_begin); + // Note: do_recycle_and_execute() commits suicide. + s.template do_recycle_and_execute(orphaned, s.m_handler, ec, + num_bytes_transferred); // Throws + } + +private: + H m_handler; +}; + +template +template +class Service::BasicStreamOps::BufferedReadOper : public BufferedReadOperBase { +public: + BufferedReadOper(std::size_t size, S& stream, char* begin, char* end, int delim, ReadAheadBuffer& rab, H handler) + : BufferedReadOperBase{size, stream, begin, end, delim, rab} + , m_handler{std::move(handler)} + { + } + void recycle_and_execute() override final + { + auto& s = *this; + REALM_ASSERT(s.is_complete() || (s.is_canceled() && !s.m_error_code)); + REALM_ASSERT(s.is_canceled() || s.m_error_code || + (s.m_delim != std::char_traits::eof() + ? s.m_curr > s.m_begin && s.m_curr[-1] == std::char_traits::to_char_type(s.m_delim) + : s.m_curr == s.m_end)); + REALM_ASSERT(s.m_curr >= s.m_begin); + bool orphaned = !s.m_stream; + std::error_code ec = s.m_error_code; + if (s.is_canceled()) + ec = error::operation_aborted; + std::size_t num_bytes_transferred = std::size_t(s.m_curr - s.m_begin); + // Note: do_recycle_and_execute() commits suicide. + s.template do_recycle_and_execute(orphaned, s.m_handler, ec, + num_bytes_transferred); // Throws + } + +private: + H m_handler; +}; + +template +inline void Service::post(H handler) +{ + do_post(&Service::post_oper_constr, sizeof(PostOper), &handler); +} + +inline void Service::OwnersOperDeleter::operator()(AsyncOper* op) const noexcept +{ + if (op->in_use()) { + op->orphan(); + } + else { + void* addr = op; + op->~AsyncOper(); + delete[] static_cast(addr); + } +} + +inline void Service::LendersOperDeleter::operator()(AsyncOper* op) const noexcept +{ + op->recycle(); // Suicide +} + +template +std::unique_ptr Service::alloc(OwnersOperPtr& owners_ptr, Args&&... args) +{ + void* addr = owners_ptr.get(); + std::size_t size; + if (REALM_LIKELY(addr)) { + REALM_ASSERT(!owners_ptr->in_use()); + size = owners_ptr->m_size; + // We can use static dispatch in the destructor call here, since an + // object, that is not in use, is always an instance of UnusedOper. + REALM_ASSERT(dynamic_cast(owners_ptr.get())); + static_cast(owners_ptr.get())->UnusedOper::~UnusedOper(); + if (REALM_UNLIKELY(size < sizeof(Oper))) { + owners_ptr.release(); + delete[] static_cast(addr); + goto no_object; + } + } + else { + no_object: + addr = new char[sizeof(Oper)]; // Throws + size = sizeof(Oper); + owners_ptr.reset(static_cast(addr)); + } + std::unique_ptr lenders_ptr; + try { + lenders_ptr.reset(new (addr) Oper(size, std::forward(args)...)); // Throws + } + catch (...) { + new (addr) UnusedOper(size); // Does not throw + throw; + } + return lenders_ptr; +} + +template +inline Service::PostOperBase* Service::post_oper_constr(void* addr, std::size_t size, Impl& service, void* cookie) +{ + H& handler = *static_cast(cookie); + return new (addr) PostOper(size, service, std::move(handler)); // Throws +} + +inline bool Service::AsyncOper::in_use() const noexcept +{ + return m_in_use; +} + +inline bool Service::AsyncOper::is_complete() const noexcept +{ + return m_complete; +} + +inline void Service::AsyncOper::cancel() noexcept +{ + REALM_ASSERT(m_in_use); + REALM_ASSERT(!m_canceled); + m_canceled = true; +} + +inline Service::AsyncOper::AsyncOper(std::size_t size, bool is_in_use) noexcept + : m_size{size} + , m_in_use{is_in_use} +{ +} + +inline bool Service::AsyncOper::is_canceled() const noexcept +{ + return m_canceled; +} + +inline void Service::AsyncOper::set_is_complete(bool value) noexcept +{ + REALM_ASSERT(!m_complete); + REALM_ASSERT(!value || m_in_use); + m_complete = value; +} + +template +inline void Service::AsyncOper::do_recycle_and_execute(bool orphaned, H& handler, Args&&... args) +{ + // Recycle the operation object before the handler is exceuted, such that + // the memory is available for a new post operation that might be initiated + // during the execution of the handler. + bool was_recycled = false; + try { + // We need to copy or move all arguments to be passed to the handler, + // such that there is no risk of references to the recycled operation + // object being passed to the handler (the passed arguments may be + // references to members of the recycled operation object). The easiest + // way to achive this, is by forwarding the reference arguments (passed + // to this function) to a helper function whose arguments have + // nonreference type (`Args...` rather than `Args&&...`). + // + // Note that the copying and moving of arguments may throw, and it is + // important that the operation is still recycled even if that + // happens. For that reason, copying and moving of arguments must not + // happen until we are in a scope (this scope) that catches and deals + // correctly with such exceptions. + do_recycle_and_execute_helper(orphaned, was_recycled, std::move(handler), + std::forward(args)...); // Throws + } + catch (...) { + if (!was_recycled) + do_recycle(orphaned); + throw; + } +} + +template +inline void Service::AsyncOper::do_recycle_and_execute_helper(bool orphaned, bool& was_recycled, H handler, + Args... args) +{ + do_recycle(orphaned); + was_recycled = true; + handler(std::move(args)...); // Throws +} + +inline void Service::AsyncOper::do_recycle(bool orphaned) noexcept +{ + REALM_ASSERT(in_use()); + void* addr = this; + std::size_t size = m_size; + this->~AsyncOper(); // Suicide + if (orphaned) { + delete[] static_cast(addr); + } + else { + new (addr) UnusedOper(size); + } +} + +// ---------------- Resolver ---------------- + +template +class Resolver::ResolveOper : public Service::ResolveOperBase { +public: + ResolveOper(std::size_t size, Resolver& r, Query q, H handler) + : ResolveOperBase{size, r, std::move(q)} + , m_handler{std::move(handler)} + { + } + void recycle_and_execute() override final + { + REALM_ASSERT(is_complete() || (is_canceled() && !m_error_code)); + REALM_ASSERT(is_canceled() || m_error_code || !m_endpoints.empty()); + bool orphaned = !m_resolver; + std::error_code ec = m_error_code; + if (is_canceled()) + ec = error::operation_aborted; + // Note: do_recycle_and_execute() commits suicide. + do_recycle_and_execute(orphaned, m_handler, ec, std::move(m_endpoints)); // Throws + } + +private: + H m_handler; +}; + +inline Resolver::Resolver(Service& service) + : m_service_impl{*service.m_impl} +{ +} + +inline Resolver::~Resolver() noexcept +{ + cancel(); +} + +inline Endpoint::List Resolver::resolve(const Query& q) +{ + std::error_code ec; + Endpoint::List list = resolve(q, ec); + if (REALM_UNLIKELY(ec)) + throw std::system_error(ec); + return list; +} + +template +void Resolver::async_resolve(Query query, H handler) +{ + Service::LendersResolveOperPtr op = Service::alloc>(m_resolve_oper, *this, std::move(query), + std::move(handler)); // Throws + initiate_oper(std::move(op)); // Throws +} + +inline Resolver::Query::Query(std::string service_port, int init_flags) + : m_flags{init_flags} + , m_service{service_port} +{ +} + +inline Resolver::Query::Query(const StreamProtocol& prot, std::string service_port, int init_flags) + : m_flags{init_flags} + , m_protocol{prot} + , m_service{service_port} +{ +} + +inline Resolver::Query::Query(std::string host_name, std::string service_port, int init_flags) + : m_flags{init_flags} + , m_host{host_name} + , m_service{service_port} +{ +} + +inline Resolver::Query::Query(const StreamProtocol& prot, std::string host_name, std::string service_port, + int init_flags) + : m_flags{init_flags} + , m_protocol{prot} + , m_host{host_name} + , m_service{service_port} +{ +} + +inline Resolver::Query::~Query() noexcept {} + +inline int Resolver::Query::flags() const +{ + return m_flags; +} + +inline StreamProtocol Resolver::Query::protocol() const +{ + return m_protocol; +} + +inline std::string Resolver::Query::host() const +{ + return m_host; +} + +inline std::string Resolver::Query::service() const +{ + return m_service; +} + +// ---------------- SocketBase ---------------- + +inline SocketBase::SocketBase(Service& service) + : m_desc{*service.m_impl} +{ +} + +inline SocketBase::~SocketBase() noexcept +{ + close(); +} + +inline bool SocketBase::is_open() const noexcept +{ + return m_desc.is_open(); +} + +inline auto SocketBase::native_handle() const noexcept -> native_handle_type +{ + return m_desc.native_handle(); +} + +inline void SocketBase::open(const StreamProtocol& prot) +{ + std::error_code ec; + if (open(prot, ec)) + throw std::system_error(ec); +} + +inline void SocketBase::close() noexcept +{ + if (!is_open()) + return; + cancel(); + m_desc.close(); +} + +template +inline void SocketBase::get_option(O& opt) const +{ + std::error_code ec; + if (get_option(opt, ec)) + throw std::system_error(ec); +} + +template +inline std::error_code SocketBase::get_option(O& opt, std::error_code& ec) const +{ + opt.get(*this, ec); + return ec; +} + +template +inline void SocketBase::set_option(const O& opt) +{ + std::error_code ec; + if (set_option(opt, ec)) + throw std::system_error(ec); +} + +template +inline std::error_code SocketBase::set_option(const O& opt, std::error_code& ec) +{ + opt.set(*this, ec); + return ec; +} + +inline void SocketBase::bind(const Endpoint& ep) +{ + std::error_code ec; + if (bind(ep, ec)) + throw std::system_error(ec); +} + +inline Endpoint SocketBase::local_endpoint() const +{ + std::error_code ec; + Endpoint ep = local_endpoint(ec); + if (ec) + throw std::system_error(ec); + return ep; +} + +inline auto SocketBase::release_native_handle() noexcept -> native_handle_type +{ + if (is_open()) { + cancel(); + return m_desc.release(); + } + return m_desc.native_handle(); +} + +inline const StreamProtocol& SocketBase::get_protocol() const noexcept +{ + return m_protocol; +} + +template +inline SocketBase::Option::Option(T init_value) + : m_value{init_value} +{ +} + +template +inline T SocketBase::Option::value() const +{ + return m_value; +} + +template +inline void SocketBase::Option::get(const SocketBase& sock, std::error_code& ec) +{ + union { + U value; + char strut[sizeof(U) + 1]; + }; + std::size_t value_size = sizeof strut; + sock.get_option(opt_enum(opt), &value, value_size, ec); + if (!ec) { + REALM_ASSERT(value_size == sizeof value); + m_value = T(value); + } +} + +template +inline void SocketBase::Option::set(SocketBase& sock, std::error_code& ec) const +{ + U value_to_set = U(m_value); + sock.set_option(opt_enum(opt), &value_to_set, sizeof value_to_set, ec); +} + +// ---------------- Socket ---------------- + +class Socket::ConnectOperBase : public Service::IoOper { +public: + ConnectOperBase(std::size_t size, Socket& sock) noexcept + : IoOper{size} + , m_socket{&sock} + { + } + Want initiate(const Endpoint& ep) + { + REALM_ASSERT(this == m_socket->m_write_oper.get()); + if (m_socket->initiate_async_connect(ep, m_error_code)) { // Throws + set_is_complete(true); // Failure, or immediate completion + return Want::nothing; + } + return Want::write; + } + Want advance() noexcept override final + { + REALM_ASSERT(!is_complete()); + REALM_ASSERT(!is_canceled()); + REALM_ASSERT(!m_error_code); + m_socket->finalize_async_connect(m_error_code); + set_is_complete(true); + return Want::nothing; + } + void recycle() noexcept override final + { + bool orphaned = !m_socket; + REALM_ASSERT(orphaned); + // Note: do_recycle() commits suicide. + do_recycle(orphaned); + } + void orphan() noexcept override final + { + m_socket = nullptr; + } + Service::Descriptor& descriptor() noexcept override final + { + return m_socket->m_desc; + } + +protected: + Socket* m_socket; + std::error_code m_error_code; +}; + +template +class Socket::ConnectOper : public ConnectOperBase { +public: + ConnectOper(std::size_t size, Socket& sock, H handler) + : ConnectOperBase{size, sock} + , m_handler{std::move(handler)} + { + } + void recycle_and_execute() override final + { + REALM_ASSERT(is_complete() || (is_canceled() && !m_error_code)); + bool orphaned = !m_socket; + std::error_code ec = m_error_code; + if (is_canceled()) + ec = error::operation_aborted; + // Note: do_recycle_and_execute() commits suicide. + do_recycle_and_execute(orphaned, m_handler, ec); // Throws + } + +private: + H m_handler; +}; + +inline Socket::Socket(Service& service) + : SocketBase{service} +{ +} + +inline Socket::Socket(Service& service, const StreamProtocol& prot, native_handle_type native_socket) + : SocketBase{service} +{ + assign(prot, native_socket); // Throws +} + +inline Socket::~Socket() noexcept {} + +inline void Socket::connect(const Endpoint& ep) +{ + std::error_code ec; + if (connect(ep, ec)) // Throws + throw std::system_error(ec); +} + +inline std::size_t Socket::read(char* buffer, std::size_t size) +{ + std::error_code ec; + read(buffer, size, ec); // Throws + if (ec) + throw std::system_error(ec); + return size; +} + +inline std::size_t Socket::read(char* buffer, std::size_t size, std::error_code& ec) +{ + return StreamOps::read(*this, buffer, size, ec); // Throws +} + +inline std::size_t Socket::read(char* buffer, std::size_t size, ReadAheadBuffer& rab) +{ + std::error_code ec; + read(buffer, size, rab, ec); // Throws + if (ec) + throw std::system_error(ec); + return size; +} + +inline std::size_t Socket::read(char* buffer, std::size_t size, ReadAheadBuffer& rab, std::error_code& ec) +{ + int delim = std::char_traits::eof(); + return StreamOps::buffered_read(*this, buffer, size, delim, rab, ec); // Throws +} + +inline std::size_t Socket::read_until(char* buffer, std::size_t size, char delim, ReadAheadBuffer& rab) +{ + std::error_code ec; + std::size_t n = read_until(buffer, size, delim, rab, ec); // Throws + if (ec) + throw std::system_error(ec); + return n; +} + +inline std::size_t Socket::read_until(char* buffer, std::size_t size, char delim, ReadAheadBuffer& rab, + std::error_code& ec) +{ + int delim_2 = std::char_traits::to_int_type(delim); + return StreamOps::buffered_read(*this, buffer, size, delim_2, rab, ec); // Throws +} + +inline std::size_t Socket::write(const char* data, std::size_t size) +{ + std::error_code ec; + write(data, size, ec); // Throws + if (ec) + throw std::system_error(ec); + return size; +} + +inline std::size_t Socket::write(const char* data, std::size_t size, std::error_code& ec) +{ + return StreamOps::write(*this, data, size, ec); // Throws +} + +inline std::size_t Socket::read_some(char* buffer, std::size_t size) +{ + std::error_code ec; + std::size_t n = read_some(buffer, size, ec); // Throws + if (ec) + throw std::system_error(ec); + return n; +} + +inline std::size_t Socket::read_some(char* buffer, std::size_t size, std::error_code& ec) +{ + return StreamOps::read_some(*this, buffer, size, ec); // Throws +} + +inline std::size_t Socket::write_some(const char* data, std::size_t size) +{ + std::error_code ec; + std::size_t n = write_some(data, size, ec); // Throws + if (ec) + throw std::system_error(ec); + return n; +} + +inline std::size_t Socket::write_some(const char* data, std::size_t size, std::error_code& ec) +{ + return StreamOps::write_some(*this, data, size, ec); // Throws +} + +template +inline void Socket::async_connect(const Endpoint& ep, H handler) +{ + LendersConnectOperPtr op = Service::alloc>(m_write_oper, *this, std::move(handler)); // Throws + m_desc.initiate_oper(std::move(op), ep); // Throws +} + +template +inline void Socket::async_read(char* buffer, std::size_t size, H handler) +{ + bool is_read_some = false; + StreamOps::async_read(*this, buffer, size, is_read_some, std::move(handler)); // Throws +} + +template +inline void Socket::async_read(char* buffer, std::size_t size, ReadAheadBuffer& rab, H handler) +{ + int delim = std::char_traits::eof(); + StreamOps::async_buffered_read(*this, buffer, size, delim, rab, std::move(handler)); // Throws +} + +template +inline void Socket::async_read_until(char* buffer, std::size_t size, char delim, ReadAheadBuffer& rab, H handler) +{ + int delim_2 = std::char_traits::to_int_type(delim); + StreamOps::async_buffered_read(*this, buffer, size, delim_2, rab, std::move(handler)); // Throws +} + +template +inline void Socket::async_write(const char* data, std::size_t size, H handler) +{ + bool is_write_some = false; + StreamOps::async_write(*this, data, size, is_write_some, std::move(handler)); // Throws +} + +template +inline void Socket::async_read_some(char* buffer, std::size_t size, H handler) +{ + bool is_read_some = true; + StreamOps::async_read(*this, buffer, size, is_read_some, std::move(handler)); // Throws +} + +template +inline void Socket::async_write_some(const char* data, std::size_t size, H handler) +{ + bool is_write_some = true; + StreamOps::async_write(*this, data, size, is_write_some, std::move(handler)); // Throws +} + +inline void Socket::shutdown(shutdown_type what) +{ + std::error_code ec; + if (shutdown(what, ec)) // Throws + throw std::system_error(ec); +} + +inline void Socket::assign(const StreamProtocol& prot, native_handle_type native_socket) +{ + std::error_code ec; + if (assign(prot, native_socket, ec)) // Throws + throw std::system_error(ec); +} + +inline std::error_code Socket::assign(const StreamProtocol& prot, native_handle_type native_socket, + std::error_code& ec) +{ + return do_assign(prot, native_socket, ec); // Throws +} + +inline Socket& Socket::lowest_layer() noexcept +{ + return *this; +} + +inline void Socket::do_init_read_async(std::error_code&, Want& want) noexcept +{ + want = Want::read; // Wait for read readiness before proceeding +} + +inline void Socket::do_init_write_async(std::error_code&, Want& want) noexcept +{ + want = Want::write; // Wait for write readiness before proceeding +} + +inline std::size_t Socket::do_read_some_sync(char* buffer, std::size_t size, std::error_code& ec) noexcept +{ + return m_desc.read_some(buffer, size, ec); +} + +inline std::size_t Socket::do_write_some_sync(const char* data, std::size_t size, std::error_code& ec) noexcept +{ + return m_desc.write_some(data, size, ec); +} + +inline std::size_t Socket::do_read_some_async(char* buffer, std::size_t size, std::error_code& ec, + Want& want) noexcept +{ + std::error_code ec_2; + std::size_t n = m_desc.read_some(buffer, size, ec_2); + bool success = (!ec_2 || ec_2 == error::resource_unavailable_try_again); + if (REALM_UNLIKELY(!success)) { + ec = ec_2; + want = Want::nothing; // Failure + return 0; + } + ec = std::error_code(); + want = Want::read; // Success + return n; +} + +inline std::size_t Socket::do_write_some_async(const char* data, std::size_t size, std::error_code& ec, + Want& want) noexcept +{ + std::error_code ec_2; + std::size_t n = m_desc.write_some(data, size, ec_2); + bool success = (!ec_2 || ec_2 == error::resource_unavailable_try_again); + if (REALM_UNLIKELY(!success)) { + ec = ec_2; + want = Want::nothing; // Failure + return 0; + } + ec = std::error_code(); + want = Want::write; // Success + return n; +} + +// ---------------- Acceptor ---------------- + +class Acceptor::AcceptOperBase : public Service::IoOper { +public: + AcceptOperBase(std::size_t size, Acceptor& a, Socket& s, Endpoint* e) + : IoOper{size} + , m_acceptor{&a} + , m_socket{s} + , m_endpoint{e} + { + } + Want initiate() + { + REALM_ASSERT(this == m_acceptor->m_read_oper.get()); + REALM_ASSERT(!is_complete()); + m_acceptor->m_desc.ensure_nonblocking_mode(); // Throws + return Want::read; + } + Want advance() noexcept override final + { + REALM_ASSERT(!is_complete()); + REALM_ASSERT(!is_canceled()); + REALM_ASSERT(!m_error_code); + REALM_ASSERT(!m_socket.is_open()); + Want want = m_acceptor->do_accept_async(m_socket, m_endpoint, m_error_code); + if (want == Want::nothing) + set_is_complete(true); // Success or failure + return want; + } + void recycle() noexcept override final + { + bool orphaned = !m_acceptor; + REALM_ASSERT(orphaned); + // Note: do_recycle() commits suicide. + do_recycle(orphaned); + } + void orphan() noexcept override final + { + m_acceptor = nullptr; + } + Service::Descriptor& descriptor() noexcept override final + { + return m_acceptor->m_desc; + } + +protected: + Acceptor* m_acceptor; + Socket& m_socket; // May be dangling after cancellation + Endpoint* const m_endpoint; // May be dangling after cancellation + std::error_code m_error_code; +}; + +template +class Acceptor::AcceptOper : public AcceptOperBase { +public: + AcceptOper(std::size_t size, Acceptor& a, Socket& s, Endpoint* e, H handler) + : AcceptOperBase{size, a, s, e} + , m_handler{std::move(handler)} + { + } + void recycle_and_execute() override final + { + REALM_ASSERT(is_complete() || (is_canceled() && !m_error_code)); + REALM_ASSERT(is_canceled() || m_error_code || m_socket.is_open()); + bool orphaned = !m_acceptor; + std::error_code ec = m_error_code; + if (is_canceled()) + ec = error::operation_aborted; + // Note: do_recycle_and_execute() commits suicide. + do_recycle_and_execute(orphaned, m_handler, ec); // Throws + } + +private: + H m_handler; +}; + +inline Acceptor::Acceptor(Service& service) + : SocketBase{service} +{ +} + +inline Acceptor::~Acceptor() noexcept {} + +inline void Acceptor::listen(int backlog) +{ + std::error_code ec; + if (listen(backlog, ec)) // Throws + throw std::system_error(ec); +} + +inline void Acceptor::accept(Socket& sock) +{ + std::error_code ec; + if (accept(sock, ec)) // Throws + throw std::system_error(ec); +} + +inline void Acceptor::accept(Socket& sock, Endpoint& ep) +{ + std::error_code ec; + if (accept(sock, ep, ec)) // Throws + throw std::system_error(ec); +} + +inline std::error_code Acceptor::accept(Socket& sock, std::error_code& ec) +{ + Endpoint* ep = nullptr; + return accept(sock, ep, ec); // Throws +} + +inline std::error_code Acceptor::accept(Socket& sock, Endpoint& ep, std::error_code& ec) +{ + return accept(sock, &ep, ec); // Throws +} + +template +inline void Acceptor::async_accept(Socket& sock, H handler) +{ + Endpoint* ep = nullptr; + async_accept(sock, ep, std::move(handler)); // Throws +} + +template +inline void Acceptor::async_accept(Socket& sock, Endpoint& ep, H handler) +{ + async_accept(sock, &ep, std::move(handler)); // Throws +} + +inline std::error_code Acceptor::accept(Socket& socket, Endpoint* ep, std::error_code& ec) +{ + REALM_ASSERT(!m_read_oper || !m_read_oper->in_use()); + if (REALM_UNLIKELY(socket.is_open())) + throw util::runtime_error("Socket is already open"); + m_desc.ensure_blocking_mode(); // Throws + m_desc.accept(socket.m_desc, m_protocol, ep, ec); + return ec; +} + +inline Acceptor::Want Acceptor::do_accept_async(Socket& socket, Endpoint* ep, std::error_code& ec) noexcept +{ + std::error_code ec_2; + m_desc.accept(socket.m_desc, m_protocol, ep, ec_2); + if (ec_2 == error::resource_unavailable_try_again) + return Want::read; + ec = ec_2; + return Want::nothing; +} + +template +inline void Acceptor::async_accept(Socket& sock, Endpoint* ep, H handler) +{ + if (REALM_UNLIKELY(sock.is_open())) + throw util::runtime_error("Socket is already open"); + LendersAcceptOperPtr op = Service::alloc>(m_read_oper, *this, sock, ep, + std::move(handler)); // Throws + m_desc.initiate_oper(std::move(op)); // Throws +} + +// ---------------- DeadlineTimer ---------------- + +template +class DeadlineTimer::WaitOper : public Service::WaitOperBase { +public: + WaitOper(std::size_t size, DeadlineTimer& timer, clock::time_point expiration_time, H handler) + : Service::WaitOperBase{size, timer, expiration_time} + , m_handler{std::move(handler)} + { + } + void recycle_and_execute() override final + { + bool orphaned = !m_timer; + std::error_code ec; + if (is_canceled()) + ec = error::operation_aborted; + // Note: do_recycle_and_execute() commits suicide. + do_recycle_and_execute(orphaned, m_handler, ec); // Throws + } + +private: + H m_handler; +}; + +inline DeadlineTimer::DeadlineTimer(Service& service) + : m_service_impl{*service.m_impl} +{ +} + +inline DeadlineTimer::~DeadlineTimer() noexcept +{ + cancel(); +} + +template +inline void DeadlineTimer::async_wait(std::chrono::duration delay, H handler) +{ + clock::time_point now = clock::now(); + // FIXME: This method of detecting overflow does not work. Comparison + // between distinct duration types is not overflow safe. Overflow easily + // happens in the implied conversion of arguments to the common duration + // type (std::common_type<>). + auto max_add = clock::time_point::max() - now; + if (delay > max_add) + throw util::overflow_error("Expiration time overflow"); + clock::time_point expiration_time = now + delay; + Service::LendersWaitOperPtr op = Service::alloc>(m_wait_oper, *this, expiration_time, + std::move(handler)); // Throws + initiate_oper(std::move(op)); // Throws +} + +// ---------------- Trigger ---------------- + +template +class Trigger::ExecOper : public Service::TriggerExecOperBase { +public: + ExecOper(Service::Impl& service_impl, H handler) + : Service::TriggerExecOperBase{service_impl} + , m_handler{std::move(handler)} + { + } + void recycle_and_execute() override final + { + REALM_ASSERT(in_use()); + // Note: Potential suicide when `self` goes out of scope + util::bind_ptr self{this, bind_ptr_base::adopt_tag{}}; + if (m_service) { + Service::reset_trigger_exec(*m_service, *this); + m_handler(); // Throws + } + } + +private: + H m_handler; +}; + +template +inline Trigger::Trigger(Service& service, H handler) + : m_exec_oper{new ExecOper{*service.m_impl, std::move(handler)}} // Throws +{ +} + +inline Trigger::~Trigger() noexcept +{ + if (m_exec_oper) + m_exec_oper->orphan(); +} + +inline void Trigger::trigger() noexcept +{ + REALM_ASSERT(m_exec_oper); + m_exec_oper->trigger(); +} + +// ---------------- ReadAheadBuffer ---------------- + +inline ReadAheadBuffer::ReadAheadBuffer() + : m_buffer{new char[s_size]} // Throws +{ +} + +inline void ReadAheadBuffer::clear() noexcept +{ + m_begin = nullptr; + m_end = nullptr; +} + +inline bool ReadAheadBuffer::empty() const noexcept +{ + return (m_begin == m_end); +} + +template +inline void ReadAheadBuffer::refill_sync(S& stream, std::error_code& ec) noexcept +{ + char* buffer = m_buffer.get(); + std::size_t size = s_size; + static_assert(noexcept(stream.do_read_some_sync(buffer, size, ec)), ""); + std::size_t n = stream.do_read_some_sync(buffer, size, ec); + if (REALM_UNLIKELY(n == 0)) + return; + REALM_ASSERT(!ec); + REALM_ASSERT(n <= size); + m_begin = m_buffer.get(); + m_end = m_begin + n; +} + +template +inline bool ReadAheadBuffer::refill_async(S& stream, std::error_code& ec, Want& want) noexcept +{ + char* buffer = m_buffer.get(); + std::size_t size = s_size; + static_assert(noexcept(stream.do_read_some_async(buffer, size, ec, want)), ""); + std::size_t n = stream.do_read_some_async(buffer, size, ec, want); + if (n == 0) + return false; + REALM_ASSERT(!ec); + REALM_ASSERT(n <= size); + m_begin = m_buffer.get(); + m_end = m_begin + n; + return true; +} + +} // namespace network +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_NETWORK_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/network_ssl.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/network_ssl.hpp new file mode 100644 index 0000000..33c3abc --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/network_ssl.hpp @@ -0,0 +1,1353 @@ +#ifndef REALM_UTIL_NETWORK_SSL_HPP +#define REALM_UTIL_NETWORK_SSL_HPP + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#if REALM_HAVE_OPENSSL +#include +#include +#elif REALM_HAVE_SECURE_TRANSPORT +#include +#include +#include + +#define REALM_HAVE_KEYCHAIN_APIS (TARGET_OS_MAC && !TARGET_OS_IPHONE) + +#endif + +// FIXME: Add necessary support for customizing the SSL server and client +// configurations. + +// FIXME: Currently, the synchronous SSL operations (handshake, read, write, +// shutdown) do not automatically retry if the underlying SSL function returns +// with SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE. This normally never +// happens, but it can happen according to the man pages, but in the case of +// SSL_write(), only when a renegotiation has to take place. It is likely that +// the solution is to to wrap the SSL calls inside a loop, such that they keep +// retrying until they succeed, however, such a simple scheme will fail if the +// synchronous operations were to be used with an underlying TCP socket in +// nonblocking mode. Currently, the underlying TCP socket is always in blocking +// mode when performing synchronous operations, but that may continue to be the +// case in teh future. + + +namespace realm { +namespace util { +namespace network { +namespace ssl { + +enum class Errors { + certificate_rejected = 1, +}; + +class ErrorCategory : public std::error_category { +public: + const char* name() const noexcept override final; + std::string message(int) const override final; + bool equivalent(const std::error_code&, int) const noexcept override final; +}; + +/// The error category associated with \ref Errors. The name of this category is +/// `realm.util.network.ssl`. +extern ErrorCategory error_category; + +inline std::error_code make_error_code(Errors err) +{ + return std::error_code(int(err), error_category); +} + +inline std::error_condition make_error_condition(Errors err) +{ + return std::error_condition(int(err), error_category); +} + +} // namespace ssl +} // namespace network +} // namespace util +} // namespace realm + +namespace std { + +template <> +class is_error_condition_enum { +public: + static const bool value = true; +}; + +} // namespace std + +namespace realm { +namespace util { +namespace network { + +class OpensslErrorCategory : public std::error_category { +public: + const char* name() const noexcept override final; + std::string message(int) const override final; +}; + +/// The error category associated with error codes produced by the third-party +/// library, OpenSSL. The name of this category is `openssl`. +extern OpensslErrorCategory openssl_error_category; + +class SecureTransportErrorCategory : public std::error_category { +public: + const char* name() const noexcept override final; + std::string message(int) const override final; +}; + +/// The error category associated with error codes produced by Apple's +/// SecureTransport library. The name of this category is `securetransport`. +extern SecureTransportErrorCategory secure_transport_error_category; + + +namespace ssl { + +class ProtocolNotSupported; + + +/// `VerifyMode::none` corresponds to OpenSSL's `SSL_VERIFY_NONE`, and +/// `VerifyMode::peer` to `SSL_VERIFY_PEER`. +enum class VerifyMode { none, peer }; + + +class Context { +public: + Context(); + ~Context() noexcept; + + /// File must be in PEM format. Corresponds to OpenSSL's + /// `SSL_CTX_use_certificate_chain_file()`. + void use_certificate_chain_file(const std::string& path); + + /// File must be in PEM format. Corresponds to OpenSSL's + /// `SSL_CTX_use_PrivateKey_file()`. + void use_private_key_file(const std::string& path); + + /// Calling use_default_verify() will make a client use the device + /// default certificates for server verification. For OpenSSL, + /// use_default_verify() corresponds to + /// SSL_CTX_set_default_verify_paths(SSL_CTX*); + void use_default_verify(); + + /// The verify file is a PEM file containing trust certificates that the + /// client will use to verify the server certificate. If use_verify_file() + /// is not called, the default device trust store will be used. + /// use_verify_file() corresponds roughly to OpenSSL's + /// SSL_CTX_load_verify_locations(). + void use_verify_file(const std::string& path); + +private: + void ssl_init(); + void ssl_destroy() noexcept; + void ssl_use_certificate_chain_file(const std::string& path, std::error_code&); + void ssl_use_private_key_file(const std::string& path, std::error_code&); + void ssl_use_default_verify(std::error_code&); + void ssl_use_verify_file(const std::string& path, std::error_code&); + +#if REALM_HAVE_OPENSSL + SSL_CTX* m_ssl_ctx = nullptr; + +#elif REALM_HAVE_SECURE_TRANSPORT + +#if REALM_HAVE_KEYCHAIN_APIS + std::error_code open_temporary_keychain_if_needed(); + std::error_code update_identity_if_needed(); + + util::CFPtr m_keychain; + std::string m_keychain_path; + + util::CFPtr m_certificate; + util::CFPtr m_private_key; + util::CFPtr m_identity; + + util::CFPtr m_certificate_chain; + +#else + using SecKeychainRef = std::nullptr_t; + +#endif // REALM_HAVE_KEYCHAIN_APIS + static util::CFPtr load_pem_file(const std::string& path, SecKeychainRef, std::error_code&); + + util::CFPtr m_trust_anchors; + util::CFPtr m_pinned_certificate; + +#endif + + friend class Stream; +}; + + +/// Switching between synchronous and asynchronous operations is allowed, but +/// only in a nonoverlapping fashion. That is, a synchronous operation is not +/// allowed to run concurrently with an asynchronous one on the same +/// stream. Note that an asynchronous operation is considered to be running +/// until its completion handler starts executing. +class Stream { +public: + using port_type = util::network::Endpoint::port_type; + using SSLVerifyCallback = bool(const std::string& server_address, port_type server_port, const char* pem_data, + size_t pem_size, int preverify_ok, int depth); + + enum HandshakeType { client, server }; + + util::Logger* logger = nullptr; + + Stream(Socket&, Context&, HandshakeType); + ~Stream() noexcept; + + /// \brief set_logger() set a logger for the stream class. If + /// set_logger() is not called, no logging will take place by + /// the Stream class. + void set_logger(util::Logger*); + + /// \brief Set the certificate verification mode for this SSL stream. + /// + /// Corresponds to OpenSSL's `SSL_set_verify()` with null passed as + /// `verify_callback`. + /// + /// Clients should always set it to `VerifyMode::peer`, such that the client + /// verifies the servers certificate. Servers should only set it to + /// `VerifyMode::peer` if they want to request a certificate from the + /// client. When testing with self-signed certificates, it is necessary to + /// set it to `VerifyMode::none` for clients too. + /// + /// It is an error if this function is called after the handshake operation + /// is initiated. + /// + /// The default verify mode is `VerifyMode::none`. + void set_verify_mode(VerifyMode); + + /// \brief Check the certificate against a host_name. + /// + /// On the client side, this enables the Server Name Indication (TLS/SNI) + /// extension if supported by the underlying platform. For OpenSSL, it is + /// enabled starting from version 1.1.1. + /// + /// Additionally, this turns on a host name check as part of certificate + /// verification, if certificate verification is enabled + /// (set_verify_mode()). + /// + /// NOTE: With Secure Transport on macos, host name check will be turned on + /// regardless of whether certificate verification is enabled (see + /// https://github.com/curl/curl/pull/1240#issuecomment-285281512). + void set_host_name(std::string host_name); + + /// get_server_port() and set_server_port() are getter and setter for + /// the server port. They are only used by the verify callback function + /// below. + void set_server_port(port_type server_port); + + /// If use_verify_callback() is called, the SSL certificate chain of + /// the server is presented to callback, one certificate at a time. + /// The SSL connection is accepted if and only if callback returns true + /// for all certificates. + /// The signature of \param callback is + /// + /// bool(const std::string& server_address, + /// port_type server_port, + /// const char* pem_data, + /// size_t pem_size, + /// int preverify_ok, + /// int depth); + // + /// server address and server_port is the address and port of the server + /// that a SSL connection is being established to. + /// pem_data is the certificate of length pem_size in + /// the PEM format. preverify_ok is OpenSSL's preverification of the + /// certificate. preverify_ok is either 0, or 1. If preverify_ok is 1, + /// OpenSSL has accepted the certificate and it will generally be safe + /// to trust that certificate. depth represents the position of the + /// certificate in the certificate chain sent by the server. depth = 0 + /// represents the actual server certificate that should contain the + /// host name(server address) of the server. The highest depth is the + /// root certificate. + /// The callback function will receive the certificates starting from + /// the root certificate and moving down the chain until it reaches the + /// server's own certificate with a host name. The depth of the last + /// certificate is 0. The depth of the first certificate is chain + /// length - 1. + /// + /// The return value of the callback function decides whether the + /// client accepts the certificate. If the return value is false, the + /// processing of the certificate chain is interrupted and the SSL + /// connection is rejected. If the return value is true, the verification + /// process continues. If the callback function returns true for all + /// presented certificates including the depth == 0 certificate, the + /// SSL connection is accepted. + /// + /// A recommended way of using the callback function is to return true + /// if preverify_ok = 1 and depth > 0, + /// always check the host name if depth = 0, + /// and use an independent verification step if preverify_ok = 0. + /// + /// Another possible way of using the callback is to collect all the + /// certificates until depth = 0, and present the entire chain for + /// independent verification. + void use_verify_callback(const std::function& callback); + +#ifdef REALM_INCLUDE_CERTS + /// use_included_certificates() loads a set of certificates that are + /// included in the header file src/realm/noinst/root_certs.hpp. By using + /// the included certificates, the client can verify a server in the case + /// where the relevant certificate cannot be found, or is absent, in the + /// system trust store. This function is only implemented for OpenSSL. + void use_included_certificates(); +#endif + + /// @{ + /// + /// Read and write operations behave the same way as they do on \ref + /// network::Socket, except that after cancellation of asynchronous + /// operations (`lowest_layer().cancel()`), the stream may be left in a bad + /// state (see below). + /// + /// The handshake operation must complete successfully before any read, + /// write, or shutdown operations are performed. + /// + /// The shutdown operation sends the shutdown alert to the peer, and + /// returns/completes as soon as the alert message has been written to the + /// underlying socket. It is an error if the shutdown operation is initiated + /// while there are read or write operations in progress. No read or write + /// operations are allowed to be initiated after the shutdown operation has + /// been initiated. When the shutdown operation has completed, it is safe to + /// close the underlying socket (`lowest_layer().close()`). + /// + /// If a write operation is executing while, or is initiated after a close + /// notify alert is received from the remote peer, the write operation will + /// fail with error::broken_pipe. + /// + /// Callback functions for async read and write operations must take two + /// arguments, an std::error_code(), and an integer of a type std::size_t + /// indicating the number of transferred bytes (other types are allowed as + /// long as implicit conversion can take place). + /// + /// Callback functions for async handshake and shutdown operations must take + /// a single argument of type std::error_code() (other types are allowed as + /// long as implicit conversion can take place). + /// + /// Resumption of stream operation after cancellation of asynchronous + /// operations is not supported (does not work). Since the shutdown + /// operation involves network communication, that operation is also not + /// allowed after cancellation. The only thing that is allowed, is to + /// destroy the stream object. Other stream objects are not affected. + + void handshake(); + std::error_code handshake(std::error_code&); + + std::size_t read(char* buffer, std::size_t size); + std::size_t read(char* buffer, std::size_t size, std::error_code& ec); + std::size_t read(char* buffer, std::size_t size, ReadAheadBuffer&); + std::size_t read(char* buffer, std::size_t size, ReadAheadBuffer&, std::error_code& ec); + std::size_t read_until(char* buffer, std::size_t size, char delim, ReadAheadBuffer&); + std::size_t read_until(char* buffer, std::size_t size, char delim, ReadAheadBuffer&, std::error_code& ec); + + std::size_t write(const char* data, std::size_t size); + std::size_t write(const char* data, std::size_t size, std::error_code& ec); + + std::size_t read_some(char* buffer, std::size_t size); + std::size_t read_some(char* buffer, std::size_t size, std::error_code&); + + std::size_t write_some(const char* data, std::size_t size); + std::size_t write_some(const char* data, std::size_t size, std::error_code&); + + void shutdown(); + std::error_code shutdown(std::error_code&); + + template + void async_handshake(H handler); + + template + void async_read(char* buffer, std::size_t size, H handler); + template + void async_read(char* buffer, std::size_t size, ReadAheadBuffer&, H handler); + template + void async_read_until(char* buffer, std::size_t size, char delim, ReadAheadBuffer&, H handler); + + template + void async_write(const char* data, std::size_t size, H handler); + + template + void async_read_some(char* buffer, std::size_t size, H handler); + + template + void async_write_some(const char* data, std::size_t size, H handler); + + template + void async_shutdown(H handler); + + /// @} + + /// Returns a reference to the underlying socket. + Socket& lowest_layer() noexcept; + +private: + using Want = Service::Want; + using StreamOps = Service::BasicStreamOps; + + class HandshakeOperBase; + template + class HandshakeOper; + class ShutdownOperBase; + template + class ShutdownOper; + + using LendersHandshakeOperPtr = std::unique_ptr; + using LendersShutdownOperPtr = std::unique_ptr; + + Socket& m_tcp_socket; + Context& m_ssl_context; + const HandshakeType m_handshake_type; + + // The host name that the certificate should be checked against. + // The host name is called server address in the certificate verify + // callback function. + std::string m_host_name; + + // The port of the server which is used in the certificate verify + // callback function. + port_type m_server_port; + + // The callback for certificate verification and an + // opaque argument that will be supplied to the callback. + const std::function* m_ssl_verify_callback = nullptr; + + bool m_valid_certificate_in_chain = false; + + + // See Service::BasicStreamOps for details on these these 6 functions. + void do_init_read_async(std::error_code&, Want&) noexcept; + void do_init_write_async(std::error_code&, Want&) noexcept; + std::size_t do_read_some_sync(char* buffer, std::size_t size, std::error_code&) noexcept; + std::size_t do_write_some_sync(const char* data, std::size_t size, std::error_code&) noexcept; + std::size_t do_read_some_async(char* buffer, std::size_t size, std::error_code&, Want&) noexcept; + std::size_t do_write_some_async(const char* data, std::size_t size, std::error_code&, Want&) noexcept; + + // The meaning of the arguments and return values of ssl_read() and + // ssl_write() are identical to do_read_some_async() and + // do_write_some_async() respectively, except that when the return value is + // nonzero, `want` is always `Want::nothing`, meaning that after bytes have + // been transferred, ssl_read() and ssl_write() must be called again to + // figure out whether it is necessary to wait for read or write readiness. + // + // The first invocation of ssl_shutdown() must send the shutdown alert to + // the peer. In blocking mode it must wait until the alert has been sent. In + // nonblocking mode, it must keep setting `want` to something other than + // `Want::nothing` until the alert has been sent. When the shutdown alert + // has been sent, it is safe to shut down the sending side of the underlying + // socket. On failure, ssl_shutdown() must set `ec` to something different + // than `std::error_code()` and return false. On success, it must set `ec` + // to `std::error_code()`, and return true if a shutdown alert from the peer + // has already been received, otherwise it must return false. When it sets + // `want` to something other than `Want::nothing`, it must set `ec` to + // `std::error_code()` and return false. + // + // The second invocation of ssl_shutdown() (after the first invocation + // completed) must wait for reception on the peers shutdown alert. + // + // Note: The semantics around the second invocation of shutdown is currently + // unused by the higher level API, because of a requirement of compatibility + // with Apple's Secure Transport API. + void ssl_init(); + void ssl_destroy() noexcept; + void ssl_set_verify_mode(VerifyMode, std::error_code&); + void ssl_set_host_name(const std::string&, std::error_code&); + void ssl_use_verify_callback(const std::function&, std::error_code&); + void ssl_use_included_certificates(std::error_code&); + + void ssl_handshake(std::error_code&, Want& want) noexcept; + bool ssl_shutdown(std::error_code& ec, Want& want) noexcept; + std::size_t ssl_read(char* buffer, std::size_t size, std::error_code&, Want& want) noexcept; + std::size_t ssl_write(const char* data, std::size_t size, std::error_code&, Want& want) noexcept; + +#if REALM_HAVE_OPENSSL + class BioMethod; + static BioMethod s_bio_method; + SSL* m_ssl = nullptr; + std::error_code m_bio_error_code; + + int m_ssl_index = -1; + + template + std::size_t ssl_perform(Oper oper, std::error_code& ec, Want& want) noexcept; + + int do_ssl_accept() noexcept; + int do_ssl_connect() noexcept; + int do_ssl_shutdown() noexcept; + int do_ssl_read(char* buffer, std::size_t size) noexcept; + int do_ssl_write(const char* data, std::size_t size) noexcept; + + static int bio_write(BIO*, const char*, int) noexcept; + static int bio_read(BIO*, char*, int) noexcept; + static int bio_puts(BIO*, const char*) noexcept; + static long bio_ctrl(BIO*, int, long, void*) noexcept; + static int bio_create(BIO*) noexcept; + static int bio_destroy(BIO*) noexcept; + + // verify_callback_using_hostname is used as an argument to OpenSSL's SSL_set_verify function. + // verify_callback_using_hostname verifies that the certificate is valid and contains + // m_host_name as a Common Name or Subject Alternative Name. + static int verify_callback_using_hostname(int preverify_ok, X509_STORE_CTX* ctx) noexcept; + + // verify_callback_using_delegate() is also used as an argument to OpenSSL's set_verify_function. + // verify_callback_using_delegate() calls out to the user supplied verify callback. + static int verify_callback_using_delegate(int preverify_ok, X509_STORE_CTX* ctx) noexcept; + + // verify_callback_using_root_certs is used by OpenSSL to handle certificate verification + // using the included root certifictes. + static int verify_callback_using_root_certs(int preverify_ok, X509_STORE_CTX* ctx); +#elif REALM_HAVE_SECURE_TRANSPORT + util::CFPtr m_ssl; + VerifyMode m_verify_mode = VerifyMode::none; + + enum class BlockingOperation { + read, + write, + }; + util::Optional m_last_operation; + + // Details of the underlying I/O error that lead to errSecIO being returned + // from a SecureTransport function. + std::error_code m_last_error; + + // The number of bytes accepted by SSWrite() but not yet confirmed to be + // written to the underlying socket. + std::size_t m_num_partially_written_bytes = 0; + + template + std::size_t ssl_perform(Oper oper, std::error_code& ec, Want& want) noexcept; + + std::pair do_ssl_handshake() noexcept; + std::pair do_ssl_shutdown() noexcept; + std::pair do_ssl_read(char* buffer, std::size_t size) noexcept; + std::pair do_ssl_write(const char* data, std::size_t size) noexcept; + + static OSStatus tcp_read(SSLConnectionRef, void*, std::size_t* length) noexcept; + static OSStatus tcp_write(SSLConnectionRef, const void*, std::size_t* length) noexcept; + + OSStatus tcp_read(void*, std::size_t* length) noexcept; + OSStatus tcp_write(const void*, std::size_t* length) noexcept; + + OSStatus verify_peer() noexcept; +#endif + + friend class Service::BasicStreamOps; + friend class network::ReadAheadBuffer; +}; + + +// Implementation + +class ProtocolNotSupported : public std::exception { +public: + const char* what() const noexcept override final; +}; + +inline Context::Context() +{ + ssl_init(); // Throws +} + +inline Context::~Context() noexcept +{ + ssl_destroy(); +} + +inline void Context::use_certificate_chain_file(const std::string& path) +{ + std::error_code ec; + ssl_use_certificate_chain_file(path, ec); // Throws + if (ec) + throw std::system_error(ec); +} + +inline void Context::use_private_key_file(const std::string& path) +{ + std::error_code ec; + ssl_use_private_key_file(path, ec); // Throws + if (ec) + throw std::system_error(ec); +} + +inline void Context::use_default_verify() +{ + std::error_code ec; + ssl_use_default_verify(ec); + if (ec) + throw std::system_error(ec); +} + +inline void Context::use_verify_file(const std::string& path) +{ + std::error_code ec; + ssl_use_verify_file(path, ec); + if (ec) { + throw std::system_error(ec); + } +} + +class Stream::HandshakeOperBase : public Service::IoOper { +public: + HandshakeOperBase(std::size_t size, Stream& stream) + : IoOper{size} + , m_stream{&stream} + { + } + Want initiate() + { + REALM_ASSERT(this == m_stream->m_tcp_socket.m_read_oper.get()); + REALM_ASSERT(!is_complete()); + m_stream->m_tcp_socket.m_desc.ensure_nonblocking_mode(); // Throws + return advance(); + } + Want advance() noexcept override final + { + REALM_ASSERT(!is_complete()); + REALM_ASSERT(!is_canceled()); + REALM_ASSERT(!m_error_code); + Want want = Want::nothing; + m_stream->ssl_handshake(m_error_code, want); + set_is_complete(want == Want::nothing); + return want; + } + void recycle() noexcept override final + { + bool orphaned = !m_stream; + REALM_ASSERT(orphaned); + // Note: do_recycle() commits suicide. + do_recycle(orphaned); + } + void orphan() noexcept override final + { + m_stream = nullptr; + } + Service::Descriptor& descriptor() noexcept override final + { + return m_stream->lowest_layer().m_desc; + } + +protected: + Stream* m_stream; + std::error_code m_error_code; +}; + +template +class Stream::HandshakeOper : public HandshakeOperBase { +public: + HandshakeOper(std::size_t size, Stream& stream, H handler) + : HandshakeOperBase{size, stream} + , m_handler{std::move(handler)} + { + } + void recycle_and_execute() override final + { + REALM_ASSERT(is_complete() || is_canceled()); + bool orphaned = !m_stream; + std::error_code ec = m_error_code; + if (is_canceled()) + ec = error::operation_aborted; + // Note: do_recycle_and_execute() commits suicide. + do_recycle_and_execute(orphaned, m_handler, ec); // Throws + } + +private: + H m_handler; +}; + +class Stream::ShutdownOperBase : public Service::IoOper { +public: + ShutdownOperBase(std::size_t size, Stream& stream) + : IoOper{size} + , m_stream{&stream} + { + } + Want initiate() + { + REALM_ASSERT(this == m_stream->m_tcp_socket.m_write_oper.get()); + REALM_ASSERT(!is_complete()); + m_stream->m_tcp_socket.m_desc.ensure_nonblocking_mode(); // Throws + return advance(); + } + Want advance() noexcept override final + { + REALM_ASSERT(!is_complete()); + REALM_ASSERT(!is_canceled()); + REALM_ASSERT(!m_error_code); + Want want = Want::nothing; + m_stream->ssl_shutdown(m_error_code, want); + if (want == Want::nothing) + set_is_complete(true); + return want; + } + void recycle() noexcept override final + { + bool orphaned = !m_stream; + REALM_ASSERT(orphaned); + // Note: do_recycle() commits suicide. + do_recycle(orphaned); + } + void orphan() noexcept override final + { + m_stream = nullptr; + } + Service::Descriptor& descriptor() noexcept override final + { + return m_stream->lowest_layer().m_desc; + } + +protected: + Stream* m_stream; + std::error_code m_error_code; +}; + +template +class Stream::ShutdownOper : public ShutdownOperBase { +public: + ShutdownOper(std::size_t size, Stream& stream, H handler) + : ShutdownOperBase{size, stream} + , m_handler{std::move(handler)} + { + } + void recycle_and_execute() override final + { + REALM_ASSERT(is_complete() || is_canceled()); + bool orphaned = !m_stream; + std::error_code ec = m_error_code; + if (is_canceled()) + ec = error::operation_aborted; + // Note: do_recycle_and_execute() commits suicide. + do_recycle_and_execute(orphaned, m_handler, ec); // Throws + } + +private: + H m_handler; +}; + +inline Stream::Stream(Socket& socket, Context& context, HandshakeType type) + : m_tcp_socket{socket} + , m_ssl_context{context} + , m_handshake_type{type} +{ + ssl_init(); // Throws +} + +inline Stream::~Stream() noexcept +{ + m_tcp_socket.cancel(); + ssl_destroy(); +} + +inline void Stream::set_logger(util::Logger* logger) +{ + this->logger = logger; +} + +inline void Stream::set_verify_mode(VerifyMode mode) +{ + std::error_code ec; + ssl_set_verify_mode(mode, ec); // Throws + if (ec) + throw std::system_error(ec); +} + +inline void Stream::set_host_name(std::string host_name) +{ + m_host_name = std::move(host_name); + std::error_code ec; + ssl_set_host_name(m_host_name, ec); + if (ec) + throw std::system_error(ec); +} + +inline void Stream::set_server_port(port_type server_port) +{ + m_server_port = server_port; +} + +inline void Stream::use_verify_callback(const std::function& callback) +{ + std::error_code ec; + ssl_use_verify_callback(callback, ec); // Throws + if (ec) + throw std::system_error(ec); +} + +#ifdef REALM_INCLUDE_CERTS +inline void Stream::use_included_certificates() +{ + std::error_code ec; + ssl_use_included_certificates(ec); // Throws + if (ec) + throw std::system_error(ec); +} +#endif + +inline void Stream::handshake() +{ + std::error_code ec; + if (handshake(ec)) // Throws + throw std::system_error(ec); +} + +inline std::size_t Stream::read(char* buffer, std::size_t size) +{ + std::error_code ec; + read(buffer, size, ec); // Throws + if (ec) + throw std::system_error(ec); + return size; +} + +inline std::size_t Stream::read(char* buffer, std::size_t size, std::error_code& ec) +{ + return StreamOps::read(*this, buffer, size, ec); // Throws +} + +inline std::size_t Stream::read(char* buffer, std::size_t size, ReadAheadBuffer& rab) +{ + std::error_code ec; + read(buffer, size, rab, ec); // Throws + if (ec) + throw std::system_error(ec); + return size; +} + +inline std::size_t Stream::read(char* buffer, std::size_t size, ReadAheadBuffer& rab, std::error_code& ec) +{ + int delim = std::char_traits::eof(); + return StreamOps::buffered_read(*this, buffer, size, delim, rab, ec); // Throws +} + +inline std::size_t Stream::read_until(char* buffer, std::size_t size, char delim, ReadAheadBuffer& rab) +{ + std::error_code ec; + std::size_t n = read_until(buffer, size, delim, rab, ec); // Throws + if (ec) + throw std::system_error(ec); + return n; +} + +inline std::size_t Stream::read_until(char* buffer, std::size_t size, char delim, ReadAheadBuffer& rab, + std::error_code& ec) +{ + int delim_2 = std::char_traits::to_int_type(delim); + return StreamOps::buffered_read(*this, buffer, size, delim_2, rab, ec); // Throws +} + +inline std::size_t Stream::write(const char* data, std::size_t size) +{ + std::error_code ec; + write(data, size, ec); // Throws + if (ec) + throw std::system_error(ec); + return size; +} + +inline std::size_t Stream::write(const char* data, std::size_t size, std::error_code& ec) +{ + return StreamOps::write(*this, data, size, ec); // Throws +} + +inline std::size_t Stream::read_some(char* buffer, std::size_t size) +{ + std::error_code ec; + std::size_t n = read_some(buffer, size, ec); // Throws + if (ec) + throw std::system_error(ec); + return n; +} + +inline std::size_t Stream::read_some(char* buffer, std::size_t size, std::error_code& ec) +{ + return StreamOps::read_some(*this, buffer, size, ec); // Throws +} + +inline std::size_t Stream::write_some(const char* data, std::size_t size) +{ + std::error_code ec; + std::size_t n = write_some(data, size, ec); // Throws + if (ec) + throw std::system_error(ec); + return n; +} + +inline std::size_t Stream::write_some(const char* data, std::size_t size, std::error_code& ec) +{ + return StreamOps::write_some(*this, data, size, ec); // Throws +} + +inline void Stream::shutdown() +{ + std::error_code ec; + if (shutdown(ec)) // Throws + throw std::system_error(ec); +} + +template +inline void Stream::async_handshake(H handler) +{ + LendersHandshakeOperPtr op = Service::alloc>(m_tcp_socket.m_read_oper, *this, + std::move(handler)); // Throws + m_tcp_socket.m_desc.initiate_oper(std::move(op)); // Throws +} + +template +inline void Stream::async_read(char* buffer, std::size_t size, H handler) +{ + bool is_read_some = false; + StreamOps::async_read(*this, buffer, size, is_read_some, std::move(handler)); // Throws +} + +template +inline void Stream::async_read(char* buffer, std::size_t size, ReadAheadBuffer& rab, H handler) +{ + int delim = std::char_traits::eof(); + StreamOps::async_buffered_read(*this, buffer, size, delim, rab, std::move(handler)); // Throws +} + +template +inline void Stream::async_read_until(char* buffer, std::size_t size, char delim, ReadAheadBuffer& rab, H handler) +{ + int delim_2 = std::char_traits::to_int_type(delim); + StreamOps::async_buffered_read(*this, buffer, size, delim_2, rab, std::move(handler)); // Throws +} + +template +inline void Stream::async_write(const char* data, std::size_t size, H handler) +{ + bool is_write_some = false; + StreamOps::async_write(*this, data, size, is_write_some, std::move(handler)); // Throws +} + +template +inline void Stream::async_read_some(char* buffer, std::size_t size, H handler) +{ + bool is_read_some = true; + StreamOps::async_read(*this, buffer, size, is_read_some, std::move(handler)); // Throws +} + +template +inline void Stream::async_write_some(const char* data, std::size_t size, H handler) +{ + bool is_write_some = true; + StreamOps::async_write(*this, data, size, is_write_some, std::move(handler)); // Throws +} + +template +inline void Stream::async_shutdown(H handler) +{ + LendersShutdownOperPtr op = Service::alloc>(m_tcp_socket.m_write_oper, *this, + std::move(handler)); // Throws + m_tcp_socket.m_desc.initiate_oper(std::move(op)); // Throws +} + +inline void Stream::do_init_read_async(std::error_code&, Want& want) noexcept +{ + want = Want::nothing; // Proceed immediately unless there is an error +} + +inline void Stream::do_init_write_async(std::error_code&, Want& want) noexcept +{ + want = Want::nothing; // Proceed immediately unless there is an error +} + +inline std::size_t Stream::do_read_some_sync(char* buffer, std::size_t size, std::error_code& ec) noexcept +{ + Want want = Want::nothing; + std::size_t n = do_read_some_async(buffer, size, ec, want); + if (n == 0 && want != Want::nothing) + ec = error::resource_unavailable_try_again; + return n; +} + +inline std::size_t Stream::do_write_some_sync(const char* data, std::size_t size, std::error_code& ec) noexcept +{ + Want want = Want::nothing; + std::size_t n = do_write_some_async(data, size, ec, want); + if (n == 0 && want != Want::nothing) + ec = error::resource_unavailable_try_again; + return n; +} + +inline std::size_t Stream::do_read_some_async(char* buffer, std::size_t size, std::error_code& ec, + Want& want) noexcept +{ + return ssl_read(buffer, size, ec, want); +} + +inline std::size_t Stream::do_write_some_async(const char* data, std::size_t size, std::error_code& ec, + Want& want) noexcept +{ + return ssl_write(data, size, ec, want); +} + +inline Socket& Stream::lowest_layer() noexcept +{ + return m_tcp_socket; +} + + +#if REALM_HAVE_OPENSSL + +inline void Stream::ssl_handshake(std::error_code& ec, Want& want) noexcept +{ + auto perform = [this]() noexcept { + switch (m_handshake_type) { + case client: + return do_ssl_connect(); + case server: + return do_ssl_accept(); + } + REALM_ASSERT(false); + return 0; + }; + std::size_t n = ssl_perform(std::move(perform), ec, want); + REALM_ASSERT(n == 0 || n == 1); + if (want == Want::nothing && n == 0 && !ec) { + // End of input on TCP socket + ec = MiscExtErrors::premature_end_of_input; + } +} + +inline std::size_t Stream::ssl_read(char* buffer, std::size_t size, std::error_code& ec, Want& want) noexcept +{ + auto perform = [this, buffer, size]() noexcept { + return do_ssl_read(buffer, size); + }; + std::size_t n = ssl_perform(std::move(perform), ec, want); + if (want == Want::nothing && n == 0 && !ec) { + // End of input on TCP socket + if (SSL_get_shutdown(m_ssl) & SSL_RECEIVED_SHUTDOWN) { + ec = MiscExtErrors::end_of_input; + } + else { + ec = MiscExtErrors::premature_end_of_input; + } + } + return n; +} + +inline std::size_t Stream::ssl_write(const char* data, std::size_t size, std::error_code& ec, Want& want) noexcept +{ + // While OpenSSL is able to continue writing after we have received the + // close notify alert fro the remote peer, Apple's Secure Transport API is + // not, so to achieve common behaviour, we make sure that any such attempt + // will result in an `error::broken_pipe` error. + if ((SSL_get_shutdown(m_ssl) & SSL_RECEIVED_SHUTDOWN) != 0) { + ec = error::broken_pipe; + want = Want::nothing; + return 0; + } + auto perform = [this, data, size]() noexcept { + return do_ssl_write(data, size); + }; + std::size_t n = ssl_perform(std::move(perform), ec, want); + if (want == Want::nothing && n == 0 && !ec) { + // End of input on TCP socket + ec = MiscExtErrors::premature_end_of_input; + } + return n; +} + +inline bool Stream::ssl_shutdown(std::error_code& ec, Want& want) noexcept +{ + auto perform = [this]() noexcept { + return do_ssl_shutdown(); + }; + std::size_t n = ssl_perform(std::move(perform), ec, want); + REALM_ASSERT(n == 0 || n == 1); + if (want == Want::nothing && n == 0 && !ec) { + // The first invocation of SSL_shutdown() does not signal completion + // until the shutdown alert has been sent to the peer, or an error + // occurred (does not wait for acknowledgment). + // + // The second invocation (after a completed first invocation) does not + // signal completion until the peers shutdown alert has been received, + // or an error occurred. + // + // It is believed that: + // + // If this is the first time SSL_shutdown() is called, and + // `SSL_get_shutdown() & SSL_SENT_SHUTDOWN` evaluates to nonzero, then a + // zero return value means "partial success" (shutdown alert was sent, + // but the peers shutdown alert was not yet received), and 1 means "full + // success" (peers shutdown alert has already been received). + // + // If this is the first time SSL_shutdown() is called, and + // `SSL_get_shutdown() & SSL_SENT_SHUTDOWN` valuates to zero, then a + // zero return value means "premature end of input", and 1 is supposedly + // not a possibility. + // + // If this is the second time SSL_shutdown() is called (after the first + // call has returned zero), then a zero return value means "premature + // end of input", and 1 means "full success" (peers shutdown alert has + // now been received). + if ((SSL_get_shutdown(m_ssl) & SSL_SENT_SHUTDOWN) == 0) + ec = MiscExtErrors::premature_end_of_input; + } + return (n > 0); +} + +// Provides a homogeneous, and mostly quirks-free interface across the OpenSSL +// operations (handshake, read, write, shutdown). +// +// First of all, if the operation remains incomplete (neither successfully +// completed, nor failed), ssl_perform() will set `ec` to `std::system_error()`, +// `want` to something other than `Want::nothing`, and return zero. Note that +// read and write operations are partial in the sense that they do not need to +// read or write everything before completing successfully. They only need to +// read or write at least one byte to complete successfully. +// +// Such a situation will normally only happen when the underlying TCP socket is +// in nonblocking mode, and the read/write requirements of the operation could +// not be immediately accommodated. However, as is noted in the SSL_write() man +// page, it can also happen in blocking mode (at least while writing). +// +// If an error occurred, ssl_perform() will set `ec` to something other than +// `std::system_error()`, `want` to `Want::nothing`, and return 0. +// +// If no error occurred, and the operation completed (`!ec && want == +// Want::nothing`), then the return value indicates the outcome of the +// operation. +// +// In general, a nonzero value means "full" success, and a zero value means +// "partial" success, however, a zero result can also generally mean "premature +// end of input" / "unclean protocol termination". +// +// Assuming there is no premature end of input, then for reads and writes, the +// returned value is the number of transferred bytes. Zero for read on end of +// input. Never zero for write. For handshake it is always 1. For shutdown it is +// 1 if the peer shutdown alert was already received, otherwise it is zero. +// +// ssl_read() should use `SSL_get_shutdown() & SSL_RECEIVED_SHUTDOWN` to +// distinguish between the two possible meanings of zero. +// +// ssl_shutdown() should use `SSL_get_shutdown() & SSL_SENT_SHUTDOWN` to +// distinguish between the two possible meanings of zero. +template +std::size_t Stream::ssl_perform(Oper oper, std::error_code& ec, Want& want) noexcept +{ + ERR_clear_error(); + m_bio_error_code = std::error_code(); // Success + int ret = oper(); + int ssl_error = SSL_get_error(m_ssl, ret); + int sys_error = int(ERR_get_error()); + + // Guaranteed by the documentation of SSL_get_error() + REALM_ASSERT((ret > 0) == (ssl_error == SSL_ERROR_NONE)); + + REALM_ASSERT(!m_bio_error_code || ssl_error == SSL_ERROR_SYSCALL); + + // Judging from various comments in the man pages, and from experience with + // the API, it seems that, + // + // ret=0, ssl_error=SSL_ERROR_SYSCALL, sys_error=0 + // + // is supposed to be an indicator of "premature end of input" / "unclean + // protocol termination", while + // + // ret=0, ssl_error=SSL_ERROR_ZERO_RETURN + // + // is supposed to be an indicator of the following success conditions: + // + // - Mature end of input / clean protocol termination. + // + // - Successful transmission of the shutdown alert, but no prior reception + // of shutdown alert from peer. + // + // Unfortunately, as is also remarked in various places in the man pages, + // those two success conditions may actually result in `ret=0, + // ssl_error=SSL_ERROR_SYSCALL, sys_error=0` too, and it seems that they + // almost always do. + // + // This means that we cannot properly discriminate between these conditions + // in ssl_perform(), and will have to defer to the caller to interpret the + // situation. Since thay cannot be properly told apart, we report all + // `ret=0, ssl_error=SSL_ERROR_SYSCALL, sys_error=0` and `ret=0, + // ssl_error=SSL_ERROR_ZERO_RETURN` cases as the latter. + switch (ssl_error) { + case SSL_ERROR_NONE: + ec = std::error_code(); // Success + want = Want::nothing; + return std::size_t(ret); // ret > 0 + case SSL_ERROR_ZERO_RETURN: + ec = std::error_code(); // Success + want = Want::nothing; + return 0; + case SSL_ERROR_WANT_READ: + ec = std::error_code(); // Success + want = Want::read; + return 0; + case SSL_ERROR_WANT_WRITE: + ec = std::error_code(); // Success + want = Want::write; + return 0; + case SSL_ERROR_SYSCALL: + if (REALM_UNLIKELY(sys_error != 0)) { + ec = make_basic_system_error_code(sys_error); + } + else if (REALM_UNLIKELY(m_bio_error_code)) { + ec = m_bio_error_code; + } + else if (ret == 0) { + // ret = 0, ssl_eror = SSL_ERROR_SYSCALL, sys_error = 0 + // + // See remarks above! + ec = std::error_code(); // Success + } + else { + // ret = -1, ssl_eror = SSL_ERROR_SYSCALL, sys_error = 0 + // + // This situation arises in OpenSSL version >= 1.1. + // It has been observed in the SSL_connect call if the + // other endpoint terminates the connection during + // SSL_connect. The OpenSSL documentation states + // that ret = -1 implies an underlying BIO error and + // that errno should be consulted. However, + // errno = 0(Undefined error) in the observed case. + // At the moment. we will report + // MiscExtErrors::premature_end_of_input. + // If we see this error case occurring in other situations in + // the future, we will have to update this case. + ec = MiscExtErrors::premature_end_of_input; + } + want = Want::nothing; + return 0; + case SSL_ERROR_SSL: + ec = std::error_code(sys_error, openssl_error_category); + want = Want::nothing; + return 0; + default: + break; + } + // We are not supposed to ever get here + REALM_ASSERT(false); + return 0; +} + +inline int Stream::do_ssl_accept() noexcept +{ + int ret = SSL_accept(m_ssl); + return ret; +} + +inline int Stream::do_ssl_connect() noexcept +{ + int ret = SSL_connect(m_ssl); + return ret; +} + +inline int Stream::do_ssl_read(char* buffer, std::size_t size) noexcept +{ + int size_2 = int(size); + if (size > unsigned(std::numeric_limits::max())) + size_2 = std::size_t(std::numeric_limits::max()); + int ret = SSL_read(m_ssl, buffer, size_2); + return ret; +} + +inline int Stream::do_ssl_write(const char* data, std::size_t size) noexcept +{ + int size_2 = int(size); + if (size > unsigned(std::numeric_limits::max())) + size_2 = std::size_t(std::numeric_limits::max()); + int ret = SSL_write(m_ssl, data, size_2); + return ret; +} + +inline int Stream::do_ssl_shutdown() noexcept +{ + int ret = SSL_shutdown(m_ssl); + return ret; +} + +#elif REALM_HAVE_SECURE_TRANSPORT + +// Provides a homogeneous, and mostly quirks-free interface across the SecureTransport +// operations (handshake, read, write, shutdown). +// +// First of all, if the operation remains incomplete (neither successfully +// completed, nor failed), ssl_perform() will set `ec` to `std::system_error()`, +// `want` to something other than `Want::nothing`, and return zero. +// +// If an error occurred, ssl_perform() will set `ec` to something other than +// `std::system_error()`, `want` to `Want::nothing`, and return 0. +// +// If no error occurred, and the operation completed (`!ec && want == +// Want::nothing`), then the return value indicates the outcome of the +// operation. +// +// In general, a nonzero value means "full" success, and a zero value means +// "partial" success, however, a zero result can also generally mean "premature +// end of input" / "unclean protocol termination". +// +// Assuming there is no premature end of input, then for reads and writes, the +// returned value is the number of transferred bytes. Zero for read on end of +// input. Never zero for write. For handshake it is always 1. For shutdown it is +// 1 if the peer shutdown alert was already received, otherwise it is zero. +template +std::size_t Stream::ssl_perform(Oper oper, std::error_code& ec, Want& want) noexcept +{ + OSStatus result; + std::size_t n; + std::tie(result, n) = oper(); + + if (result == noErr) { + ec = std::error_code(); + want = Want::nothing; + return n; + } + + if (result == errSSLWouldBlock) { + REALM_ASSERT(m_last_operation); + ec = std::error_code(); + want = m_last_operation == BlockingOperation::read ? Want::read : Want::write; + m_last_operation = {}; + return n; + } + + if (result == errSSLClosedGraceful) { + ec = MiscExtErrors::end_of_input; + want = Want::nothing; + return n; + } + + if (result == errSSLClosedAbort || result == errSSLClosedNoNotify) { + ec = MiscExtErrors::premature_end_of_input; + want = Want::nothing; + return n; + } + + if (result == errSecIO) { + // A generic I/O error means something went wrong at a lower level. Use the error + // code we smuggled out of our lower-level functions to provide a more specific error. + REALM_ASSERT(m_last_error); + ec = m_last_error; + want = Want::nothing; + return n; + } + + ec = std::error_code(result, secure_transport_error_category); + want = Want::nothing; + return 0; +} +#endif // REALM_HAVE_OPENSSL / REALM_HAVE_SECURE_TRANSPORT + +} // namespace ssl +} // namespace network +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_NETWORK_SSL_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/optional.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/optional.hpp new file mode 100644 index 0000000..dafdb86 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/optional.hpp @@ -0,0 +1,736 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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. + * + **************************************************************************/ + +#pragma once +#ifndef REALM_UTIL_OPTIONAL_HPP +#define REALM_UTIL_OPTIONAL_HPP + +#include +#include + +#include // std::logic_error +#include // std::less + +namespace realm { +namespace util { + +template +class Optional; + +// some() should be the equivalent of the proposed C++17 `make_optional`. +template +Optional some(Args&&...); +template +struct Some; + +// Note: Should conform with the future std::nullopt_t and std::in_place_t. +struct None { + constexpr explicit None(int) + { + } +}; +static constexpr None none{0}; +struct InPlace { + constexpr InPlace() + { + } +}; +static constexpr InPlace in_place; + +// Note: Should conform with the future std::bad_optional_access. +struct BadOptionalAccess : ExceptionWithBacktrace { + using ExceptionWithBacktrace::ExceptionWithBacktrace; +}; + +} // namespace util + +namespace _impl { + +template ::value> +struct OptionalStorage; + +template +struct TypeIsAssignableToOptional { + // Constraints from [optional.object.assign.18] + static const bool value = (std::is_same::type, T>::value && + std::is_constructible::value && std::is_assignable::value); +}; + +} // namespace _impl + +namespace util { + +// Note: Should conform with the future std::optional. +template +class Optional : private realm::_impl::OptionalStorage { +public: + using value_type = T; + + constexpr Optional(); + constexpr Optional(None); + Optional(Optional&& other) noexcept; + Optional(const Optional& other); + + constexpr Optional(T&& value); + constexpr Optional(const T& value); + + template + constexpr Optional(InPlace tag, Args&&...); + // FIXME: std::optional specifies an std::initializer_list constructor overload as well. + + Optional& operator=(None) noexcept; + Optional& operator=(Optional&& other) noexcept(std::is_nothrow_move_assignable::value); + Optional& operator=(const Optional& other) noexcept(std::is_nothrow_copy_assignable::value); + + template ::value>::type> + Optional& operator=(U&& value); + + explicit constexpr operator bool() const; + constexpr const T& value() const; // Throws + T& value(); // Throws, FIXME: Can be constexpr with C++14 + constexpr const T& operator*() const; // Throws + T& operator*(); // Throws, FIXME: Can be constexpr with C++14 + constexpr const T* operator->() const; // Throws + T* operator->(); // Throws, FIXME: Can be constexpr with C++14 + + template + constexpr T value_or(U&& value) const &; + + template + T value_or(U&& value) &&; + + void swap(Optional& other); // FIXME: Add noexcept() clause + + template + void emplace(Args&&...); + // FIXME: std::optional specifies an std::initializer_list overload for `emplace` as well. + + void reset(); + +private: + using Storage = realm::_impl::OptionalStorage; + using Storage::m_engaged; + using Storage::m_value; + + constexpr bool is_engaged() const + { + return m_engaged; + } + void set_engaged(bool b) + { + m_engaged = b; + } +}; + + +/// An Optional is functionally equivalent to a bool. +/// Note: C++17 does not (yet) specify this specialization, but it is convenient +/// as a "safer bool", especially in the presence of `fmap`. +/// Disabled for compliance with std::optional. +// template <> +// class Optional { +// public: +// Optional() {} +// Optional(None) {} +// Optional(Optional&&) = default; +// Optional(const Optional&) = default; +// explicit operator bool() const { return m_engaged; } +// private: +// bool m_engaged = false; +// friend struct Some; +// }; + +/// An Optional is a non-owning nullable pointer that throws on dereference. +// FIXME: Visual Studio 2015's constexpr support isn't sufficient to allow Optional to compile +// in constexpr contexts. +template +class Optional { +public: + using value_type = T&; + using target_type = typename std::decay::type; + + constexpr Optional() + { + } + constexpr Optional(None) + { + } // FIXME: Was a delegating constructor, but not fully supported in VS2015 + Optional(const Optional& other) = default; + template + Optional(const Optional& other) noexcept + : m_ptr(other.m_ptr) + { + } + template + Optional(std::reference_wrapper ref) noexcept + : m_ptr(&ref.get()) + { + } + + constexpr Optional(T& init_value) noexcept + : m_ptr(&init_value) + { + } + Optional(T&& value) = delete; // Catches accidental references to rvalue temporaries. + + Optional& operator=(None) noexcept + { + m_ptr = nullptr; + return *this; + } + Optional& operator=(const Optional& other) + { + m_ptr = other.m_ptr; + return *this; + } + + template + Optional& operator=(std::reference_wrapper ref) noexcept + { + m_ptr = &ref.get(); + return *this; + } + + explicit constexpr operator bool() const noexcept + { + return m_ptr; + } + constexpr const target_type& value() const; // Throws + target_type& value(); // Throws + constexpr const target_type& operator*() const + { + return value(); + } + target_type& operator*() + { + return value(); + } + constexpr const target_type* operator->() const + { + return &value(); + } + target_type* operator->() + { + return &value(); + } + + void swap(Optional other); // FIXME: Add noexcept() clause +private: + T* m_ptr = nullptr; + + template + friend class Optional; +}; + + +template +struct RemoveOptional { + using type = T; +}; +template +struct RemoveOptional> { + using type = typename RemoveOptional::type; // Remove recursively +}; + + +/// Implementation: + +template +struct Some { + template + static Optional some(Args&&... args) + { + return Optional{std::forward(args)...}; + } +}; + +/// Disabled for compliance with std::optional. +// template <> +// struct Some { +// static Optional some() +// { +// Optional opt; +// opt.m_engaged = true; +// return opt; +// } +// }; + +template +Optional some(Args&&... args) +{ + return Some::some(std::forward(args)...); +} + + +template +constexpr Optional::Optional() + : Storage(none) +{ +} + +template +constexpr Optional::Optional(None) + : Storage(none) +{ +} + +template +Optional::Optional(Optional&& other) noexcept + : Storage(none) +{ + if (other.m_engaged) { + new (&m_value) T(std::move(other.m_value)); + m_engaged = true; + } +} + +template +Optional::Optional(const Optional& other) + : Storage(none) +{ + if (other.m_engaged) { + new (&m_value) T(other.m_value); + m_engaged = true; + } +} + +template +constexpr Optional::Optional(T&& r_value) + : Storage(std::move(r_value)) +{ +} + +template +constexpr Optional::Optional(const T& l_value) + : Storage(l_value) +{ +} + +template +template +constexpr Optional::Optional(InPlace, Args&&... args) + : Storage(std::forward(args)...) +{ +} + +template +void Optional::reset() +{ + if (m_engaged) { + m_value.~T(); + m_engaged = false; + } +} + +template +Optional& Optional::operator=(None) noexcept +{ + reset(); + return *this; +} + +template +Optional& Optional::operator=(Optional&& other) noexcept(std::is_nothrow_move_assignable::value) +{ + if (m_engaged) { + if (other.m_engaged) { + m_value = std::move(other.m_value); + } + else { + reset(); + } + } + else { + if (other.m_engaged) { + new (&m_value) T(std::move(other.m_value)); + m_engaged = true; + } + } + return *this; +} + +template +Optional& Optional::operator=(const Optional& other) noexcept(std::is_nothrow_copy_assignable::value) +{ + if (m_engaged) { + if (other.m_engaged) { + m_value = other.m_value; + } + else { + reset(); + } + } + else { + if (other.m_engaged) { + new (&m_value) T(other.m_value); + m_engaged = true; + } + } + return *this; +} + +template +template +Optional& Optional::operator=(U&& r_value) +{ + if (m_engaged) { + m_value = std::forward(r_value); + } + else { + new (&m_value) T(std::forward(r_value)); + m_engaged = true; + } + return *this; +} + +template +constexpr Optional::operator bool() const +{ + return m_engaged; +} + +template +constexpr const T& Optional::value() const +{ + return m_value; +} + +template +T& Optional::value() +{ + REALM_ASSERT(m_engaged); + return m_value; +} + +template +constexpr const typename Optional::target_type& Optional::value() const +{ + return *m_ptr; +} + +template +typename Optional::target_type& Optional::value() +{ + REALM_ASSERT(m_ptr); + return *m_ptr; +} + +template +constexpr const T& Optional::operator*() const +{ + return value(); +} + +template +T& Optional::operator*() +{ + return value(); +} + +template +constexpr const T* Optional::operator->() const +{ + return &value(); +} + +template +T* Optional::operator->() +{ + return &value(); +} + +template +template +constexpr T Optional::value_or(U&& otherwise) const & +{ + return m_engaged ? T{m_value} : T{std::forward(otherwise)}; +} + +template +template +T Optional::value_or(U&& otherwise) && +{ + if (is_engaged()) { + return T(std::move(m_value)); + } + else { + return T(std::forward(otherwise)); + } +} + +template +void Optional::swap(Optional& other) +{ + // FIXME: This might be optimizable. + Optional tmp = std::move(other); + other = std::move(*this); + *this = std::move(tmp); +} + +template +template +void Optional::emplace(Args&&... args) +{ + reset(); + new (&m_value) T(std::forward(args)...); + m_engaged = true; +} + + +template +constexpr Optional::type> make_optional(T&& value) +{ + using Type = typename std::decay::type; + return some(std::forward(value)); +} + +template +bool operator==(const Optional& lhs, const Optional& rhs) +{ + if (!lhs && !rhs) { + return true; + } + if (lhs && rhs) { + return *lhs == *rhs; + } + return false; +} + +template +bool operator!=(const Optional& lhs, const Optional& rhs) +{ + return !(lhs == rhs); +} + +template +bool operator<(const Optional& lhs, const Optional& rhs) +{ + if (!rhs) { + return false; + } + if (!lhs) { + return true; + } + return std::less{}(*lhs, *rhs); +} + +template +bool operator>(const util::Optional& lhs, const util::Optional& rhs) +{ + if (!lhs) { + return false; + } + if (!rhs) { + return true; + } + return std::greater{}(*lhs, *rhs); +} + +template +bool operator==(const Optional& lhs, None) +{ + return !bool(lhs); +} + +template +bool operator!=(const Optional& lhs, None) +{ + return bool(lhs); +} + +template +bool operator<(const Optional& lhs, None) +{ + static_cast(lhs); + return false; +} + +template +bool operator==(None, const Optional& rhs) +{ + return !bool(rhs); +} + +template +bool operator!=(None, const Optional& rhs) +{ + return bool(rhs); +} + +template +bool operator<(None, const Optional& rhs) +{ + return bool(rhs); +} + +template +bool operator==(const Optional& lhs, const U& rhs) +{ + return lhs ? *lhs == rhs : false; +} + +template +bool operator<(const Optional& lhs, const T& rhs) +{ + return lhs ? std::less{}(*lhs, rhs) : true; +} + +template +bool operator==(const T& lhs, const Optional& rhs) +{ + return rhs ? lhs == *rhs : false; +} + +template +bool operator<(const T& lhs, const Optional& rhs) +{ + return rhs ? std::less{}(lhs, *rhs) : false; +} + +template +auto operator>>(Optional lhs, F&& rhs) -> decltype(fmap(lhs, std::forward(rhs))) +{ + return fmap(lhs, std::forward(rhs)); +} + +template +OS& operator<<(OS& os, const Optional& rhs) +{ + if (rhs) { + os << "some(" << *rhs << ")"; + } + else { + os << "none"; + } + return os; +} + +template +T unwrap(T&& value) +{ + return value; +} + +template +T unwrap(util::Optional&& value) +{ + return *value; +} + +template +T unwrap(const util::Optional& value) +{ + return *value; +} + +template +T unwrap(util::Optional& value) +{ + return *value; +} + +} // namespace util + +namespace _impl { + +// T is trivially destructible. +template +struct OptionalStorage { + union { + T m_value; + char m_null_state; + }; + bool m_engaged = false; + + constexpr OptionalStorage(realm::util::None) + : m_null_state() + { + } + constexpr OptionalStorage(T&& value) + : m_value(std::move(value)) + , m_engaged(true) + { + } + + template + constexpr OptionalStorage(Args&&... args) + : m_value(args...) + , m_engaged(true) + { + } +}; + +// T is not trivially destructible. +template +struct OptionalStorage { + union { + T m_value; + char m_null_state; + }; + bool m_engaged = false; + + constexpr OptionalStorage(realm::util::None) + : m_null_state() + { + } + constexpr OptionalStorage(T&& value) + : m_value(std::move(value)) + , m_engaged(true) + { + } + + template + constexpr OptionalStorage(Args&&... args) + : m_value(args...) + , m_engaged(true) + { + } + + ~OptionalStorage() + { + if (m_engaged) + m_value.~T(); + } +}; + +} // namespace _impl + +using util::none; + +} // namespace realm + + +// for convienence, inject a default hash implementation into the std namespace +namespace std +{ + template + struct hash> + { + std::size_t operator()(realm::util::Optional const& o) const noexcept + { + if (bool(o) == false) { + return 0; // any choice will collide with some std::hash + } else { + return std::hash{}(*o); + } + } + }; +} + + +#endif // REALM_UTIL_OPTIONAL_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/overload.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/overload.hpp new file mode 100644 index 0000000..49188ae --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/overload.hpp @@ -0,0 +1,70 @@ +/************************************************************************* + * + * Copyright 2017 Realm Inc. + * + * 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 REALM_UTIL_OVERLOAD_HPP +#define REALM_UTIL_OVERLOAD_HPP + +#include + +namespace realm { + +namespace _impl { + +template +struct Overloaded; + +} // namespace _impl + + +namespace util { + +// Declare an overload set using lambdas or other function objects. +// A minimal version of C++ Library Evolution Working Group proposal P0051R2. + +template +_impl::Overloaded overload(Fns&&... f) +{ + return _impl::Overloaded(std::forward(f)...); +} + +} // namespace util + + +namespace _impl { + +template +struct Overloaded : Fn, Overloaded { + template + Overloaded(U&& fn, Rest&&... rest) : Fn(std::forward(fn)), Overloaded(std::forward(rest)...) { } + + using Fn::operator(); + using Overloaded::operator(); +}; + +template +struct Overloaded : Fn { + template + Overloaded(U&& fn) : Fn(std::forward(fn)) { } + + using Fn::operator(); +}; + +} // namespace _impl +} // namespace realm + +#endif // REALM_UTIL_OVERLOAD_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/overloaded.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/overloaded.hpp new file mode 100644 index 0000000..6eaeff3 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/overloaded.hpp @@ -0,0 +1,16 @@ +#ifndef REALM_UTIL_OVERLOADED_HPP +#define REALM_UTIL_OVERLOADED_HPP + +namespace realm::util { + +// FIXME: Move this utility into Core. +template +struct overloaded : Fs... { + using Fs::operator()...; +}; +template +overloaded(Fs...)->overloaded; + +} // namespace realm::util + +#endif // REALM_UTIL_OVERLOADED_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/parent_dir.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/parent_dir.hpp new file mode 100644 index 0000000..e8bb994 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/parent_dir.hpp @@ -0,0 +1,18 @@ +#ifndef REALM_UTIL_PARENT_DIR_HPP +#define REALM_UTIL_PARENT_DIR_HPP + +#include + +namespace realm { +namespace util { + +/// Same effect as std::filesystem::path::parent_path(). +/// +/// FIXME: This function ought to be moved to in the +/// realm-core repository. +std::string parent_dir(const std::string& path); + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_PARENT_DIR_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/platform_info.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/platform_info.hpp new file mode 100644 index 0000000..58c7f52 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/platform_info.hpp @@ -0,0 +1,43 @@ +#ifndef REALM_UTIL_PLATFORM_INFO_HPP +#define REALM_UTIL_PLATFORM_INFO_HPP + +#include + + +namespace realm { +namespace util { + +/// Get a description of the current system platform. +/// +/// Returns a space-separated concatenation of `osname`, `sysname`, `release`, +/// `version`, and `machine` as returned by get_platform_info(PlatformInfo&). +std::string get_platform_info(); + + +struct PlatformInfo { + std::string osname; ///< Equivalent to `uname -o` (Linux). + std::string sysname; ///< Equivalent to `uname -s`. + std::string release; ///< Equivalent to `uname -r`. + std::string version; ///< Equivalent to `uname -v`. + std::string machine; ///< Equivalent to `uname -m`. +}; + +/// Get a description of the current system platform. +void get_platform_info(PlatformInfo&); + + +// Implementation + +inline std::string get_platform_info() +{ + PlatformInfo info; + get_platform_info(info); // Throws + return (info.osname + " " + info.sysname + " " + info.release + " " + info.version + " " + + info.machine); // Throws +} + + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_PLATFORM_INFO_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/priority_queue.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/priority_queue.hpp new file mode 100644 index 0000000..a2a28c8 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/priority_queue.hpp @@ -0,0 +1,304 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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. + * + **************************************************************************/ + + +#pragma once +#ifndef REALM_UTIL_PRIORITY_QUEUE_HPP +#define REALM_UTIL_PRIORITY_QUEUE_HPP + +#include +#include +#include + +namespace realm { +namespace util { + + +/// PriorityQueue corresponds exactly to `std::priority_queue`, but has the extra feature +/// of allowing iteration and erasure of elements in the queue. +/// +/// PriorityQueue only allows const access to its elements, because non-const access +/// would open up the risk of changing the ordering of the elements. +/// +/// Note: As opposed to `std::priority_queue`, this does not store elements in a heap +/// internally. Instead, elements are stored in sorted order. Users of this class are +/// allowed to operate on this assumption. +template , class Compare = std::less> +class PriorityQueue : private Compare { +public: + using container_type = Container; + using value_type = typename Container::value_type; + using size_type = typename Container::size_type; + using reference = typename Container::reference; + using const_reference = typename Container::const_reference; + using const_reverse_iterator = typename Container::const_reverse_iterator; + using const_iterator = typename Container::const_iterator; + + //@{ + /// Construct a PriorityQueue, optionally providing a comparator object. + PriorityQueue(const Compare& comparator, const Container& cont); + + explicit PriorityQueue(const Compare& comparator = Compare{}, Container&& cont = Container{}); + + template + PriorityQueue(InputIt first, InputIt last, const Compare& comparator, const Container& cont); + + template + PriorityQueue(InputIt first, InputIt last, const Compare& comparator = Compare{}, Container&& cont = Container{}); + //@} + // Skipping Allocator-specific template constructors. + + PriorityQueue(const PriorityQueue&) = default; + PriorityQueue(PriorityQueue&&) = default; + PriorityQueue& operator=(const PriorityQueue&) = default; + PriorityQueue& operator=(PriorityQueue&&) = default; + + bool empty() const; + size_type size() const; + + //@{ + /// Push an element to the priority queue. + /// + /// If insertion to the underlying `Container` invalidates + /// iterators and references, any iterators and references into this + /// priority queue are also invalidated. By default, this is the case. + void push(const T& value); + void push(T&& value); + //@} + + /// Pop the largest element from the priority queue. + /// + /// If `pop_back` on the underlying `Container` invalidates + /// iterators and references, any iterators and reference into this + /// priority queue are also invalidated. By default, this is *NOT* the case. + /// + /// Calling `pop()` on an empty priority queue is undefined. + void pop(); + + /// Return a reference to the largest element of the priority queue. + /// + /// Calling `top()` on an empty priority queue is undefined. + const_reference top() const; + + /// Pop the top of the queue and return it by moving it out of the queue. + /// + /// Note: This method does not exist in `std::priority_queue`. + /// + /// Calling `pop_top()` on an empty priorty queue is undefined. + value_type pop_top(); + + // FIXME: emplace() deliberately omitted for simplicity. + + /// Swap the contents of this priority queue with the contents of \a other. + void swap(PriorityQueue& other); + + // Not in std::priority_queue: + + /// Return an iterator to the beginning of the queue (smallest element first). + const_iterator begin() const; + + /// Return an iterator to the end of the queue (largest element last); + const_iterator end() const; + + /// Return a reverse iterator into the priority queue (largest element first). + const_reverse_iterator rbegin() const; + + /// Return a reverse iterator representing the end of the priority queue (smallest element last). + const_reverse_iterator rend() const; + + /// Erase element pointed to by \a it. + /// + /// Note: This function differs from `std::priority_queue` by returning the erased + /// element using move semantics. + /// + /// Calling `erase()` with a beyond-end iterator (such as what is returned by `end()`) + /// is undefined. + value_type erase(const_iterator it); + + /// Remove all elements from the priority queue. + void clear(); + + /// Calls `reserve()` on the underlying `Container`. + void reserve(size_type); + +private: + Container m_queue; + + const Compare& compare() const; + Compare& compare(); +}; + + +/// Implementation + +template +PriorityQueue::PriorityQueue(const Compare& comparator, const Container& cont) + : Compare(comparator) + , m_queue(cont) +{ +} + +template +PriorityQueue::PriorityQueue(const Compare& comparator, Container&& cont) + : Compare(comparator) + , m_queue(std::move(cont)) +{ +} + +template +template +PriorityQueue::PriorityQueue(InputIt first, InputIt last, const Compare& comparator, + const Container& cont) + : Compare(comparator) + , m_queue(cont) +{ + for (auto it = first; it != last; ++it) { + push(*it); + } +} + +template +template +PriorityQueue::PriorityQueue(InputIt first, InputIt last, const Compare& comparator, + Container&& cont) + : Compare(comparator) + , m_queue(std::move(cont)) +{ + for (auto it = first; it != last; ++it) { + push(*it); + } +} + +template +typename PriorityQueue::size_type PriorityQueue::size() const +{ + return m_queue.size(); +} + +template +bool PriorityQueue::empty() const +{ + return m_queue.empty(); +} + +template +void PriorityQueue::push(const T& element) +{ + auto it = std::lower_bound(m_queue.begin(), m_queue.end(), element, compare()); + m_queue.insert(it, element); +} + +template +void PriorityQueue::push(T&& element) +{ + auto it = std::lower_bound(m_queue.begin(), m_queue.end(), element, compare()); + m_queue.insert(it, std::move(element)); +} + +template +void PriorityQueue::pop() +{ + m_queue.pop_back(); +} + +template +typename PriorityQueue::const_reference PriorityQueue::top() const +{ + return m_queue.back(); +} + +template +typename PriorityQueue::value_type PriorityQueue::pop_top() +{ + value_type value = std::move(m_queue.back()); + m_queue.pop_back(); + return value; +} + +template +Compare& PriorityQueue::compare() +{ + return *this; +} + +template +const Compare& PriorityQueue::compare() const +{ + return *this; +} + +template +typename PriorityQueue::const_iterator PriorityQueue::begin() const +{ + return m_queue.begin(); +} + +template +typename PriorityQueue::const_iterator PriorityQueue::end() const +{ + return m_queue.end(); +} + +template +typename PriorityQueue::const_reverse_iterator +PriorityQueue::rbegin() const +{ + return m_queue.rbegin(); +} + +template +typename PriorityQueue::const_reverse_iterator +PriorityQueue::rend() const +{ + return m_queue.rend(); +} + +template +typename PriorityQueue::value_type +PriorityQueue::erase(const_iterator it) +{ + // Convert to non-const iterator: + auto non_const_iterator = m_queue.begin() + (it - m_queue.begin()); + value_type value = std::move(*non_const_iterator); + m_queue.erase(non_const_iterator); + return value; +} + +template +void PriorityQueue::clear() +{ + m_queue.clear(); +} + +template +void PriorityQueue::reserve(size_type sz) +{ + m_queue.reserve(sz); +} + +template +void PriorityQueue::swap(PriorityQueue& other) +{ + using std::swap; + swap(m_queue, other.m_queue); + swap(compare(), other.compare()); +} +} +} + +#endif // REALM_UTIL_PRIORITY_QUEUE_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/quote.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/quote.hpp new file mode 100644 index 0000000..26a7739 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/quote.hpp @@ -0,0 +1,158 @@ +#ifndef REALM_UTIL_QUOTE_HPP +#define REALM_UTIL_QUOTE_HPP + +#include + +namespace realm { +namespace util { + +template +struct Quote { + bool smart; + util::BasicStringView view; +}; + + +/// Mark text for quotation during output to stream. +/// +/// If `out` is an output stream, and `str` is a string (e.g., an std::string), +/// then +/// +/// out << quoted(str) +/// +/// will write `str` in quoted form to `out`. +/// +/// Quotation involves bracketing the text in double quotes (`"`), and escaping +/// special characters according to the rules of C/C++ string literals. In this +/// case, the special characters are `"` and `\` as well as those that are not +/// printable (!std::isprint()). +/// +/// Quotation happens as the string is written to a stream, so there is no +/// intermediate representation of the quoted string. +template +Quote quoted(util::BasicStringView) noexcept; + + +/// Same as quoted(), except that in this case, quotation is elided when the +/// specified string consists of a single printable word. Or, to be more +/// precise, quotation is elided if the string is nonempty, consists entirely of +/// printable charcters (std::isprint()), does not contain space (` `), and does +/// not conatian quotation (`"`) or backslash (`\`). +template +Quote smart_quoted(util::BasicStringView) noexcept; + + +template +std::basic_ostream& operator<<(std::basic_ostream&, Quote); + + +// Implementation + +template +inline Quote quoted(util::BasicStringView view) noexcept +{ + bool smart = false; + return {smart, view}; +} + +template +inline Quote smart_quoted(util::BasicStringView view) noexcept +{ + bool smart = true; + return {smart, view}; +} + +template +inline std::basic_ostream& operator<<(std::basic_ostream& out, Quote quoted) +{ + std::locale loc = out.getloc(); + const std::ctype& ctype = std::use_facet>(loc); + C dquote = ctype.widen('"'); + C bslash = ctype.widen('\\'); + util::BasicStringView view = quoted.view; + if (quoted.smart && !view.empty()) { + for (C ch : view) { + if (ch == dquote || ch == bslash || !ctype.is(ctype.graph, ch)) + goto quote; + } + return out << view; // Throws + } +quote: + typename std::basic_ostream::sentry sentry{out}; + if (REALM_LIKELY(sentry)) { + out.put(dquote); // Throws + bool follows_hex = false; + for (C ch : view) { + if (REALM_LIKELY(ctype.is(ctype.print, ch))) { + if (REALM_LIKELY(!follows_hex || !ctype.is(ctype.xdigit, ch))) { + if (REALM_LIKELY(ch != dquote && ch != bslash)) + goto put_char; + goto escape_char; + } + } + { + char ch_2 = ctype.narrow(ch, '\0'); + switch (ch_2) { + case '\a': + ch = ctype.widen('a'); + goto escape_char; + case '\b': + ch = ctype.widen('b'); + goto escape_char; + case '\f': + ch = ctype.widen('f'); + goto escape_char; + case '\n': + ch = ctype.widen('n'); + goto escape_char; + case '\r': + ch = ctype.widen('r'); + goto escape_char; + case '\t': + ch = ctype.widen('t'); + goto escape_char; + case '\v': + ch = ctype.widen('v'); + goto escape_char; + } + } + goto numeric; + escape_char: + out.put(bslash); // Throws + put_char: + out.put(ch); // Throws + next: + follows_hex = false; + continue; + numeric: + out.put(bslash); // Throws + using D = typename std::make_unsigned::type; + char digits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + D val = ch; + if (val < 512) { + out.put(ctype.widen(digits[val / 64])); // Throws + out.put(ctype.widen(digits[val % 64 / 8])); // Throws + out.put(ctype.widen(digits[val % 8])); // Throws + goto next; + } + out.put(ctype.widen('x')); // Throws + const int max_hex_digits = (std::numeric_limits::digits + 3) / 4; + C buffer[max_hex_digits]; + int i = max_hex_digits; + while (val != 0) { + buffer[--i] = ctype.widen(digits[val % 16]); + val /= 16; + } + out.write(buffer + i, max_hex_digits - i); // Throws + follows_hex = true; + } + out.put(dquote); // Throws + } + return out; +} + + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_QUOTE_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/random.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/random.hpp new file mode 100644 index 0000000..541252e --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/random.hpp @@ -0,0 +1,116 @@ + +#ifndef REALM_UTIL_RANDOM_HPP +#define REALM_UTIL_RANDOM_HPP + +#include +#include +#include +#include +#include +#include + +namespace realm { +namespace util { + +/// Perform a nondeterministc seeding of the specified pseudo random number +/// generator. +/// +/// \tparam Engine A type that satisfies UniformRandomBitGenerator as defined by +/// the C++ standard. +/// +/// \tparam state_size The number of words of type Engine::result_type that make +/// up the engine state. +/// +/// Thread-safe. +/// +/// FIXME: Move this to core repo, as it is generally useful. +template +void seed_prng_nondeterministically(Engine&); + +template +std::string generate_random_lower_case_string(Engine& engine, size_t size); + + +// Implementation + +} // namespace util + +namespace _impl { + +void get_extra_seed_entropy(unsigned int& extra_entropy_1, unsigned int& extra_entropy_2, + unsigned int& extra_entropy_3); + +} // namespace _impl + +namespace util { + +template +void seed_prng_nondeterministically(Engine& engine) +{ + // This implementation was informed and inspired by + // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0205r0.html. + // + // The number of bits of entropy needed is `state_size * + // std::numeric_limits::digits` (assuming that + // the engine uses all available bits in each word). + // + // Each invocation of `std::random_device::operator()` gives us + // `std::numeric_limits::digits` bits (assuming maximum + // entropy). Note that `std::random_device::result_type` must be `unsigned + // int`, `std::random_device::min()` must return zero, and + // `std::random_device::max()` must return `std::numeric_limits::max()`. + // + // Ideally, we could have used `std::random_device::entropy()` as the actual + // number of bits of entropy produced per invocation of + // `std::random_device::operator()`, however, it is incorrectly implemented + // on many platform. Also, it is supposed to return zero when + // `std::random_device` is just a PRNG, but that would leave us with no way + // to continue. + // + // When the actual entropy from `std::random_device` is less than maximum, + // the seeding will be less than optimal. For example, if the actual entropy + // is only half of the maximum, then the seeding will only produce half the + // entrpy that it ought to, but that will generally still be a good seeding. + // + // For the (assumed) rare cases where `std::random_device` is a PRGN that is + // not nondeterministically seeded, we include a bit of extra entropy taken + // from such places as the current time and the ID of the executing process + // (when available). + + constexpr long seed_bits_needed = state_size * long(std::numeric_limits::digits); + constexpr int seed_bits_per_device_invocation = std::numeric_limits::digits; + constexpr size_t seed_words_needed = size_t((seed_bits_needed + (seed_bits_per_device_invocation - 1)) / + seed_bits_per_device_invocation); // Rounding up + constexpr int num_extra = 3; + std::array seed_values; + std::random_device rnddev; + std::generate(seed_values.begin(), seed_values.end() - num_extra, std::ref(rnddev)); + + unsigned int extra_entropy[3]; + _impl::get_extra_seed_entropy(extra_entropy[0], extra_entropy[1], extra_entropy[2]); + static_assert(num_extra == sizeof extra_entropy / sizeof extra_entropy[0], "Mismatch"); + std::copy(extra_entropy, extra_entropy + num_extra, seed_values.end() - num_extra); + + std::seed_seq seed_seq(seed_values.begin(), seed_values.end()); + engine.seed(seed_seq); +} + +template +std::string generate_random_lower_case_string(Engine& engine, size_t size) +{ + std::uniform_int_distribution dist(0, 25); + std::string str; + str.reserve(size); + for (size_t i = 0; i < size; ++i) { + short val = dist(engine); + char c = 'a' + char(val); + str.push_back(c); + } + return str; +} + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_RANDOM_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/resource_limits.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/resource_limits.hpp new file mode 100644 index 0000000..07c5c4b --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/resource_limits.hpp @@ -0,0 +1,64 @@ +#ifndef REALM_UTIL_RESOURCE_LIMITS_HPP +#define REALM_UTIL_RESOURCE_LIMITS_HPP + +namespace realm { +namespace util { + + +enum class Resource { + /// The maximum size, in bytes, of the core file produced when the memory + /// image of this process is dumped. If the memory image is larger than the + /// limit, the core file will not be created. Same as `RLIMIT_CORE` of + /// POSIX. + core_dump_size, + + /// The maximum CPU time, in seconds, available to this process. If the + /// limit is exceeded, the process will be killed. Same as `RLIMIT_CPU` of + /// POSIX. + cpu_time, + + /// The maximum size, in bytes, of the data segment of this process. If the + /// limit is exceede, std::malloc() will fail with `errno` equal to + /// `ENOMEM`. Same as `RLIMIT_DATA` of POSIX. + data_segment_size, + + /// The maximum size, in bytes, of a file that is modified by this + /// process. If the limit is exceede, the process will be killed. Same as + /// `RLIMIT_FSIZE` of POSIX. + file_size, + + /// One plus the maximum file descriptor value that can be opened by this + /// process. Same as `RLIMIT_NOFILE` of POSIX. + num_open_files, + + /// The maximum size, in bytes, of the stack of the main thread of this + /// process. If the limit is exceede, the process is killed. Same as + /// `RLIMIT_STACK` of POSIX. + stack_size, + + /// The maximum size, in bytes, of the process's virtual memory (address + /// space). If the limit is exceeded due to heap allocation, std::malloc() + /// will fail with `errno` equal to `ENOMEM`. If the limit is exceeded due + /// to explicit memory mapping, mmap() will fail with `errno` equal to + /// `ENOMEM`. If the limit is exceeded due to stack expansion, the process + /// will be killed. Same as `RLIMIT_AS` of POSIX. + virtual_memory_size +}; + + +bool system_has_rlimit(Resource) noexcept; + + +//@{ +/// Get or set resouce limits. A negative value means 'unlimited', both when +/// getting and when setting. +long get_hard_rlimit(Resource); +long get_soft_rlimit(Resource); +void set_soft_rlimit(Resource, long value); +//@} + + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_RESOURCE_LIMITS_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/safe_int_ops.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/safe_int_ops.hpp new file mode 100644 index 0000000..eb906c6 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/safe_int_ops.hpp @@ -0,0 +1,334 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_UTIL_SAFE_INT_OPS_HPP +#define REALM_UTIL_SAFE_INT_OPS_HPP + +#ifdef _WIN32 +#undef max // collides with numeric_limits::max called later in this header file +#undef min // collides with numeric_limits::min called later in this header file +#include +#endif + +#include + +#include +#include +#include + +namespace realm { +namespace util { + +//@{ + +/// Compare two integers of the same, or of different type, and +/// produce the expected result according to the natural +/// interpretation of the operation. +/// +/// Note that in general a standard comparison between a signed and an +/// unsigned integer type is unsafe, and it often generates a compiler +/// warning. An example is a 'less than' comparison between a negative +/// value of type 'int' and a small positive value of type +/// 'unsigned'. In this case the negative value will be converted to +/// 'unsigned' producing a large positive value which, in turn, will +/// lead to the counter intuitive result of 'false'. +/// +/// Please note that these operation incur absolutely no overhead when +/// the two types have the same signedness. +/// +/// These functions check at compile time that both types have valid +/// specializations of std::numeric_limits<> and that both are indeed +/// integers. + +template +inline bool int_equal_to(A, B) noexcept; +template +inline bool int_not_equal_to(A, B) noexcept; +template +inline bool int_less_than(A, B) noexcept; +template +inline bool int_less_than_or_equal(A, B) noexcept; +template +inline bool int_greater_than(A, B) noexcept; +template +inline bool int_greater_than_or_equal(A, B) noexcept; + +//@} + + +//@{ + +/// Check for overflow in integer variable `lval` while adding integer +/// `rval` to it, or while subtracting integer `rval` from it. Returns +/// true on positive or negative overflow. +/// +/// Both `lval` and `rval` must be of an integer type for which a +/// specialization of std::numeric_limits<> exists. The two types need +/// not be the same, in particular, one can be signed and the other +/// one can be unsigned. +/// +/// These functions are especially well suited for cases where \a rval +/// is a compile-time constant. +/// +/// These functions check at compile time that both types have valid +/// specializations of std::numeric_limits<> and that both are indeed +/// integers. + +template +inline bool int_add_with_overflow_detect(L& lval, R rval) noexcept; + +template +inline bool int_subtract_with_overflow_detect(L& lval, R rval) noexcept; + +//@} + + +/// Check for positive overflow when multiplying two positive integers +/// of the same, or of different type. Returns true on overflow. +/// +/// \param lval Must not be negative. Both signed and unsigned types +/// can be used. +/// +/// \param rval Must be stricly greater than zero. Both signed and +/// unsigned types can be used. +/// +/// This function is especially well suited for cases where \a rval is +/// a compile-time constant. +/// +/// This function checks at compile time that both types have valid +/// specializations of std::numeric_limits<> and that both are indeed +/// integers. +template +inline bool int_multiply_with_overflow_detect(L& lval, R rval) noexcept; + + +/// Checks for positive overflow when performing a bitwise shift to +/// the left on a non-negative value of arbitrary integer +/// type. Returns true on overflow. +/// +/// \param lval Must not be negative. Both signed and unsigned types +/// can be used. +/// +/// \param i Must be non-negative and such that L(1)>>i has a +/// value that is defined by the C++03 standard. In particular, the +/// value of i must not exceed the number of bits of storage type T as +/// shifting by this amount is not defined by the standard. +template +inline bool int_shift_left_with_overflow_detect(T& lval, int i) noexcept; + + +//@{ + +/// Check for overflow when casting an integer value from one type to +/// another. While the first function is a mere check, the second one +/// also carries out the cast, but only when there is no +/// overflow. Both return true on overflow. +/// +/// These functions check at compile time that both types have valid +/// specializations of std::numeric_limits<> and that both are indeed +/// integers. +/// +/// These functions make absolutely no assumptions about the platform +/// except that it complies with at least C++03. + +template +bool int_cast_has_overflow(From from) noexcept; + +template +bool int_cast_with_overflow_detect(From from, To& to) noexcept; + +//@} + +} // namespace util + +namespace _impl { + +template +struct SafeIntBinopsImpl; + +// (both signed or both unsigned) +template +struct SafeIntBinopsImpl == std::is_signed_v>> { + using common = std::common_type_t; + static bool equal(L l, R r) noexcept + { + return common(l) == common(r); + } + static bool less(L l, R r) noexcept + { + return common(l) < common(r); + } +}; + +// (unsigned, signed) +template +struct SafeIntBinopsImpl && std::is_signed_v>> { + using lim_l = std::numeric_limits; + using lim_r = std::numeric_limits; + static bool equal(L l, R r) noexcept + { + return (lim_l::digits > lim_r::digits) ? r >= 0 && l == L(r) : R(l) == r; + } + static bool less(L l, R r) noexcept + { + return (lim_l::digits > lim_r::digits) ? r >= 0 && l < L(r) : R(l) < r; + } +}; + +// (signed, unsigned) (all size combinations) +template +struct SafeIntBinopsImpl && !std::is_signed_v>> { + static bool equal(L l, R r) noexcept + { + // r == l + return SafeIntBinopsImpl::equal(r, l); + } + static bool less(L l, R r) noexcept + { + // !(r == l || r < l) + return !(SafeIntBinopsImpl::equal(r, l) || SafeIntBinopsImpl::less(r, l)); + } +}; + +template +struct SafeIntBinops : SafeIntBinopsImpl { + typedef std::numeric_limits lim_l; + typedef std::numeric_limits lim_r; + static_assert(lim_l::is_specialized && lim_r::is_specialized, + "std::numeric_limits<> must be specialized for both types"); + static_assert(lim_l::is_integer && lim_r::is_integer, "Both types must be integers"); +}; + +} // namespace _impl + +namespace util { + +template +inline bool int_equal_to(A a, B b) noexcept +{ + return realm::_impl::SafeIntBinops::equal(a, b); +} + +template +inline bool int_not_equal_to(A a, B b) noexcept +{ + return !realm::_impl::SafeIntBinops::equal(a, b); +} + +template +inline bool int_less_than(A a, B b) noexcept +{ + return realm::_impl::SafeIntBinops::less(a, b); +} + +template +inline bool int_less_than_or_equal(A a, B b) noexcept +{ + return !realm::_impl::SafeIntBinops::less(b, a); // Not greater than +} + +template +inline bool int_greater_than(A a, B b) noexcept +{ + return realm::_impl::SafeIntBinops::less(b, a); +} + +template +inline bool int_greater_than_or_equal(A a, B b) noexcept +{ + return !realm::_impl::SafeIntBinops::less(a, b); // Not less than +} + +template +inline bool int_add_with_overflow_detect(L& lval, R rval) noexcept +{ + // Note: MSVC returns true on success, while gcc/clang return true on overflow. + // Note: Both may write to destination on overflow, but our tests check that this doesn't happen. + auto old = lval; +#ifdef _MSC_VER + auto overflow = !msl::utilities::SafeAdd(lval, rval, lval); +#else + auto overflow = __builtin_add_overflow(lval, rval, &lval); +#endif + if (REALM_UNLIKELY(overflow)) + lval = old; + return overflow; +} + +template +inline bool int_subtract_with_overflow_detect(L& lval, R rval) noexcept +{ + auto old = lval; +#ifdef _MSC_VER + auto overflow = !msl::utilities::SafeSubtract(lval, rval, lval); +#else + auto overflow = __builtin_sub_overflow(lval, rval, &lval); +#endif + if (REALM_UNLIKELY(overflow)) + lval = old; + return overflow; +} + +template +inline bool int_multiply_with_overflow_detect(L& lval, R rval) noexcept +{ + auto old = lval; +#ifdef _MSC_VER + auto overflow = !msl::utilities::SafeMultiply(lval, rval, lval); +#else + auto overflow = __builtin_mul_overflow(lval, rval, &lval); +#endif + if (REALM_UNLIKELY(overflow)) + lval = old; + return overflow; +} + +template +inline bool int_shift_left_with_overflow_detect(T& lval, int i) noexcept +{ + typedef std::numeric_limits lim; + static_assert(lim::is_specialized, "std::numeric_limits<> must be specialized for T"); + static_assert(lim::is_integer, "T must be an integer type"); + REALM_ASSERT(int_greater_than_or_equal(lval, 0)); + if ((lim::max() >> i) < lval) + return true; + lval <<= i; + return false; +} + +template +inline bool int_cast_has_overflow(From from) noexcept +{ + typedef std::numeric_limits lim_to; + return int_less_than(from, lim_to::min()) || int_less_than(lim_to::max(), from); +} + +template +inline bool int_cast_with_overflow_detect(From from, To& to) noexcept +{ + if (REALM_LIKELY(!int_cast_has_overflow(from))) { + to = To(from); + return false; + } + return true; +} + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_SAFE_INT_OPS_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/scope_exit.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/scope_exit.hpp new file mode 100644 index 0000000..5410d19 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/scope_exit.hpp @@ -0,0 +1,72 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_UTIL_SCOPE_EXIT_HPP +#define REALM_UTIL_SCOPE_EXIT_HPP + +#include +#include + +#include + +namespace realm { +namespace util { + +template +class ScopeExit { +public: + explicit ScopeExit(const H& handler) noexcept(std::is_nothrow_copy_constructible::value) + : m_handler(handler) + { + } + + explicit ScopeExit(H&& handler) noexcept(std::is_nothrow_move_constructible::value) + : m_handler(std::move(handler)) + { + } + + ScopeExit(ScopeExit&& se) noexcept(std::is_nothrow_move_constructible::value) + : m_handler(std::move(se.m_handler)) + { + se.m_handler = none; + } + + ~ScopeExit() noexcept + { + if (m_handler) + (*m_handler)(); + } + + static_assert(noexcept(std::declval()()), "Handler must be nothrow executable"); + static_assert(std::is_nothrow_destructible::value, "Handler must be nothrow destructible"); + +private: + util::Optional m_handler; +}; + +template +ScopeExit::type> make_scope_exit(H&& handler) noexcept( + noexcept(ScopeExit::type>(std::forward(handler)))) +{ + return ScopeExit::type>(std::forward(handler)); +} + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_SCOPE_EXIT_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/serializer.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/serializer.hpp new file mode 100644 index 0000000..255d69b --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/serializer.hpp @@ -0,0 +1,102 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_UTIL_SERIALIZER_HPP +#define REALM_UTIL_SERIALIZER_HPP + +#include +#include + +#include +#include +#include + +namespace realm { + +class BinaryData; +struct ColKey; +struct null; +class ObjectId; +struct ObjKey; +class StringData; +class Timestamp; +class LinkMap; +enum class ExpressionComparisonType : unsigned char; + +namespace util { +namespace serializer { + + +// Definitions +template +std::string print_value(T value); + +template +std::string print_value(Optional value); + +const static std::string value_separator = "."; + +// Specializations declared here to be defined in the cpp file +template <> std::string print_value<>(BinaryData); +template <> std::string print_value<>(bool); +template <> +std::string print_value<>(float); +template <> +std::string print_value<>(double); +template <> std::string print_value<>(realm::null); +template <> std::string print_value<>(StringData); +template <> std::string print_value<>(realm::Timestamp); +template <> +std::string print_value<>(realm::ObjectId); +template <> +std::string print_value<>(realm::ObjKey); + +// General implementation for most types +template +std::string print_value(T value) +{ + std::stringstream ss; + ss << value; + return ss.str(); +} + +template +std::string print_value(Optional value) +{ + if (bool(value)) { + return print_value(*value); + } else { + return "NULL"; + } +} + +struct SerialisationState { + std::string describe_column(ConstTableRef table, ColKey col_key); + std::string describe_columns(const LinkMap& link_map, ColKey target_col_key); + std::string describe_expression_type(ExpressionComparisonType type); + std::string get_column_name(ConstTableRef table, ColKey col_key); + std::string get_backlink_column_name(ConstTableRef from, ColKey col_key); + std::string get_variable_name(ConstTableRef table); + std::vector subquery_prefix_list; +}; + +} // namespace serializer +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_SERIALIZER_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/sha_crypto.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/sha_crypto.hpp new file mode 100644 index 0000000..5cbe9f7 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/sha_crypto.hpp @@ -0,0 +1,43 @@ +/************************************************************************* + * + * Copyright 2019 Realm Inc. + * + * 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 REALM_SHA_CRYPTO_HPP +#define REALM_SHA_CRYPTO_HPP + +#include + +namespace realm { +namespace util { + +/// The digest functions calculate the message digest of the input in \param +/// in_buffer of size \param in_buffer_size . The digest is placed in \param +/// out_buffer . The caller must guarantee that the output buffer is large +/// enough to contain the digest. +/// +/// The functions throw if the underlying platform dependent implementations +/// throw. Typically, exceptions are "out of memory" errors. +/// +/// sha1() calculates the SHA-1 hash value of output size 20. +/// sha256() calculates the SHA-256 hash value of output size 32. +void sha1(const char* in_buffer, size_t in_buffer_size, unsigned char* out_buffer); +void sha256(const char* in_buffer, size_t in_buffer_size, unsigned char* out_buffer); + +} // namespace util +} // namespace realm + +#endif // REALM_SHA_CRYPTO_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/shared_ptr.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/shared_ptr.hpp new file mode 100644 index 0000000..1a34701 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/shared_ptr.hpp @@ -0,0 +1,131 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_SHARED_PTR_HPP +#define REALM_SHARED_PTR_HPP + +#include // size_t + +namespace realm { +namespace util { + +template +class SharedPtr { +public: + SharedPtr(T* p) + { + init(p); + } + + SharedPtr() + { + init(0); + } + + ~SharedPtr() + { + decref(); + } + + SharedPtr(const SharedPtr& o) + : m_ptr(o.m_ptr) + , m_count(o.m_count) + { + incref(); + } + + SharedPtr& operator=(const SharedPtr& o) + { + // if (m_ptr == o.m_ptr) + if (this == &o) + return *this; + decref(); + m_ptr = o.m_ptr; + m_count = o.m_count; + incref(); + return *this; + } + + T* operator->() const + { + return m_ptr; + } + + T& operator*() const + { + return *m_ptr; + } + + T* get() const + { + return m_ptr; + } + + bool operator==(const SharedPtr& o) const + { + return m_ptr == o.m_ptr; + } + + bool operator!=(const SharedPtr& o) const + { + return m_ptr != o.m_ptr; + } + + bool operator<(const SharedPtr& o) const + { + return m_ptr < o.m_ptr; + } + + size_t ref_count() const + { + return *m_count; + } + +private: + void init(T* p) + { + m_ptr = p; + try { + m_count = new size_t(1); + } + catch (...) { + delete p; + throw; + } + } + + void decref() + { + if (--(*m_count) == 0) { + delete m_ptr; + delete m_count; + } + } + + void incref() + { + ++(*m_count); + } + + T* m_ptr; + size_t* m_count; +}; +} +} + +#endif diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/signal_blocker.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/signal_blocker.hpp new file mode 100644 index 0000000..e0555b1 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/signal_blocker.hpp @@ -0,0 +1,59 @@ + +#ifndef REALM_UTIL_SIGNAL_BLOCKER_HPP +#define REALM_UTIL_SIGNAL_BLOCKER_HPP + +#include + +#include + + +namespace realm { +namespace util { + +/// \brief Block all signals from being delivered to the instantiating thread. +/// +/// On platforms that support POSIX signals, the constructor will set the signal +/// mask such that all signals are blocked from being delivered to the calling +/// thread, and the destructor will restore the signal mask to its original +/// value. +/// +/// This scheme assumes that it is always the same thread that constructs and +/// destroys a particular instance of SignalBlocker, and that, for a particular +/// thread, two SignalBlocker objects never overlap in time, and the signal mask +/// is never modified by other means while a SignalBlocker object exists. +class SignalBlocker { +public: + SignalBlocker() noexcept; + ~SignalBlocker() noexcept; + +private: +#ifndef _WIN32 + ::sigset_t m_orig_mask; +#endif +}; + + +// Implementation + +inline SignalBlocker::SignalBlocker() noexcept +{ +#ifndef _WIN32 + ::sigset_t mask; + sigfillset(&mask); + int ret = ::pthread_sigmask(SIG_BLOCK, &mask, &m_orig_mask); + REALM_ASSERT(ret == 0); +#endif +} + +inline SignalBlocker::~SignalBlocker() noexcept +{ +#ifndef _WIN32 + int ret = ::pthread_sigmask(SIG_SETMASK, &m_orig_mask, nullptr); + REALM_ASSERT(ret == 0); +#endif +} + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_SIGNAL_BLOCKER_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/string_buffer.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/string_buffer.hpp new file mode 100644 index 0000000..71736bd --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/string_buffer.hpp @@ -0,0 +1,209 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_UTIL_STRING_BUFFER_HPP +#define REALM_UTIL_STRING_BUFFER_HPP + +#include +#include +#include + +#include +#include + +namespace realm { +namespace util { + + +// FIXME: In C++17, this can be replaced with std::string (since +// std::string::data() can return a mutable pointer in C++17). +template +class BasicStringBuffer { +public: + BasicStringBuffer() noexcept; + + std::string str() const; + + /// Returns the current size of the string in this buffer. This + /// size does not include the terminating zero. + size_t size() const noexcept; + + /// Gives read and write access to the bytes of this buffer. The + /// caller may read and write from *c_str() up to, but not + /// including, *(c_str()+size()). + char* data() noexcept; + + /// Gives read access to the bytes of this buffer. The caller may + /// read from *c_str() up to, but not including, + /// *(c_str()+size()). + const char* data() const noexcept; + + /// Guarantees that the returned string is zero terminated, that + /// is, *(c_str()+size()) is zero. The caller may read from + /// *c_str() up to and including *(c_str()+size()). + const char* c_str() const noexcept; + + void append(const std::string&); + + void append(const char* append_data, size_t append_size); + + /// Append a zero-terminated string to this buffer. + void append_c_str(const char* c_string); + + /// The specified size is understood as not including the + /// terminating zero. If the specified size is less than the + /// current size, then the string is truncated accordingly. If the + /// specified size is greater than the current size, then the + /// extra characters will have undefined values, however, there + /// will be a terminating zero at *(c_str()+size()), and the + /// original terminating zero will also be left in place such that + /// from the point of view of c_str(), the size of the string is + /// unchanged. + void resize(size_t new_size); + + /// The specified minimum capacity is understood as not including + /// the terminating zero. This operation does not change the size + /// of the string in the buffer as returned by size(). If the + /// specified capacity is less than the current capacity, this + /// operation has no effect. + void reserve(size_t min_capacity); + + /// Set size to zero. The capacity remains unchanged. + void clear() noexcept; + +private: + util::Buffer m_buffer; + size_t m_size; // Excluding the terminating zero + void reallocate(size_t min_capacity); +}; + +using StringBuffer = BasicStringBuffer; + + +// Implementation: + +template +BasicStringBuffer::BasicStringBuffer() noexcept + : m_size(0) +{ +} + +template +std::string BasicStringBuffer::str() const +{ + return std::string(m_buffer.data(), m_size); +} + +template +size_t BasicStringBuffer::size() const noexcept +{ + return m_size; +} + +template +char* BasicStringBuffer::data() noexcept +{ + return m_buffer.data(); +} + +template +const char* BasicStringBuffer::data() const noexcept +{ + return m_buffer.data(); +} + +template +const char* BasicStringBuffer::c_str() const noexcept +{ + static const char zero = 0; + const char* d = data(); + return d ? d : &zero; +} + +template +void BasicStringBuffer::append(const std::string& s) +{ + return append(s.data(), s.size()); +} + +template +void BasicStringBuffer::append_c_str(const char* c_string) +{ + append(c_string, std::strlen(c_string)); +} + +template +void BasicStringBuffer::reserve(size_t min_capacity) +{ + size_t capacity = m_buffer.size(); + if (capacity == 0 || capacity - 1 < min_capacity) + reallocate(min_capacity); +} + +template +void BasicStringBuffer::resize(size_t new_size) +{ + reserve(new_size); + // Note that even reserve(0) will attempt to allocate a + // buffer, so we can safely write the truncating zero at this + // time. + m_size = new_size; + m_buffer[new_size] = 0; +} + +template +void BasicStringBuffer::clear() noexcept +{ + if (m_buffer.size() == 0) + return; + m_size = 0; + m_buffer[0] = 0; +} + +template +void BasicStringBuffer::append(const char* append_data, size_t append_data_size) +{ + size_t new_size = m_size; + if (int_add_with_overflow_detect(new_size, append_data_size)) + throw util::BufferSizeOverflow(); + reserve(new_size); // Throws + realm::safe_copy_n(append_data, append_data_size, m_buffer.data() + m_size); + m_size = new_size; + m_buffer[new_size] = 0; // Add zero termination +} + + +template +void BasicStringBuffer::reallocate(size_t min_capacity) +{ + size_t min_capacity_2 = min_capacity; + // Make space for zero termination + if (int_add_with_overflow_detect(min_capacity_2, 1)) + throw util::BufferSizeOverflow(); + size_t new_capacity = m_buffer.size(); + if (int_multiply_with_overflow_detect(new_capacity, 2)) + new_capacity = std::numeric_limits::max(); // LCOV_EXCL_LINE + if (new_capacity < min_capacity_2) + new_capacity = min_capacity_2; + m_buffer.resize(new_capacity, 0, m_size, 0); // Throws +} + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_STRING_BUFFER_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/string_view.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/string_view.hpp new file mode 100644 index 0000000..e4dc113 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/string_view.hpp @@ -0,0 +1,459 @@ +#ifndef REALM_UTIL_STRING_VIEW_HPP +#define REALM_UTIL_STRING_VIEW_HPP + +#include +#include +#include +#include +#include +#include +#include + +#include + + +namespace realm { +namespace util { + +template > +class BasicStringView { +public: + using value_type = C; + using traits_type = T; + using pointer = C*; + using const_pointer = const C*; + using reference = C&; + using const_reference = const C&; + using iterator = const_pointer; + using const_iterator = const_pointer; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + + static constexpr size_type npos = size_type(-1); + + BasicStringView() noexcept; + BasicStringView(const std::basic_string&) noexcept; + BasicStringView(const char* data, size_type size) noexcept; + BasicStringView(const char* c_str) noexcept; + + explicit operator std::basic_string() const; + + const_iterator begin() const noexcept; + const_iterator end() const noexcept; + const_iterator cbegin() const noexcept; + const_iterator cend() const noexcept; + + const_reverse_iterator rbegin() const noexcept; + const_reverse_iterator rend() const noexcept; + const_reverse_iterator crbegin() const noexcept; + const_reverse_iterator crend() const noexcept; + + const_reference operator[](size_type i) const noexcept; + const_reference at(size_type i) const; + const_reference front() const noexcept; + const_reference back() const noexcept; + + const_pointer data() const noexcept; + size_type size() const noexcept; + bool empty() const noexcept; + + BasicStringView substr(size_type i = 0, size_type n = npos) const; + int compare(BasicStringView other) const noexcept; + size_type find(BasicStringView, size_type i = 0) const noexcept; + size_type find(C ch, size_type i = 0) const noexcept; + size_type find_first_of(BasicStringView, size_type i = 0) const noexcept; + size_type find_first_of(C ch, size_type i = 0) const noexcept; + size_type find_first_not_of(BasicStringView, size_type i = 0) const noexcept; + size_type find_first_not_of(C ch, size_type i = 0) const noexcept; + +private: + const char* m_data = nullptr; + std::size_t m_size = 0; +}; + +template +bool operator==(BasicStringView, BasicStringView) noexcept; +template +bool operator!=(BasicStringView, BasicStringView) noexcept; +template +bool operator<(BasicStringView, BasicStringView) noexcept; +template +bool operator>(BasicStringView, BasicStringView) noexcept; +template +bool operator<=(BasicStringView, BasicStringView) noexcept; +template +bool operator>=(BasicStringView, BasicStringView) noexcept; + +template +bool operator==(std::decay_t>, BasicStringView) noexcept; +template +bool operator!=(std::decay_t>, BasicStringView) noexcept; +template +bool operator<(std::decay_t>, BasicStringView) noexcept; +template +bool operator>(std::decay_t>, BasicStringView) noexcept; +template +bool operator<=(std::decay_t>, BasicStringView) noexcept; +template +bool operator>=(std::decay_t>, BasicStringView) noexcept; + +template +bool operator==(BasicStringView, std::decay_t>) noexcept; +template +bool operator!=(BasicStringView, std::decay_t>) noexcept; +template +bool operator<(BasicStringView, std::decay_t>) noexcept; +template +bool operator>(BasicStringView, std::decay_t>) noexcept; +template +bool operator<=(BasicStringView, std::decay_t>) noexcept; +template +bool operator>=(BasicStringView, std::decay_t>) noexcept; + + +template +std::basic_ostream& operator<<(std::basic_ostream&, BasicStringView); + + +using StringView = BasicStringView; + + +// Implementation + +template +inline BasicStringView::BasicStringView() noexcept +{ +} + +template +inline BasicStringView::BasicStringView(const std::basic_string& str) noexcept + : m_data{str.data()} + , m_size{str.size()} +{ +} + +template +inline BasicStringView::BasicStringView(const char* data, size_type size) noexcept + : m_data{data} + , m_size{size} +{ +} + +template +inline BasicStringView::BasicStringView(const char* c_str) noexcept + : m_data{c_str} + , m_size{T::length(c_str)} +{ +} + +template +inline BasicStringView::operator std::basic_string() const +{ + return {m_data, m_size}; // Throws +} + +template +inline auto BasicStringView::begin() const noexcept -> const_iterator +{ + return m_data; +} + +template +inline auto BasicStringView::end() const noexcept -> const_iterator +{ + return m_data + m_size; +} + +template +inline auto BasicStringView::cbegin() const noexcept -> const_iterator +{ + return begin(); +} + +template +inline auto BasicStringView::cend() const noexcept -> const_iterator +{ + return end(); +} + +template +inline auto BasicStringView::rbegin() const noexcept -> const_reverse_iterator +{ + return const_reverse_iterator{end()}; +} + +template +inline auto BasicStringView::rend() const noexcept -> const_reverse_iterator +{ + return const_reverse_iterator{begin()}; +} + +template +inline auto BasicStringView::crbegin() const noexcept -> const_reverse_iterator +{ + return rbegin(); +} + +template +inline auto BasicStringView::crend() const noexcept -> const_reverse_iterator +{ + return rend(); +} + +template +inline auto BasicStringView::operator[](size_type i) const noexcept -> const_reference +{ + return m_data[i]; +} + +template +inline auto BasicStringView::at(size_type i) const -> const_reference +{ + if (REALM_LIKELY(i < m_size)) + return m_data[i]; + throw std::out_of_range("index"); +} + +template +inline auto BasicStringView::front() const noexcept -> const_reference +{ + return m_data[0]; +} + +template +inline auto BasicStringView::back() const noexcept -> const_reference +{ + return m_data[m_size - 1]; +} + +template +inline auto BasicStringView::data() const noexcept -> const_pointer +{ + return m_data; +} + +template +inline auto BasicStringView::size() const noexcept -> size_type +{ + return m_size; +} + +template +inline bool BasicStringView::empty() const noexcept +{ + return (size() == 0); +} + +template +inline BasicStringView BasicStringView::substr(size_type i, size_type n) const +{ + if (REALM_LIKELY(i <= m_size)) { + size_type m = std::min(n, m_size - i); + return BasicStringView{m_data + i, m}; + } + throw std::out_of_range("index"); +} + +template +inline int BasicStringView::compare(BasicStringView other) const noexcept +{ + size_type n = std::min(m_size, other.m_size); + int ret = T::compare(m_data, other.m_data, n); + if (REALM_LIKELY(ret != 0)) + return ret; + if (m_size < other.m_size) + return -1; + if (m_size > other.m_size) + return 1; + return 0; +} + +template +inline auto BasicStringView::find(BasicStringView v, size_type i) const noexcept -> size_type +{ + if (REALM_LIKELY(!v.empty())) { + if (REALM_LIKELY(i < m_size)) { + const C* p = std::search(begin() + i, end(), v.begin(), v.end()); + if (p != end()) + return size_type(p - begin()); + } + return npos; + } + return i; +} + +template +inline auto BasicStringView::find(C ch, size_type i) const noexcept -> size_type +{ + if (REALM_LIKELY(i < m_size)) { + const C* p = std::find(begin() + i, end(), ch); + if (p != end()) + return size_type(p - begin()); + } + return npos; +} + +template +inline auto BasicStringView::find_first_of(BasicStringView v, size_type i) const noexcept -> size_type +{ + for (size_type j = i; j < m_size; ++j) { + if (REALM_LIKELY(v.find(m_data[j]) == npos)) + continue; + return j; + } + return npos; +} + +template +inline auto BasicStringView::find_first_of(C ch, size_type i) const noexcept -> size_type +{ + for (size_type j = i; j < m_size; ++j) { + if (REALM_UNLIKELY(m_data[j] == ch)) + return j; + } + return npos; +} + +template +inline auto BasicStringView::find_first_not_of(BasicStringView v, size_type i) const noexcept -> size_type +{ + for (size_type j = i; j < m_size; ++j) { + if (REALM_UNLIKELY(v.find(m_data[j]) == npos)) + return j; + } + return npos; +} + +template +inline auto BasicStringView::find_first_not_of(C ch, size_type i) const noexcept -> size_type +{ + for (size_type j = i; j < m_size; ++j) { + if (REALM_UNLIKELY(m_data[j] != ch)) + return j; + } + return npos; +} + +template +inline bool operator==(BasicStringView lhs, BasicStringView rhs) noexcept +{ + return (lhs.compare(rhs) == 0); +} + +template +inline bool operator!=(BasicStringView lhs, BasicStringView rhs) noexcept +{ + return (lhs.compare(rhs) != 0); +} + +template +inline bool operator<(BasicStringView lhs, BasicStringView rhs) noexcept +{ + return (lhs.compare(rhs) < 0); +} + +template +inline bool operator>(BasicStringView lhs, BasicStringView rhs) noexcept +{ + return (lhs.compare(rhs) > 0); +} + +template +inline bool operator<=(BasicStringView lhs, BasicStringView rhs) noexcept +{ + return (lhs.compare(rhs) <= 0); +} + +template +inline bool operator>=(BasicStringView lhs, BasicStringView rhs) noexcept +{ + return (lhs.compare(rhs) >= 0); +} + +template +inline bool operator==(std::decay_t> lhs, BasicStringView rhs) noexcept +{ + return (lhs.compare(rhs) == 0); +} + +template +inline bool operator!=(std::decay_t> lhs, BasicStringView rhs) noexcept +{ + return (lhs.compare(rhs) != 0); +} + +template +inline bool operator<(std::decay_t> lhs, BasicStringView rhs) noexcept +{ + return (lhs.compare(rhs) < 0); +} + +template +inline bool operator>(std::decay_t> lhs, BasicStringView rhs) noexcept +{ + return (lhs.compare(rhs) > 0); +} + +template +inline bool operator<=(std::decay_t> lhs, BasicStringView rhs) noexcept +{ + return (lhs.compare(rhs) <= 0); +} + +template +inline bool operator>=(std::decay_t> lhs, BasicStringView rhs) noexcept +{ + return (lhs.compare(rhs) >= 0); +} + +template +inline bool operator==(BasicStringView lhs, std::decay_t> rhs) noexcept +{ + return (lhs.compare(rhs) == 0); +} + +template +inline bool operator!=(BasicStringView lhs, std::decay_t> rhs) noexcept +{ + return (lhs.compare(rhs) != 0); +} + +template +inline bool operator<(BasicStringView lhs, std::decay_t> rhs) noexcept +{ + return (lhs.compare(rhs) < 0); +} + +template +inline bool operator>(BasicStringView lhs, std::decay_t> rhs) noexcept +{ + return (lhs.compare(rhs) > 0); +} + +template +inline bool operator<=(BasicStringView lhs, std::decay_t> rhs) noexcept +{ + return (lhs.compare(rhs) <= 0); +} + +template +inline bool operator>=(BasicStringView lhs, std::decay_t> rhs) noexcept +{ + return (lhs.compare(rhs) >= 0); +} + +template +inline std::basic_ostream& operator<<(std::basic_ostream& out, BasicStringView view) +{ + typename std::basic_ostream::sentry sentry{out}; + if (REALM_LIKELY(sentry)) + out.write(view.data(), view.size()); + return out; +} + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_STRING_VIEW_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/substitute.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/substitute.hpp new file mode 100644 index 0000000..0d31fc1 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/substitute.hpp @@ -0,0 +1,367 @@ +#ifndef REALM_UTIL_SUBSTITUTE_HPP +#define REALM_UTIL_SUBSTITUTE_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +namespace realm { +namespace util { +namespace _private { + +class SubstituterBase { +protected: + template + struct FindArg1; + template + struct FindArg2; + static StderrLogger s_default_logger; +}; + +} // namespace _private + + +struct SubstituterConfig { + /// Allow parsing to be considered successful even when syntax errors are + /// detected. When enabled, logging will happen on `warn`, instead of + /// `error` level. + bool lenient = false; + + /// The logger to be used by default. If left unspecified, the default + /// logger is one that logs to STDERR. In any case, logging happens only + /// during parsing. + Logger* logger = nullptr; +}; + + +/// Perform variable substitutions in text. +/// +/// A variable reference generally has the form `@{}`, where `` is +/// the variable name. For example, if the variable name is `x`, then `@{x}` is +/// a reference to that variable. If the variable name consists of a single +/// letter, then a shorter form of reference, `@` is available, i.e., +/// since `x` is a single letter, `@x` is a reference to `x`. As a special rule, +/// `@@` is substituted by `@`. +/// +/// Example of use: +/// +/// struct CtxA { int y = 0; }; +/// struct CtxB { int x = 0; }; +/// using Subst = Substituter; +/// Subst subst; +/// subst["x"] = &CtxB::x; +/// subst["y"] = [](std::ostream& out, const CtxA& a, const CtxB&) { +/// out << a.y; +/// }; +/// Subst::Template templ; +/// if (subst.parse("<@x:@y>\n", templ)) { +/// CtxA a; +/// CtxB b; +/// for (int i = 0; i < 3; ++i) { +/// templ.expand(std::cout, a, b); +/// a.y += 1; +/// b.x += 2; +/// } +/// } +/// +/// This code should write +/// +/// <0:0> +/// <2:1> +/// <4:2> +/// +/// to STDOUT. +template +class Substituter : private _private::SubstituterBase { +public: + using EvalFunc = void(std::ostream&, A&...); + class ProtoDef; + class Template; + + Substituter(SubstituterConfig = {}) noexcept; + + ProtoDef operator[](const char* name) noexcept; + + bool expand(StringView text, std::ostream&, A&&...) const; + + bool parse(StringView text, Template&) const; + bool parse(StringView text, Template&, Logger&) const; + +private: + using size_type = StringView::size_type; + struct Substitution; + + const bool m_lenient; + Logger& m_logger; + + using Variables = std::map>; + Variables m_variables; + + void define(const char* name, std::function); +}; + + +template +class Substituter::ProtoDef { +public: + template + void operator=(T*); + template + void operator=(T C::*); + void operator=(std::function); + +private: + Substituter& m_substituter; + const char* m_name; + + ProtoDef(Substituter& substituter, const char* name) noexcept; + + friend class Substituter; +}; + + +template +class Substituter::Template { +public: + /// Uses std::locale::classic(). + std::string expand(A&&...) const; + + void expand(std::ostream&, A...) const; + + bool refers_to(const char* name) const noexcept; + +private: + StringView m_text; + std::vector m_substitutions; + + friend class Substituter; +}; + + +// Implementation + +namespace _private { + +template +struct SubstituterBase::FindArg2 { + static const T& find(const A&, const B&... b) noexcept + { + return FindArg1::find(b...); + } +}; + +template +struct SubstituterBase::FindArg2 { + static const T& find(const A& a, const B&...) noexcept + { + return a; + } +}; + +template +struct SubstituterBase::FindArg1 { + static const T& find(const A& a, const B&... b) noexcept + { + using P = typename std::remove_reference::type*; + return FindArg2::value, A, B...>::find(a, b...); + } +}; + +} // namespace _private + +template +struct Substituter::Substitution { + size_type begin, end; + const typename Variables::value_type* var_def; +}; + +template +inline Substituter::Substituter(SubstituterConfig config) noexcept + : m_lenient{config.lenient} + , m_logger{config.logger ? *config.logger : s_default_logger} +{ +} + +template +inline auto Substituter::operator[](const char* name) noexcept -> ProtoDef +{ + return ProtoDef{*this, name}; +} + +template +inline bool Substituter::expand(StringView text, std::ostream& out, A&&... arg) const +{ + Template templ; + if (parse(text, templ)) { // Throws + templ.expand(out, std::forward(arg)...); // Throws + return true; + } + return false; +} + +template +inline bool Substituter::parse(StringView text, Template& templ) const +{ + return parse(text, templ, m_logger); // Throws +} + +template +bool Substituter::parse(StringView text, Template& templ, Logger& logger) const +{ + bool error = false; + Logger::Level log_level = (m_lenient ? Logger::Level::warn : Logger::Level::error); + std::vector substitutions; + StringView var_name; + size_type curr = 0; + size_type end = text.size(); + for (;;) { + size_type i = text.find('@', curr); + if (i == StringView::npos) + break; + if (i + 1 == end) { + logger.log(log_level, "Unterminated `@` at end of text"); // Throws + error = true; + break; + } + char ch = text[i + 1]; + if (ch == '{') { + size_type j = text.find('}', i + 2); + if (j == StringView::npos) { + logger.log(log_level, "Unterminated `@{`"); // Throws + error = true; + curr = i + 2; + continue; + } + var_name = text.substr(i + 2, j - (i + 2)); + curr = j + 1; + } + else { + var_name = text.substr(i + 1, 1); // Throws + curr = i + 2; + } + const typename Variables::value_type* var_def = nullptr; + if (ch != '@') { + auto k = m_variables.find(var_name); + if (k == m_variables.end()) { + logger.log(log_level, "Undefined variable `%1` in substitution `%2`", var_name, + text.substr(i, curr - i)); // Throws + error = true; + continue; + } + var_def = &*k; + } + substitutions.push_back({i, curr, var_def}); // Throws + } + if (error && !m_lenient) + return false; + templ.m_text = text; + templ.m_substitutions = std::move(substitutions); + return true; +} + +template +inline void Substituter::define(const char* name, std::function func) +{ + auto p = m_variables.emplace(name, std::move(func)); // Throws + bool was_inserted = p.second; + if (!was_inserted) + throw std::runtime_error("Multiple definitions for same variable name"); +} + +template +template +inline void Substituter::ProtoDef::operator=(T* var) +{ + *this = [var](std::ostream& out, const A&...) { + out << *var; // Throws + }; +} + +template +template +inline void Substituter::ProtoDef::operator=(T C::*var) +{ + *this = [var](std::ostream& out, const A&... arg) { + const C& obj = FindArg1::find(arg...); + out << obj.*var; // Throws + }; +} + +template +inline void Substituter::ProtoDef::operator=(std::function func) +{ + m_substituter.define(m_name, std::move(func)); // Throws +} + +template +inline Substituter::ProtoDef::ProtoDef(Substituter& substituter, const char* name) noexcept + : m_substituter{substituter} + , m_name{name} +{ +} + +template +std::string Substituter::Template::expand(A&&... arg) const +{ + std::ostringstream out; + out.imbue(std::locale::classic()); + expand(out, std::forward(arg)...); // Throws + std::string str = std::move(out).str(); // Throws + return str; +} + +template +void Substituter::Template::expand(std::ostream& out, A... arg) const +{ + std::ios_base::fmtflags flags = out.flags(); + try { + size_type curr = 0; + for (const Substitution& subst : m_substitutions) { + out << m_text.substr(curr, subst.begin - curr); // Throws + if (subst.var_def) { + const std::function& eval_func = subst.var_def->second; + eval_func(out, arg...); // Throws + out.flags(flags); + } + else { + out << "@"; // Throws + } + curr = subst.end; + } + out << m_text.substr(curr); // Throws + } + catch (...) { + out.flags(flags); + throw; + } +} + +template +inline bool Substituter::Template::refers_to(const char* name) const noexcept +{ + StringView name_2 = name; + for (const auto& subst : m_substitutions) { + if (subst.var_def) { + if (name_2 != subst.var_def->first) + continue; + return true; + } + } + return false; +} + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_SUBSTITUTE_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/system_process.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/system_process.hpp new file mode 100644 index 0000000..8312567 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/system_process.hpp @@ -0,0 +1,181 @@ +#ifndef REALM_UTIL_SYSTEM_PROCESS_HPP +#define REALM_UTIL_SYSTEM_PROCESS_HPP + +#include +#include +#include +#include + +#include + + +namespace realm { +namespace util { +namespace sys_proc { + +using Environment = std::map; + +/// This function is safe to call only when the caller can be sure that there +/// are no threads that modify the environment concurrently. +/// +/// When possible, call this function from the main thread before any other +/// threads are created, such as early in `main()`. +Environment copy_local_environment(); + + +struct ExitInfo { + /// If nonzero, the process was killed by a signal. The value is the + /// signal number. + int killed_by_signal = 0; + + /// Zero if the process was killed by a signal, otherwise this is the value + /// returned by the `main()` function, or passed to `exit()`. + /// + /// On a POSIX system, if an error occurs during ::execve(), that is, after + /// ::fork(), an exit status of 127 will be used (aligned with + /// ::posix_spawn()). + int status = 0; + + /// In some cases, ChildHandle::join() will set `signal_name` when it sets + /// `killed_by_signal` to a non-zero value. In those cases, `signal_name` is + /// set to point to a null-terminated string specifying the name of the + /// signal that killed the child process. + const char* signal_name = nullptr; + + /// Returns true if, and only if both `killed_by_signal` and `status` are + /// zero. + explicit operator bool() const noexcept; +}; + + +struct SpawnConfig { + /// When set to true, the child process will be able to use a + /// ParentDeathGuard to detect the destruction of the SystemProcess object + /// in the parent process, even when this happens implicitly due to abrupt + /// termination of the parent process. + bool parent_death_guard = false; + + /// If a logger is specified here, the child process will be able to + /// instantiate a ParentLogger object, and messages logged through that + /// ParentLogger object will be transported to the parent process and + /// submitted to the logger pointed to by `logger`. The specified logger is + /// guaranteed to only be accessed while ChildHandle::join() is executing, + /// and only by the thread that executes ChildHandle::join(). See + /// ParentLogger for further details. + Logger* logger = nullptr; +}; + + +class ChildHandle { +public: + /// Wait for the child process to exit. + /// + /// If a logger was passed to spawn() (SpawnConfig::logger), then this + /// function will also transport log messages from the child to the parent + /// process while waiting for the child process to exit. See ParentLogger + /// for details. + ExitInfo join(); + + ChildHandle(ChildHandle&&) noexcept; + ~ChildHandle() noexcept; + +private: + class Impl; + std::unique_ptr m_impl; + + ChildHandle(Impl*) noexcept; + + friend ChildHandle spawn(const std::string&, const std::vector&, const Environment&, + const SpawnConfig&); +}; + + +/// Returns true if, and only if the spawn() functions work on this platform. If +/// this function returns false, the spawn() functions will throw. +bool is_spawn_supported() noexcept; + + +//@{ +/// Spawn a child process. +ChildHandle spawn(const std::string& path, const std::vector& args = {}, const Environment& = {}); +ChildHandle spawn(const std::string& path, const std::vector& args, const Environment&, + const SpawnConfig&); +//@} + + +/// Force a child process to terminate immediately if the parent process is +/// terminated, or if the parent process destroys the ChildHandle object +/// representing the child process. +/// +/// If a child process instantiates an object of this type, and keeps it alive, +/// and the child process was spawned with support for detection of parent +/// termination (SpawnConfig::parent_death_guard), then the child process will +/// be killed shortly after the parent destroys its ChildHandle object, even +/// when this happens implicitly due to abrupt termination of the parent +/// process. +/// +/// If a child process instantiates an object of this type, that object must be +/// instantiated by the main thread, and before any other thread is spawned in +/// the child process. +/// +/// In order for the guard to have the intended effect, it must be instantiated +/// immediately in the child process, and be kept alive for as long as the child +/// process is running. +class ParentDeathGuard { +public: + ParentDeathGuard(); + ~ParentDeathGuard() noexcept; + +private: + std::thread m_thread; + int m_stop_pipe_write = -1; +}; + + +/// A logger that can transport log messages from the child to the parent +/// process. +/// +/// If the parent process specifies a logger when spawning a child process +/// (SpawnConfig::logger), then that child process can instantiate a +/// ParentLogger object, and messages logged through it will be transported to +/// the parent process. While the parent process is executing +/// ChildHandle::join(), those messages will be written to the logger specified +/// by the parent process. +/// +/// If a child process instantiates an object of this type, that object must be +/// instantiated by the main thread, and before any other thread is spawned in +/// the child process. +/// +/// At most one ParentLogger object may be instantiated per child process. +/// +/// This logger is **not** thread-safe. +class ParentLogger : public RootLogger { +public: + ParentLogger(); + ~ParentLogger() noexcept; + +protected: + void do_log(Level, std::string) override final; + +private: + int m_pipe_write = -1; +}; + + +// Implementation + +inline ExitInfo::operator bool() const noexcept +{ + return (killed_by_signal == 0 && status == 0); +} + +inline ChildHandle spawn(const std::string& path, const std::vector& args, const Environment& env) +{ + return spawn(path, args, env, SpawnConfig{}); // Throws +} + +} // namespace sys_proc +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_SYSTEM_PROCESS_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/terminate.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/terminate.hpp new file mode 100644 index 0000000..4e6034e --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/terminate.hpp @@ -0,0 +1,59 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_UTIL_TERMINATE_HPP +#define REALM_UTIL_TERMINATE_HPP + +#include + +#include +#include +#include + +#define REALM_TERMINATE(msg) realm::util::terminate((msg), __FILE__, __LINE__) + +namespace realm { +namespace util { + +REALM_NORETURN void terminate(const char* message, const char* file, long line, + std::initializer_list&& = {}) noexcept; +REALM_NORETURN void terminate_with_info(const char* message, const char* file, long line, + const char* interesting_names, + std::initializer_list&& = {}) noexcept; + +// LCOV_EXCL_START +template +REALM_NORETURN void terminate(const char* message, const char* file, long line, Ts... infos) noexcept +{ + static_assert(sizeof...(infos) == 2 || sizeof...(infos) == 4 || sizeof...(infos) == 6, + "Called realm::util::terminate() with wrong number of arguments"); + terminate(message, file, line, {Printable(infos)...}); +} + +template +REALM_NORETURN void terminate_with_info(const char* assert_message, int line, const char* file, + const char* interesting_names, Args&&... interesting_values) noexcept +{ + terminate_with_info(assert_message, file, line, interesting_names, {Printable(interesting_values)...}); +} +// LCOV_EXCL_STOP + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_TERMINATE_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/thread.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/thread.hpp new file mode 100644 index 0000000..52f4384 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/thread.hpp @@ -0,0 +1,815 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_UTIL_THREAD_HPP +#define REALM_UTIL_THREAD_HPP + +#include + +#ifdef _WIN32 +#include +#include // for windows non-interprocess condvars we use std::condition_variable +#include +#include // _getpid() +#else +#include +#endif + +// Use below line to enable a thread bug detection tool. Note: Will make program execution slower. +// #include <../test/pthread_test.hpp> + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +namespace realm { +namespace util { + + +/// A separate thread of execution. +/// +/// This class is a C++03 compatible reproduction of a subset of std::thread +/// from C++11 (when discounting Thread::start(), Thread::set_name(), and +/// Thread::get_name()). +class Thread { +public: + Thread(); + ~Thread() noexcept; + + template + explicit Thread(F func); + + // Disable copying. It is an error to copy this Thread class. + Thread(const Thread&) = delete; + Thread& operator=(const Thread&) = delete; + + Thread(Thread&&) noexcept; + + /// This method is an extension of the API provided by + /// std::thread. This method exists because proper move semantics + /// is unavailable in C++03. If move semantics had been available, + /// calling `start(func)` would have been equivalent to `*this = + /// Thread(func)`. Please see std::thread::operator=() for + /// details. + template + void start(F func); + + bool joinable() noexcept; + + void join(); + + // If supported by the platform, set the name of the calling thread (mainly + // for debugging purposes). The name will be silently clamped to whatever + // limit the platform places on these names. Linux places a limit of 15 + // characters for these names. + static void set_name(const std::string&); + + // If supported by the platform, this function assigns the name of the + // calling thread to \a name, and returns true, otherwise it does nothing + // and returns false. + static bool get_name(std::string& name) noexcept; + +private: + +#ifdef _WIN32 + std::thread m_std_thread; +#else + pthread_t m_id; +#endif + bool m_joinable; + typedef void* (*entry_func_type)(void*); + + void start(entry_func_type, void* arg); + + template + static void* entry_point(void*) noexcept; + + REALM_NORETURN static void create_failed(int); + REALM_NORETURN static void join_failed(int); +}; + + +/// Low-level mutual exclusion device. +class Mutex { +public: + Mutex(); + ~Mutex() noexcept; + + struct process_shared_tag { + }; + /// Initialize this mutex for use across multiple processes. When + /// constructed this way, the instance may be placed in memory + /// shared by multiple processes, as well as in a memory mapped + /// file. Such a mutex remains valid even after the constructing + /// process terminates. Deleting the instance (freeing the memory + /// or deleting the file) without first calling the destructor is + /// legal and will not cause any system resources to be leaked. + Mutex(process_shared_tag); + + // Disable copying. + Mutex(const Mutex&) = delete; + Mutex& operator=(const Mutex&) = delete; + + friend class LockGuard; + friend class UniqueLock; + friend class InterprocessCondVar; + + void lock() noexcept; + bool try_lock() noexcept; + void unlock() noexcept; + +protected: +#ifdef _WIN32 + // Used for non-process-shared mutex. We only know at runtime whether or not to use it, depending on if we call + // Mutex::Mutex(process_shared_tag) + CRITICAL_SECTION m_critical_section; +#else + pthread_mutex_t m_impl = PTHREAD_MUTEX_INITIALIZER; +#endif + + struct no_init_tag { + }; + Mutex(no_init_tag) + { + } + + void init_as_regular(); + void init_as_process_shared(bool robust_if_available); + + REALM_NORETURN static void init_failed(int); + REALM_NORETURN static void attr_init_failed(int); + REALM_NORETURN static void destroy_failed(int) noexcept; + REALM_NORETURN static void lock_failed(int) noexcept; + +private: + friend class CondVar; + friend class RobustMutex; +}; + + +/// A simple mutex ownership wrapper. +class LockGuard { +public: + LockGuard(Mutex&) noexcept; + ~LockGuard() noexcept; + +private: + Mutex& m_mutex; + friend class CondVar; +}; + + +/// See UniqueLock. +struct defer_lock_tag { +}; + +/// A general-purpose mutex ownership wrapper supporting deferred +/// locking as well as repeated unlocking and relocking. +class UniqueLock { +public: + UniqueLock(Mutex&) noexcept; + UniqueLock(Mutex&, defer_lock_tag) noexcept; + ~UniqueLock() noexcept; + + void lock() noexcept; + void unlock() noexcept; + bool holds_lock() noexcept; + +private: + Mutex* m_mutex; + bool m_is_locked; +}; + + +/// A robust version of a process-shared mutex. +/// +/// A robust mutex is one that detects whether a thread (or process) +/// has died while holding a lock on the mutex. +/// +/// When the present platform does not offer support for robust +/// mutexes, this mutex class behaves as a regular process-shared +/// mutex, which means that if a thread dies while holding a lock, any +/// future attempt at locking will block indefinitely. +class RobustMutex : private Mutex { +public: + RobustMutex(); + ~RobustMutex() noexcept; + + static bool is_robust_on_this_platform() noexcept; + + class NotRecoverable; + + /// \param recover_func If the present platform does not support + /// robust mutexes, this function is never called. Otherwise it is + /// called if, and only if a thread has died while holding a + /// lock. The purpose of the function is to reestablish a + /// consistent shared state. If it fails to do this by throwing an + /// exception, the mutex enters the 'unrecoverable' state where + /// any future attempt at locking it will fail and cause + /// NotRecoverable to be thrown. This function is advised to throw + /// NotRecoverable when it fails, but it may throw any exception. + /// + /// \throw NotRecoverable If thrown by the specified recover + /// function, or if the mutex has entered the 'unrecoverable' + /// state due to a different thread throwing from its recover + /// function. + template + void lock(Func recover_func); + + template + bool try_lock(Func recover_func); + + void unlock() noexcept; + + /// Low-level locking of robust mutex. + /// + /// If the present platform does not support robust mutexes, this + /// function always returns true. Otherwise it returns false if, + /// and only if a thread has died while holding a lock. + /// + /// \note Most application should never call this function + /// directly. It is called automatically when using the ordinary + /// lock() function. + /// + /// \throw NotRecoverable If this mutex has entered the "not + /// recoverable" state. It enters this state if + /// mark_as_consistent() is not called between a call to + /// robust_lock() that returns false and the corresponding call to + /// unlock(). + bool low_level_lock(); + + /// Low-level try-lock of robust mutex + /// + /// If the present platform does not support robust mutexes, this + /// function always returns 0 or 1. Otherwise it returns -1 if, + /// and only if a thread has died while holding a lock. + /// + /// Returns 1 if the lock is succesfully obtained. + /// Returns 0 if the lock is held by somebody else (not obtained) + /// Returns -1 if a thread has died while holding a lock. + /// + /// \note Most application should never call this function + /// directly. It is called automatically when using the ordinary + /// lock() function. + /// + /// \throw NotRecoverable If this mutex has entered the "not + /// recoverable" state. It enters this state if + /// mark_as_consistent() is not called between a call to + /// robust_lock() that returns false and the corresponding call to + /// unlock(). + int try_low_level_lock(); + + /// Pull this mutex out of the 'inconsistent' state. + /// + /// Must be called only after low_level_lock() has returned false. + /// + /// \note Most application should never call this function + /// directly. It is called automatically when using the ordinary + /// lock() function. + void mark_as_consistent() noexcept; + + /// Attempt to check if this mutex is a valid object. + /// + /// This attempts to trylock() the mutex, and if that fails returns false if + /// the return value indicates that the low-level mutex is invalid (which is + /// distinct from 'inconsistent'). Although pthread_mutex_trylock() may + /// return EINVAL if the argument is not an initialized mutex object, merely + /// attempting to check if an arbitrary blob of memory is a mutex object may + /// involve undefined behavior, so it is only safe to assume that this + /// function will run correctly when it is known that the mutex object is + /// valid. + bool is_valid() noexcept; + + friend class CondVar; +}; + +class RobustMutex::NotRecoverable : public std::exception { +public: + const char* what() const noexcept override + { + return "Failed to recover consistent state of shared memory"; + } +}; + + +/// A simple robust mutex ownership wrapper. +class RobustLockGuard { +public: + /// \param m the mutex to guard + /// \param func See RobustMutex::lock(). + template + RobustLockGuard(RobustMutex& m, TFunc func); + ~RobustLockGuard() noexcept; + +private: + RobustMutex& m_mutex; + friend class CondVar; +}; + + +/// Condition variable for use in synchronization monitors. +class CondVar { +public: + CondVar(); + ~CondVar() noexcept; + + struct process_shared_tag { + }; + + /// Initialize this condition variable for use across multiple + /// processes. When constructed this way, the instance may be + /// placed in memory shared by multimple processes, as well as in + /// a memory mapped file. Such a condition variable remains valid + /// even after the constructing process terminates. Deleting the + /// instance (freeing the memory or deleting the file) without + /// first calling the destructor is legal and will not cause any + /// system resources to be leaked. + CondVar(process_shared_tag); + + /// Wait for another thread to call notify() or notify_all(). + void wait(LockGuard& l) noexcept; + template + void wait(RobustMutex& m, Func recover_func, const struct timespec* tp = nullptr); + + /// If any threads are wating for this condition, wake up at least + /// one. + void notify() noexcept; + + /// Wake up every thread that is currently wating on this + /// condition. + void notify_all() noexcept; + +private: +#ifdef _WIN32 + CONDITION_VARIABLE m_condvar = CONDITION_VARIABLE_INIT; +#else + pthread_cond_t m_impl; +#endif + + REALM_NORETURN static void init_failed(int); + REALM_NORETURN static void attr_init_failed(int); + REALM_NORETURN static void destroy_failed(int) noexcept; + void handle_wait_error(int error); +}; + + +class RaceDetector { + std::atomic busy; + +public: + RaceDetector() + { + busy.store(false); + } + void enter() + { + bool already_busy = busy.exchange(true, std::memory_order_acq_rel); + if (already_busy) + throw std::runtime_error("Race detected - critical section busy on entry"); + } + void leave() + { + busy.store(false, std::memory_order_release); + } + friend class CriticalSection; +}; + +class CriticalSection { + RaceDetector& rd; + +public: + CriticalSection(RaceDetector& race) + : rd(race) + { + rd.enter(); + } + ~CriticalSection() + { + rd.leave(); + } +}; + +// Implementation: + +inline Thread::Thread() + : m_joinable(false) +{ +} + +template +inline Thread::Thread(F func) + : m_joinable(true) +{ + std::unique_ptr func2(new F(func)); // Throws + start(&Thread::entry_point, func2.get()); // Throws + func2.release(); +} + +inline Thread::Thread(Thread&& thread) noexcept +{ +#ifndef _WIN32 + m_id = thread.m_id; + m_joinable = thread.m_joinable; + thread.m_joinable = false; +#endif +} + +template +inline void Thread::start(F func) +{ + if (m_joinable) + std::terminate(); + std::unique_ptr func2(new F(func)); // Throws + start(&Thread::entry_point, func2.get()); // Throws + func2.release(); + m_joinable = true; +} + +inline Thread::~Thread() noexcept +{ + if (m_joinable) + REALM_TERMINATE("Destruction of joinable thread"); +} + +inline bool Thread::joinable() noexcept +{ + return m_joinable; +} + +inline void Thread::start(entry_func_type entry_func, void* arg) +{ +#ifdef _WIN32 + m_std_thread = std::thread(entry_func, arg); +#else + const pthread_attr_t* attr = nullptr; // Use default thread attributes + int r = pthread_create(&m_id, attr, entry_func, arg); + if (REALM_UNLIKELY(r != 0)) + create_failed(r); // Throws +#endif +} + +template +inline void* Thread::entry_point(void* cookie) noexcept +{ + std::unique_ptr func(static_cast(cookie)); + try { + (*func)(); + } + catch (...) { + std::terminate(); + } + return 0; +} + + +inline Mutex::Mutex() +{ + init_as_regular(); +} + +inline Mutex::Mutex(process_shared_tag) +{ + bool robust_if_available = false; + init_as_process_shared(robust_if_available); +} + +inline Mutex::~Mutex() noexcept +{ +#ifndef _WIN32 + int r = pthread_mutex_destroy(&m_impl); + if (REALM_UNLIKELY(r != 0)) + destroy_failed(r); +#else + DeleteCriticalSection(&m_critical_section); +#endif +} + +inline void Mutex::init_as_regular() +{ +#ifndef _WIN32 + int r = pthread_mutex_init(&m_impl, 0); + if (REALM_UNLIKELY(r != 0)) + init_failed(r); +#else + InitializeCriticalSection(&m_critical_section); +#endif +} + +inline void Mutex::lock() noexcept +{ +#ifdef _WIN32 + EnterCriticalSection(&m_critical_section); +#else + int r = pthread_mutex_lock(&m_impl); + if (REALM_LIKELY(r == 0)) + return; + lock_failed(r); +#endif +} + +inline bool Mutex::try_lock() noexcept +{ +#ifdef _WIN32 + return TryEnterCriticalSection(&m_critical_section); +#else + int r = pthread_mutex_trylock(&m_impl); + if (r == EBUSY) { + return false; + } + else if (r == 0) { + return true; + } + lock_failed(r); +#endif +} + +inline void Mutex::unlock() noexcept +{ +#ifdef _WIN32 + LeaveCriticalSection(&m_critical_section); +#else + int r = pthread_mutex_unlock(&m_impl); + REALM_ASSERT(r == 0); +#endif +} + + +inline LockGuard::LockGuard(Mutex& m) noexcept + : m_mutex(m) +{ + m_mutex.lock(); +} + +inline LockGuard::~LockGuard() noexcept +{ + m_mutex.unlock(); +} + + +inline UniqueLock::UniqueLock(Mutex& m) noexcept + : m_mutex(&m) +{ + m_mutex->lock(); + m_is_locked = true; +} + +inline UniqueLock::UniqueLock(Mutex& m, defer_lock_tag) noexcept + : m_mutex(&m) +{ + m_is_locked = false; +} + +inline UniqueLock::~UniqueLock() noexcept +{ + if (m_is_locked) + m_mutex->unlock(); +} + +inline bool UniqueLock::holds_lock() noexcept +{ + return m_is_locked; +} + +inline void UniqueLock::lock() noexcept +{ + m_mutex->lock(); + m_is_locked = true; +} + +inline void UniqueLock::unlock() noexcept +{ + m_mutex->unlock(); + m_is_locked = false; +} + +template +inline RobustLockGuard::RobustLockGuard(RobustMutex& m, TFunc func) + : m_mutex(m) +{ + m_mutex.lock(func); +} + +inline RobustLockGuard::~RobustLockGuard() noexcept +{ + m_mutex.unlock(); +} + + +inline RobustMutex::RobustMutex() + : Mutex(no_init_tag()) +{ + bool robust_if_available = true; + init_as_process_shared(robust_if_available); +} + +inline RobustMutex::~RobustMutex() noexcept +{ +} + +template +inline void RobustMutex::lock(Func recover_func) +{ + bool no_thread_has_died = low_level_lock(); // Throws + if (REALM_LIKELY(no_thread_has_died)) + return; + try { + recover_func(); // Throws + mark_as_consistent(); + // If we get this far, the protected memory has been + // brought back into a consistent state, and the mutex has + // been notified about this. This means that we can safely + // enter the applications critical section. + } + catch (...) { + // Unlocking without first calling mark_as_consistent() + // means that the mutex enters the "not recoverable" + // state, which will cause all future attempts at locking + // to fail. + unlock(); + throw; + } +} + +template +inline bool RobustMutex::try_lock(Func recover_func) +{ + int lock_result = try_low_level_lock(); // Throws + if (lock_result == 0) return false; + bool no_thread_has_died = lock_result == 1; + if (REALM_LIKELY(no_thread_has_died)) + return true; + try { + recover_func(); // Throws + mark_as_consistent(); + // If we get this far, the protected memory has been + // brought back into a consistent state, and the mutex has + // been notified aboit this. This means that we can safely + // enter the applications critical section. + } + catch (...) { + // Unlocking without first calling mark_as_consistent() + // means that the mutex enters the "not recoverable" + // state, which will cause all future attempts at locking + // to fail. + unlock(); + throw; + } + return true; +} + +inline void RobustMutex::unlock() noexcept +{ + Mutex::unlock(); +} + + +inline CondVar::CondVar() +{ +#ifndef _WIN32 + int r = pthread_cond_init(&m_impl, 0); + if (REALM_UNLIKELY(r != 0)) + init_failed(r); +#endif +} + +inline CondVar::~CondVar() noexcept +{ +#ifndef _WIN32 + int r = pthread_cond_destroy(&m_impl); + if (REALM_UNLIKELY(r != 0)) + destroy_failed(r); +#endif +} + +inline void CondVar::wait(LockGuard& l) noexcept +{ +#ifdef _WIN32 + SleepConditionVariableCS(&m_condvar, &l.m_mutex.m_critical_section, INFINITE); +#else + int r = pthread_cond_wait(&m_impl, &l.m_mutex.m_impl); + if (REALM_UNLIKELY(r != 0)) + REALM_TERMINATE("pthread_cond_wait() failed"); +#endif +} + +template +inline void CondVar::wait(RobustMutex& m, Func recover_func, const struct timespec* tp) +{ + int r; + + if (!tp) { +#ifdef _WIN32 + if (!SleepConditionVariableCS(&m_condvar, &m.m_critical_section, INFINITE)) + r = GetLastError(); + else + r = 0; +#else + r = pthread_cond_wait(&m_impl, &m.m_impl); +#endif + } + else { +#ifdef _WIN32 + if (!SleepConditionVariableCS(&m_condvar, &m.m_critical_section, tp->tv_sec / 1000)) { + r = GetLastError(); + if (r == ERROR_TIMEOUT) + return; + } else { + r = 0; + } +#else + r = pthread_cond_timedwait(&m_impl, &m.m_impl, tp); + if (r == ETIMEDOUT) + return; +#endif + } + + if (REALM_LIKELY(r == 0)) + return; + + handle_wait_error(r); + + try { + recover_func(); // Throws + m.mark_as_consistent(); + // If we get this far, the protected memory has been + // brought back into a consistent state, and the mutex has + // been notified aboit this. This means that we can safely + // enter the applications critical section. + } + catch (...) { + // Unlocking without first calling mark_as_consistent() + // means that the mutex enters the "not recoverable" + // state, which will cause all future attempts at locking + // to fail. + m.unlock(); + throw; + } +} + +inline void CondVar::notify() noexcept +{ +#ifdef _WIN32 + WakeConditionVariable(&m_condvar); +#else + int r = pthread_cond_signal(&m_impl); + REALM_ASSERT(r == 0); +#endif +} + +inline void CondVar::notify_all() noexcept +{ +#ifdef _WIN32 + WakeAllConditionVariable(&m_condvar); +#else + int r = pthread_cond_broadcast(&m_impl); + REALM_ASSERT(r == 0); +#endif +} + +// helpers which can ensure atomic access to memory which has not itself been declared atomic. +// This can be used to e.g. ensure atomic access to members of a vector. Vectors does not +// fully allow atomic members because operations on vector may relocate the underlying memory. +// use with care! +template +T load_atomic(T& t_ref, std::memory_order order) +{ + std::atomic* t_ptr = reinterpret_cast*>(&t_ref); + T t = atomic_load_explicit(t_ptr, order); + return t; +} + +template +void store_atomic(T& t_ref, T value, std::memory_order order) +{ + std::atomic* t_ptr = reinterpret_cast*>(&t_ref); + atomic_store_explicit(t_ptr, value, order); +} + + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_THREAD_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/thread_exec_guard.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/thread_exec_guard.hpp new file mode 100644 index 0000000..2dc42f7 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/thread_exec_guard.hpp @@ -0,0 +1,331 @@ +#ifndef REALM_UTIL_THREAD_EXEC_GUARD_HPP +#define REALM_UTIL_THREAD_EXEC_GUARD_HPP + +#include +#include +#include + +#include +#include + + +namespace realm { +namespace util { + +/// Execute a `R::run()` using a managed thread. +/// +/// \tparam R The type of the runnable object. This type must satisfy the +/// requirements of the Runnable concept. See ThreadExecGuardWithParent. +template +class ThreadExecGuard { +public: + explicit ThreadExecGuard(R& runnable); + + ThreadExecGuard(ThreadExecGuard&&) = default; + + /// If start() or start_with_signals_blocked() was successfully executed, + /// and stop_and_rethrow() has not been called, call `R::stop()`, and then + /// wait for the thread to terminate (join). + ~ThreadExecGuard() noexcept = default; + + // @{ + /// Launch a thread and make it execute `R::run()` of the associated + /// "runnable" object. + /// + /// At most one of these functions are allowed to be called on a particular + /// guard object, and it must only be called once. + void start(); + void start(const std::string& thread_name); + void start_with_signals_blocked(); + void start_with_signals_blocked(const std::string& thread_name); + // @} + + /// If start() or start_with_signals_blocked() was successfully executed, + /// call `R::stop()`, wait for the thread to terminate (join), and then, if + /// an exception was thrown by `R::run()`, rethrow it. + void stop_and_rethrow(); + +private: + struct State { + R& runnable; + util::Thread thread; + std::exception_ptr exception; + State(R&) noexcept; + ~State() noexcept; + void start(const std::string* thread_name); + void stop_and_rethrow(); + }; + + std::unique_ptr m_state; +}; + + +/// Execute a `R::run()` using a managed thread. +/// +/// \tparam R The type of the runnable object. This type must satisfy the +/// requirements of the Runnable concept. See below. +/// +/// \tparam P The type of the object representing the parent thread. This type +/// must satisfy the requirements of the Stoppable concept. See below. +/// +/// A type satisfies the requirements of the *Stoppable* concept, if +/// - it has a nonthrowing member function named `stop()`, and +/// - `stop()` is thread-safe, and +/// - `stop()` is idempotent (can be called multiple times). +/// +/// A type satisfies the requirements of the *Runnable* concept, if +/// - it satisfies the requirements of the Stoppable concept, and +/// - it has a member function named `run()`, and +/// - `run()` will stop executing within a reasonable amount of time after +/// `stop()` has been called. +/// +template +class ThreadExecGuardWithParent { +public: + explicit ThreadExecGuardWithParent(R& runnable, P& parent); + + ThreadExecGuardWithParent(ThreadExecGuardWithParent&&) = default; + + /// If start() or start_with_signals_blocked() was successfully executed, + /// and stop_and_rethrow() has not been called, call `R::stop()`, and then + /// wait for the thread to terminate (join). + ~ThreadExecGuardWithParent() noexcept = default; + + // @{ + /// Launch a thread and make it execute `R::run()` of the associated + /// "runnable" object. + /// + /// If `R::run()` throws, call `P::stop()` on the specified parent. + /// + /// At most one of these functions are allowed to be called on a particular + /// guard object, and it must only be called once. + void start(); + void start(const std::string& thread_name); + void start_with_signals_blocked(); + void start_with_signals_blocked(const std::string& thread_name); + // @} + + /// If start() or start_with_signals_blocked() was successfully executed, + /// call `R::stop()`, wait for the thread to terminate (join), and then, if + /// an exception was thrown by `R::run()`, rethrow it. + void stop_and_rethrow(); + +private: + struct State { + R& runnable; + P& parent; + util::Thread thread; + std::exception_ptr exception; + State(R&, P&) noexcept; + ~State() noexcept; + void start(const std::string* thread_name); + void stop_and_rethrow(); + }; + + std::unique_ptr m_state; +}; + + +template +ThreadExecGuard make_thread_exec_guard(R& runnable); + +template +ThreadExecGuardWithParent make_thread_exec_guard(R& runnable, P& parent); + + +// Implementation + +template +inline ThreadExecGuard::ThreadExecGuard(R& runnable) + : m_state{std::make_unique(runnable)} // Throws +{ +} + +template +inline void ThreadExecGuard::start() +{ + const std::string* thread_name = nullptr; + m_state->start(thread_name); // Throws +} + +template +inline void ThreadExecGuard::start(const std::string& thread_name) +{ + m_state->start(&thread_name); // Throws +} + +template +inline void ThreadExecGuard::start_with_signals_blocked() +{ + SignalBlocker sb; + const std::string* thread_name = nullptr; + m_state->start(thread_name); // Throws +} + +template +inline void ThreadExecGuard::start_with_signals_blocked(const std::string& thread_name) +{ + SignalBlocker sb; + m_state->start(&thread_name); // Throws +} + +template +inline void ThreadExecGuard::stop_and_rethrow() +{ + m_state->stop_and_rethrow(); // Throws +} + +template +inline ThreadExecGuard::State::State(R& r) noexcept + : runnable{r} +{ +} + +template +inline ThreadExecGuard::State::~State() noexcept +{ + if (thread.joinable()) { + runnable.stop(); + thread.join(); + } +} + +template +inline void ThreadExecGuard::State::start(const std::string* thread_name) +{ + bool set_thread_name = false; + std::string thread_name_2; + if (thread_name) { + set_thread_name = true; + thread_name_2 = *thread_name; // Throws (copy) + } + auto run = [this, set_thread_name, thread_name = std::move(thread_name_2)]() noexcept { + try { + if (set_thread_name) + util::Thread::set_name(thread_name); // Throws + runnable.run(); // Throws + } + catch (...) { + exception = std::current_exception(); + } + }; + thread.start(std::move(run)); // Throws +} + +template +inline void ThreadExecGuard::State::stop_and_rethrow() +{ + if (thread.joinable()) { + runnable.stop(); + thread.join(); + if (exception) + std::rethrow_exception(exception); // Throws + } +} + +template +inline ThreadExecGuardWithParent::ThreadExecGuardWithParent(R& runnable, P& parent) + : m_state{std::make_unique(runnable, parent)} // Throws +{ +} + +template +inline void ThreadExecGuardWithParent::start() +{ + const std::string* thread_name = nullptr; + m_state->start(thread_name); // Throws +} + +template +inline void ThreadExecGuardWithParent::start(const std::string& thread_name) +{ + m_state->start(&thread_name); // Throws +} + +template +inline void ThreadExecGuardWithParent::start_with_signals_blocked() +{ + SignalBlocker sb; + const std::string* thread_name = nullptr; + m_state->start(thread_name); // Throws +} + +template +inline void ThreadExecGuardWithParent::start_with_signals_blocked(const std::string& thread_name) +{ + SignalBlocker sb; + m_state->start(&thread_name); // Throws +} + +template +inline void ThreadExecGuardWithParent::stop_and_rethrow() +{ + m_state->stop_and_rethrow(); // Throws +} + +template +inline ThreadExecGuardWithParent::State::State(R& r, P& p) noexcept + : runnable{r} + , parent{p} +{ +} + +template +inline ThreadExecGuardWithParent::State::~State() noexcept +{ + if (thread.joinable()) { + runnable.stop(); + thread.join(); + } +} + +template +inline void ThreadExecGuardWithParent::State::start(const std::string* thread_name) +{ + bool set_thread_name = false; + std::string thread_name_2; + if (thread_name) { + set_thread_name = true; + thread_name_2 = *thread_name; // Throws (copy) + } + auto run = [this, set_thread_name, thread_name = std::move(thread_name_2)]() noexcept { + try { + if (set_thread_name) + util::Thread::set_name(thread_name); // Throws + runnable.run(); // Throws + } + catch (...) { + exception = std::current_exception(); + parent.stop(); + } + }; + thread.start(std::move(run)); // Throws +} + +template +inline void ThreadExecGuardWithParent::State::stop_and_rethrow() +{ + if (thread.joinable()) { + runnable.stop(); + thread.join(); + if (exception) + std::rethrow_exception(exception); // Throws + } +} + +template +inline ThreadExecGuard make_thread_exec_guard(R& runnable) +{ + return ThreadExecGuard{runnable}; // Throws +} + +template +inline ThreadExecGuardWithParent make_thread_exec_guard(R& runnable, P& parent) +{ + return ThreadExecGuardWithParent{runnable, parent}; // Throws +} + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_THREAD_EXEC_GUARD_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/time.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/time.hpp new file mode 100644 index 0000000..51f5343 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/time.hpp @@ -0,0 +1,73 @@ + +#ifndef REALM_UTIL_TIME_HPP +#define REALM_UTIL_TIME_HPP + +#include +#include +#include +#include +#include +#include + + +namespace realm { +namespace util { + +/// Thread safe version of std::localtime(). Uses localtime_r() on POSIX. +std::tm localtime(std::time_t); + +/// Thread safe version of std::gmtime(). Uses gmtime_r() on POSIX. +std::tm gmtime(std::time_t); + +/// Similar to std::put_time() from . See std::put_time() for +/// information about the format string. This function is provided because +/// std::put_time() is unavailable in GCC 4. This function is thread safe. +/// +/// The default format is ISO 8601 date and time. +template +void put_time(std::basic_ostream&, const std::tm&, const C* format = "%FT%T%z"); + +// @{ +/// These functions combine localtime() or gmtime() with put_time() and +/// std::ostringstream. For detals on the format string, see +/// std::put_time(). These function are thread safe. +std::string format_local_time(std::time_t, const char* format = "%FT%T%z"); +std::string format_utc_time(std::time_t, const char* format = "%FT%T%z"); +// @} + +/// The local time since the epoch in microseconds. +/// +/// FIXME: This function has nothing to do with local time. +double local_time_microseconds(); + + +// Implementation + +template +inline void put_time(std::basic_ostream& out, const std::tm& tm, const C* format) +{ + const auto& facet = std::use_facet>(out.getloc()); // Throws + facet.put(std::ostreambuf_iterator(out), out, out.widen(' '), &tm, + format, format + T::length(format)); // Throws +} + +inline std::string format_local_time(std::time_t time, const char* format) +{ + std::tm tm = util::localtime(time); + std::ostringstream out; + util::put_time(out, tm, format); // Throws + return out.str(); // Throws +} + +inline std::string format_utc_time(std::time_t time, const char* format) +{ + std::tm tm = util::gmtime(time); + std::ostringstream out; + util::put_time(out, tm, format); // Throws + return out.str(); // Throws +} + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_TIME_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/timestamp_formatter.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/timestamp_formatter.hpp new file mode 100644 index 0000000..8f3bf45 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/timestamp_formatter.hpp @@ -0,0 +1,89 @@ + +#ifndef REALM_UTIL_TIMESTAMP_FORMATTER_HPP +#define REALM_UTIL_TIMESTAMP_FORMATTER_HPP + +#include +#include +#include +#include + +#include +#include +#include +#include + + +namespace realm { +namespace util { + +class TimestampFormatter { +public: + using char_type = char; + using string_view_type = util::BasicStringView; + + enum class Precision { seconds, milliseconds, microseconds, nanoseconds }; + + /// Default configuration for corresponds to local time in ISO 8601 date and + /// time format. + struct Config { + Config() {} + + bool utc_time = false; + + Precision precision = Precision::seconds; + + /// The format of the timestamp as understood by std::put_time(), except + /// that the first occurrence of `%S` (also taking into account the `%S` + /// that is an implicit part of `%T`) is expanded to `SS.fff` if \ref + /// precision is Precision::milliseconds, or to `SS.ffffff` if \ref + /// precision is Precision::microseconds, or to `SS.fffffffff` if \ref + /// precision is Precision::nanoseconds, where `SS` is what `%S` expands + /// to conventionally. + const char* format = "%FT%T%z"; + }; + + TimestampFormatter(Config = {}); + + // FIXME: Use std::timespec in C++17. + string_view_type format(std::time_t time, long nanoseconds); + + template + string_view_type format(std::chrono::time_point); + +private: + using memory_output_stream_type = util::MemoryOutputStream; + using format_segments_type = std::pair; + + const bool m_utc_time; + const Precision m_precision; + const format_segments_type m_format_segments; + char_type m_buffer[64]; + memory_output_stream_type m_out; + + static format_segments_type make_format_segments(const Config&); +}; + + +// Implementation + +template +inline auto TimestampFormatter::format(std::chrono::time_point time) -> string_view_type +{ + using clock_type = B; + using time_point_type = std::chrono::time_point; + std::time_t time_2 = clock_type::to_time_t(time); + time_point_type time_3 = clock_type::from_time_t(time_2); + if (REALM_UNLIKELY(time_3 > time)) { + --time_2; + time_3 = clock_type::from_time_t(time_2); + } + long nanoseconds = + long(std::chrono::duration_cast(time - time_3).count()); + REALM_ASSERT(nanoseconds >= 0 && nanoseconds < 1000000000); + return format(time_2, nanoseconds); // Throws +} + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_TIMESTAMP_FORMATTER_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/timestamp_logger.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/timestamp_logger.hpp new file mode 100644 index 0000000..87d8ae3 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/timestamp_logger.hpp @@ -0,0 +1,30 @@ + +#ifndef REALM_UTIL_TIMESTAMP_LOGGER_HPP +#define REALM_UTIL_TIMESTAMP_LOGGER_HPP + +#include +#include + + +namespace realm { +namespace util { + +class TimestampStderrLogger : public RootLogger { +public: + using Precision = TimestampFormatter::Precision; + using Config = TimestampFormatter::Config; + + explicit TimestampStderrLogger(Config = {}); + +protected: + void do_log(Logger::Level, std::string message) override; + +private: + TimestampFormatter m_formatter; +}; + + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_TIMESTAMP_LOGGER_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/to_string.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/to_string.hpp new file mode 100644 index 0000000..1bc6828 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/to_string.hpp @@ -0,0 +1,140 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_UTIL_TO_STRING_HPP +#define REALM_UTIL_TO_STRING_HPP + +#include +#include + +namespace realm { +namespace util { + +class Printable { +public: + Printable(bool value) + : m_type(Type::Bool) + , m_uint(value) + { + } + Printable(unsigned char value) + : m_type(Type::Uint) + , m_uint(value) + { + } + Printable(unsigned int value) + : m_type(Type::Uint) + , m_uint(value) + { + } + Printable(unsigned long value) + : m_type(Type::Uint) + , m_uint(value) + { + } + Printable(unsigned long long value) + : m_type(Type::Uint) + , m_uint(value) + { + } + Printable(char value) + : m_type(Type::Int) + , m_int(value) + { + } + Printable(int value) + : m_type(Type::Int) + , m_int(value) + { + } + Printable(long value) + : m_type(Type::Int) + , m_int(value) + { + } + Printable(long long value) + : m_type(Type::Int) + , m_int(value) + { + } + Printable(double value) + : m_type(Type::Double) + , m_double(value) + { + } + Printable(const char* value) + : m_type(Type::String) + , m_string(value) + { + } + Printable(std::string const& value) + : m_type(Type::String) + , m_string(value.c_str()) + { + } + + + void print(std::ostream& out, bool quote) const; + std::string str() const; + + static void print_all(std::ostream& out, const std::initializer_list& values, bool quote); + +private: + enum class Type { + Bool, + Int, + Uint, + Double, + String, + } m_type; + + union { + uintmax_t m_uint; + intmax_t m_int; + double m_double; + const char* m_string; + }; +}; + + +template +std::string to_string(const T& v) +{ + return Printable(v).str(); +} + + +std::string format(const char* fmt, std::initializer_list); + +// format string format: +// "%%" - literal '%' +// "%1" - substitutes Nth argument, 1-indexed +// +// format("Hello %1, meet %2. %3%% complete.", "Alice", "Bob", 97) +// -> "Hello Alice, meet Bob. 97% complete." +template +std::string format(const char* fmt, Args&&... args) +{ + return format(fmt, {Printable(args)...}); +} + + +} // namespace util +} // namespace realm + +#endif // REALM_UTIL_TO_STRING_HPP diff --git a/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/type_list.hpp b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/type_list.hpp new file mode 100644 index 0000000..da847c7 --- /dev/null +++ b/Darner-dan-uh/Pods/Realm/core/realm-sync.xcframework/ios-arm64_i386_x86_64-simulator/Headers/realm/util/type_list.hpp @@ -0,0 +1,244 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * 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 REALM_UTIL_TYPE_LIST_HPP +#define REALM_UTIL_TYPE_LIST_HPP + +namespace realm { +namespace util { + + +/// The 'cons' operator for building lists of types. +/// +/// \tparam H The head of the list, that is, the first type in the +/// list. +/// +/// \tparam T The tail of the list, that is, the list of types +/// following the head. It is 'void' if nothing follows the head, +/// otherwise it matches TypeCons. +/// +/// Note that 'void' is interpreted as a zero-length list. +template +struct TypeCons { + typedef H head; + typedef T tail; +}; + + +/// Append a type the the end of a type list. The resulting type list +/// is available as TypeAppend::type. +/// +/// \tparam List A list of types constructed using TypeCons<>. Note +/// that 'void' is interpreted as a zero-length list. +/// +/// \tparam T The new type to be appended. +template +struct TypeAppend { + typedef TypeCons::type> type; +}; +/// Base case for empty type list. +template +struct TypeAppend { + typedef TypeCons type; +}; + + +/// Get an element from the specified list of types. The result is +/// available as TypeAt::type. +/// +/// \tparam List A list of types constructed using TypeCons<>. Note +/// that 'void' is interpreted as a zero-length list. +/// +/// \tparam i The index of the list element to get. +template +struct TypeAt { + typedef typename TypeAt::type type; +}; +/// Base case for empty type list. +template +struct TypeAt { + typedef typename List::head type; +}; + + +/// Count the number of elements in the specified list of types. The +/// result is available as TypeCount::value. +/// +/// \tparam List The list of types, constructed using TypeCons<>. Note +/// that 'void' is interpreted as a zero-length list. +template +struct TypeCount { + static const int value = 1 + TypeCount::value; +}; +/// Base case for empty type list. +template <> +struct TypeCount { + static const int value = 0; +}; + + +/// Find the first type in the specified list that satisfies the +/// specified predicate. +/// +/// \tparam List The list of types, constructed using TypeCons<>. Note +/// that 'void' is interpreted as a zero-length list. +/// +/// \tparam Pred Must be such that `Pred::%value` is true if, and +/// only if the predicate is satisfied for `T`. +template class Pred> +struct FindType { +private: + typedef typename List::head type_1; + typedef typename FindType::type type_2; + +public: + typedef typename std::conditional::value, type_1, type_2>::type type; +}; +/// Base case for empty type list. +template