marinofaggiana 4 years ago
parent
commit
172a1cd7e3
100 changed files with 1 additions and 31063 deletions
  1. 1 1
      Cartfile.resolved
  2. 0 1
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/.dockerignore
  3. 0 32
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/.gitignore
  4. 0 3
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/.gitmodules
  5. 0 66
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/CMake/CodeCoverage.cmake
  6. 0 127
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/CMake/CompilerFlags.cmake
  7. 0 382
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/CMake/RealmCore.cmake
  8. 0 41
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/CMake/Sanitizers.cmake
  9. 0 46
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/CMakeLists.txt
  10. 0 23
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/Dockerfile
  11. 0 187
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/Jenkinsfile
  12. 0 269
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/LICENSE
  13. 0 4
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/dependencies.list
  14. 0 142
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/CMakeLists.txt
  15. 0 23
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/binding_callback_thread_observer.cpp
  16. 0 42
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/binding_callback_thread_observer.hpp
  17. 0 180
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/binding_context.hpp
  18. 0 61
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/collection_notifications.cpp
  19. 0 183
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/collection_notifications.hpp
  20. 0 30
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/feature_checks.hpp
  21. 0 243
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/apple/external_commit_helper.cpp
  22. 0 80
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/apple/external_commit_helper.hpp
  23. 0 143
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/apple/keychain_helper.cpp
  24. 0 39
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/apple/keychain_helper.hpp
  25. 0 673
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/collection_change_builder.cpp
  26. 0 81
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/collection_change_builder.hpp
  27. 0 500
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/collection_notifier.cpp
  28. 0 353
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/collection_notifier.hpp
  29. 0 299
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/epoll/external_commit_helper.cpp
  30. 0 70
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/epoll/external_commit_helper.hpp
  31. 0 40
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/external_commit_helper.hpp
  32. 0 50
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/generic/external_commit_helper.cpp
  33. 0 50
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/generic/external_commit_helper.hpp
  34. 0 104
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/list_notifier.cpp
  35. 0 58
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/list_notifier.hpp
  36. 0 51
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/notification_wrapper.hpp
  37. 0 224
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/object_accessor_impl.hpp
  38. 0 64
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/object_notifier.cpp
  39. 0 45
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/object_notifier.hpp
  40. 0 1162
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/realm_coordinator.cpp
  41. 0 274
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/realm_coordinator.hpp
  42. 0 362
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/results_notifier.cpp
  43. 0 117
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/results_notifier.hpp
  44. 0 564
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/transact_log_handler.cpp
  45. 0 62
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/transact_log_handler.hpp
  46. 0 54
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/weak_realm_notifier.cpp
  47. 0 67
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/weak_realm_notifier.hpp
  48. 0 69
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/windows/external_commit_helper.cpp
  49. 0 97
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/windows/external_commit_helper.hpp
  50. 0 707
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/index_set.cpp
  51. 0 325
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/index_set.hpp
  52. 0 507
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/list.cpp
  53. 0 319
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/list.hpp
  54. 0 163
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/object.cpp
  55. 0 188
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/object.hpp
  56. 0 349
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/object_accessor.hpp
  57. 0 343
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/object_schema.cpp
  58. 0 82
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/object_schema.hpp
  59. 0 926
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/object_store.cpp
  60. 0 170
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/object_store.hpp
  61. 0 1
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/placeholder.cpp
  62. 0 297
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/property.hpp
  63. 0 1114
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/results.cpp
  64. 0 393
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/results.hpp
  65. 0 258
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/schema.cpp
  66. 0 183
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/schema.hpp
  67. 0 1029
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/shared_realm.cpp
  68. 0 540
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/shared_realm.hpp
  69. 0 243
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/thread_safe_reference.cpp
  70. 0 59
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/thread_safe_reference.hpp
  71. 0 65
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/util/aligned_union.hpp
  72. 0 148
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/util/atomic_shared_ptr.hpp
  73. 0 60
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/util/tagged_bool.hpp
  74. 0 80
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/util/uuid.cpp
  75. 0 33
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/util/uuid.hpp
  76. 0 83
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/CMakeLists.txt
  77. 0 965
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/collection_change_indices.cpp
  78. 0 610
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/index_set.cpp
  79. 0 912
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/list.cpp
  80. 0 52
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/main.cpp
  81. 0 2059
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/migrations.cpp
  82. 0 13
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/notifications-fuzzer/CMakeLists.txt
  83. 0 246
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/notifications-fuzzer/command_file.cpp
  84. 0 56
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/notifications-fuzzer/command_file.hpp
  85. 0 21
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/notifications-fuzzer/fuzz-sorted-linkview.cpp
  86. 0 21
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/notifications-fuzzer/fuzz-sorted-query.cpp
  87. 0 21
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/notifications-fuzzer/fuzz-unsorted-linkview.cpp
  88. 0 21
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/notifications-fuzzer/fuzz-unsorted-query.cpp
  89. 0 308
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/notifications-fuzzer/fuzzer.cpp
  90. 0 38
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/notifications-fuzzer/input-lv/0
  91. 0 20
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/notifications-fuzzer/input/0
  92. 0 34
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/notifications-fuzzer/input/1
  93. 0 1017
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/object.cpp
  94. 0 77
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/object_store.cpp
  95. 0 857
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/primitive_list.cpp
  96. 0 381
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/query.json
  97. 0 1863
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/realm.cpp
  98. 0 3261
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/results.cpp
  99. 0 811
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/schema.cpp
  100. 0 896
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/thread_safe_reference.cpp

+ 1 - 1
Cartfile.resolved

@@ -18,7 +18,7 @@ github "krzyzanowskim/OpenSSL" "1.0.218"
 github "malcommac/SwiftRichString" "3.7.2"
 github "marinofaggiana/KTVHTTPCache" "2.0.2"
 github "marinofaggiana/TOPasscodeViewController" "0.0.7"
-github "nextcloud/ios-communication-library" "84c142e195ce20190396fa12d867338ce4c911e7"
+github "nextcloud/ios-communication-library" "a51f9680f13bf82387d5a16560737fb9159cb109"
 github "realm/realm-cocoa" "v5.3.3"
 github "rechsteiner/Parchment" "v2.4.0"
 github "scenee/FloatingPanel" "v1.7.5"

+ 0 - 1
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/.dockerignore

@@ -1 +0,0 @@
-.gitignore

+ 0 - 32
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/.gitignore

@@ -1,32 +0,0 @@
-# CMake
-.ninja_deps
-.ninja_log
-CMakeCache.txt
-CMakeFiles/
-Makefile
-build.ninja
-cmake_install.cmake
-rules.ninja
-CMakeScripts/
-realm-object-store.xcodeproj/
-
-# Build products
-src/librealm-object-store.a
-tests/tests
-*.build/
-Debug/
-Release/
-RelWithDebInfo/
-MinSizeRel/
-
-# IntelliJ
-.idea/
-
-# Visual Studio
-/.vs
-
-# Linters
-compile_commands.json
-
-# vim
-*.swp

+ 0 - 3
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/.gitmodules

@@ -1,3 +0,0 @@
-[submodule "external/catch"]
-	path = external/catch
-	url = https://github.com/catchorg/Catch2

+ 0 - 66
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/CMake/CodeCoverage.cmake

@@ -1,66 +0,0 @@
-###########################################################################
-#
-# 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.
-#
-###########################################################################
-
-find_program(LCOV_PATH lcov)
-find_program(GENHTML_PATH genhtml)
-find_program(GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/tests)
-
-set(CMAKE_CXX_FLAGS_COVERAGE "-g -O0 -fprofile-arcs -ftest-coverage -DCATCH_CONFIG_FAST_COMPILE")
-mark_as_advanced(CMAKE_CXX_FLAGS_COVERAGE)
-
-if(CMAKE_BUILD_TYPE STREQUAL "Coverage")
-  if(NOT (LCOV_PATH AND GENHTML_PATH AND GCOVR_PATH))
-    message(FATAL_ERROR "Generating a coverage report requires lcov and gcovr")
-  endif()
-
-  function(create_coverage_target targetname testrunner)
-    add_custom_target(${targetname}
-      # Clear previous coverage information
-      COMMAND ${LCOV_PATH} --directory . --zerocounters
-
-      # Run the tests
-      COMMAND ${testrunner}
-
-      # Generate new coverage report
-      COMMAND ${LCOV_PATH} --directory . --capture --output-file coverage.info
-      COMMAND ${LCOV_PATH} --extract coverage.info '${CMAKE_SOURCE_DIR}/src/*' --output-file coverage.info.cleaned
-      COMMAND ${GENHTML_PATH} -o coverage coverage.info.cleaned
-      COMMAND ${CMAKE_COMMAND} -E remove coverage.info coverage.info.cleaned
-
-      COMMAND echo Open coverage/index.html in your browser to view the coverage report.
-
-      WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
-    )
-
-    add_custom_target(${targetname}-cobertura
-      COMMAND ${testrunner}
-      COMMAND ${GCOVR_PATH} -x -o coverage.xml -f 'src/.*' -f "${CMAKE_SOURCE_DIR}/src.*" --exclude-directories "${CMAKE_BINARY_DIR}/tests" --exclude-directories="${CMAKE_SOURCE_DIR}/\.tmp" --exclude ".*realm\-core.*" --exclude ".*realm\-sync.*"
-      COMMAND echo Code coverage report written to coverage.xml
-
-      WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
-    )
-  endfunction()
-else()
-  function(create_coverage_target targetname testrunner)
-    add_custom_target(${targetname}
-      COMMAND echo "Configure with -DCMAKE_BUILD_TYPE=Coverage to generate coverage reports")
-
-    add_custom_target(${targetname}-cobertura
-      COMMAND echo "Configure with -DCMAKE_BUILD_TYPE=Coverage to generate coverage reports")
-  endfunction()
-endif()

+ 0 - 127
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/CMake/CompilerFlags.cmake

@@ -1,127 +0,0 @@
-###########################################################################
-#
-# 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(CheckSymbolExists)
-
-set(CMAKE_CXX_STANDARD 14)
-set(CMAKE_CXX_STANDARD_REQUIRED on)
-set(CMAKE_CXX_EXTENSIONS off)
-
-set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS
-    $<$<CONFIG:DEBUG>:REALM_DEBUG>
-    $<$<CONFIG:COVERAGE>:REALM_DEBUG>
-)
-
-if(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang" OR ${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
-    add_compile_options(
-        -Wall
-        -Wextra
-        -Wno-missing-field-initializers
-        -Wno-unevaluated-expression
-        -Wempty-body
-        -Wparentheses
-        -Wunknown-pragmas
-        -Wunreachable-code
-        -DREALM_HAVE_CONFIG
-    )
-endif()
-
-if(MSVC)
-    add_definitions(
-        /D_UNICODE
-        /DWIN32_LEAN_AND_MEAN
-        /D_CRT_SECURE_NO_WARNINGS
-        /D_SCL_SECURE_NO_WARNINGS
-        /D_ENABLE_EXTENDED_ALIGNED_STORAGE #https://developercommunity.visualstudio.com/comments/279328/view.html
-    )
-    add_compile_options(
-        /MP # Enable multi-processor compilation
-    )
-    if(NOT WINDOWS_STORE)
-        # Statically link the run-time library
-        # https://docs.microsoft.com/bg-bg/cpp/build/reference/md-mt-ld-use-run-time-library
-        # https://cmake.org/Wiki/CMake_FAQ#How_can_I_build_my_MSVC_application_with_a_static_runtime.3F
-        foreach(flag_var
-            CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
-            CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
-            if(${flag_var} MATCHES "/MD")
-                string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
-            endif()
-        endforeach()
-    endif()
-endif()
-
-if(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")
-    add_compile_options(
-        -Wassign-enum
-        -Wbool-conversion
-        -Wconditional-uninitialized
-        -Wconstant-conversion
-        -Wenum-conversion
-        -Wimplicit-fallthrough
-        -Wint-conversion
-        -Wmissing-prototypes
-        -Wnewline-eof
-        -Wshorten-64-to-32
-        -Wthread-safety
-        -Wthread-safety-negative
-    )
-endif()
-
-if(${CMAKE_GENERATOR} STREQUAL "Ninja")
-    if(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")
-        set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fcolor-diagnostics")
-        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcolor-diagnostics")
-    elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
-        set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fdiagnostics-color=always")
-        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color=always")
-    endif()
-endif()
-
-if(APPLE)
-    find_library(CF_LIBRARY CoreFoundation)
-    list(APPEND PLATFORM_LIBRARIES ${CF_LIBRARY})
-elseif(REALM_PLATFORM STREQUAL "Android")
-    find_library(ANDROID_LIBRARY android)
-    find_library(ANDROID_LOG_LIBRARY log)
-    list(APPEND PLATFORM_LIBRARIES ${ANDROID_LIBRARY})
-    list(APPEND PLATFORM_LIBRARIES ${ANDROID_LOG_LIBRARY})
-    set(PLATFORM_DEFINES "__STDC_CONSTANT_MACROS=1")
-endif()
-
-if(NOT REALM_PLATFORM OR REALM_PLATFORM STREQUAL "Node")
-    find_library(UV_LIBRARY NAMES uv libuv)
-    if(UV_LIBRARY)
-        find_path(UV_INCLUDE_DIR uv.h)
-
-        list(APPEND PLATFORM_LIBRARIES ${UV_LIBRARY})
-        add_definitions(-DREALM_HAVE_UV)
-    endif()
-endif()
-
-if(REALM_PLATFORM STREQUAL "Node")
-    set(PLATFORM_DEFINES "REALM_PLATFORM_NODE=1")
-    if(NOT UV_LIBRARY)
-        message(FATAL_ERROR "Platform set to Node but libuv was not found!")
-    endif()
-endif()
-
-check_symbol_exists(epoll_create sys/epoll.h REALM_HAVE_EPOLL)
-if(REALM_HAVE_EPOLL)
-    add_definitions(-DREALM_HAVE_EPOLL)
-endif()

+ 0 - 382
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/CMake/RealmCore.cmake

@@ -1,382 +0,0 @@
-#
-# 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(ExternalProject)
-include(ProcessorCount)
-
-find_package(Threads)
-
-# Load dependency info from dependencies.list into REALM_FOO_VERSION variables.
-set(DEPENDENCIES_FILE "dependencies.list" CACHE STRING "path to dependencies list")
-file(STRINGS ${DEPENDENCIES_FILE} DEPENDENCIES)
-message("Dependencies: ${DEPENDENCIES}")
-foreach(DEPENDENCY IN LISTS DEPENDENCIES)
-    string(REGEX MATCHALL "([^=]+)" COMPONENT_AND_VERSION ${DEPENDENCY})
-    list(GET COMPONENT_AND_VERSION 0 COMPONENT)
-    list(GET COMPONENT_AND_VERSION 1 VERSION)
-    set(${COMPONENT} ${VERSION})
-endforeach()
-
-
-if(APPLE)
-    find_library(FOUNDATION_FRAMEWORK Foundation)
-    find_library(SECURITY_FRAMEWORK Security)
-
-    set(CRYPTO_LIBRARIES "")
-    set(SSL_LIBRARIES ${FOUNDATION_FRAMEWORK} ${SECURITY_FRAMEWORK})
-elseif(CMAKE_SYSTEM_NAME MATCHES "^Windows")
-    # Windows doesn't do crypto right now, but that is subject to change
-    set(CRYPTO_LIBRARIES "")
-    set(SSL_LIBRARIES "")
-else()
-    if(NOT EXISTS ${CMAKE_BINARY_DIR}/openssl/lib/cmake/OpenSSL/OpenSSLConfig.cmake)
-        set(OPENSSL_URL "http://static.realm.io/downloads/openssl/${OPENSSL_VERSION}/Linux/x86_64/openssl.tgz")
-        if(REALM_PLATFORM STREQUAL "Android")
-            set(OPENSSL_URL "http://static.realm.io/downloads/openssl/${OPENSSL_VERSION}/Android/${ANDROID_ABI}/openssl.tgz")
-        endif()
-    
-        message(STATUS "Downloading OpenSSL...")
-        file(DOWNLOAD "${OPENSSL_URL}" "${CMAKE_BINARY_DIR}/openssl/openssl.tgz" STATUS download_status)
-    
-        list(GET download_status 0 status_code)
-        if (NOT "${status_code}" STREQUAL "0")
-            message(FATAL_ERROR "Downloading ${OPENSSL_URL}... Failed. Status: ${download_status}")
-        endif()
-    
-        message(STATUS "Uncompressing OpenSSL...")
-        execute_process(
-            COMMAND ${CMAKE_COMMAND} -E tar xfz "openssl.tgz"
-            WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/openssl"
-        )
-        message(STATUS "Importing OpenSSL...")
-    endif()
-    set(OpenSSL_DIR "${CMAKE_BINARY_DIR}/openssl/lib/cmake/OpenSSL")
-    find_package(OpenSSL REQUIRED CONFIG)
-
-    set(CRYPTO_LIBRARIES OpenSSL::Crypto)
-    set(SSL_LIBRARIES OpenSSL::SSL)
-endif()
-
-if (${CMAKE_VERSION} VERSION_GREATER "3.4.0")
-    set(USES_TERMINAL_BUILD USES_TERMINAL_BUILD 1)
-endif()
-
-function(use_realm_core enable_sync core_prefix sync_prefix)
-    if(core_prefix)
-        build_existing_realm_core(${core_prefix})
-        if(sync_prefix)
-            build_existing_realm_sync(${sync_prefix})
-        endif()
-    elseif(enable_sync)
-        # FIXME: Support building against prebuilt sync binaries.
-        clone_and_build_realm_core("v${REALM_CORE_VERSION}")
-        clone_and_build_realm_sync("v${REALM_SYNC_VERSION}")
-    else()
-        if(APPLE OR REALM_PLATFORM STREQUAL "Android" OR CMAKE_SYSTEM_NAME MATCHES "^Windows")
-            download_realm_core(${REALM_CORE_VERSION})
-        else()
-            clone_and_build_realm_core("v${REALM_CORE_VERSION}")
-        endif()
-    endif()
-endfunction()
-
-function(download_realm_tarball url target libraries)
-    get_filename_component(tarball_name "${url}" NAME)
-
-    set(tarball_parent_directory "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}")
-    set(tarball_path "${tarball_parent_directory}/${tarball_name}")
-    set(temp_tarball_path "/tmp/${tarball_name}")
-
-    if (NOT EXISTS ${tarball_path})
-        if (NOT EXISTS ${temp_tarball_path})
-            message("Downloading ${url}.")
-            file(DOWNLOAD ${url} ${temp_tarball_path}.tmp SHOW_PROGRESS)
-            file(RENAME ${temp_tarball_path}.tmp ${temp_tarball_path})
-        endif()
-        file(COPY ${temp_tarball_path} DESTINATION ${tarball_parent_directory})
-    endif()
-
-    if(APPLE)
-        add_custom_command(
-            COMMENT "Extracting ${tarball_name}"
-            OUTPUT ${libraries}
-            COMMAND ${CMAKE_COMMAND} -E tar xf ${tarball_path}
-            COMMAND ${CMAKE_COMMAND} -E remove_directory ${target}
-            COMMAND ${CMAKE_COMMAND} -E rename core ${target}
-            COMMAND ${CMAKE_COMMAND} -E touch_nocreate ${libraries})
-    elseif(REALM_PLATFORM STREQUAL "Android" OR CMAKE_SYSTEM_NAME MATCHES "^Windows")
-        add_custom_command(
-            COMMENT "Extracting ${tarball_name}"
-            OUTPUT ${libraries}
-            COMMAND "${CMAKE_COMMAND}" -E make_directory "${target}"
-            COMMAND "${CMAKE_COMMAND}" -E chdir "${target}" "${CMAKE_COMMAND}" -E tar xf "${tarball_path}"
-            COMMAND "${CMAKE_COMMAND}" -E touch_nocreate ${libraries})
-    endif()
-endfunction()
-
-function(download_realm_core core_version)
-    if(CMAKE_SYSTEM_NAME MATCHES "Windows")
-        set(compression "tar.gz")
-        set(library_directory "lib")
-
-        if(CMAKE_GENERATOR_PLATFORM MATCHES "^[Aa][Rr][Mm]$")
-            set(architecture "ARM")
-        elseif(CMAKE_GENERATOR_PLATFORM MATCHES "^[Xx]64$" OR CMAKE_SIZEOF_VOID_P EQUAL 8)
-            set(architecture "x64")
-        else()
-            set(architecture "Win32")
-        endif()
-
-        if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
-            set(platform "Windows")
-        elseif(CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
-            set(platform "UWP")
-        endif()
-
-        set(tarball_name_debug "realm-core-Debug-v${core_version}-${platform}-${architecture}-devel.tar.gz")
-        set(tarball_name_release "realm-core-Release-v${core_version}-${platform}-${architecture}-devel.tar.gz")
-
-        set(url_debug "https://static.realm.io/downloads/core/${tarball_name_debug}")
-        set(url_release "https://static.realm.io/downloads/core/${tarball_name_release}")
-
-        set(core_directory_parent "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}")
-        set(core_directory_debug "${core_directory_parent}/realm-core-${core_version}-debug")
-        set(core_directory_release "${core_directory_parent}/realm-core-${core_version}-release")
-        set(core_directory "${core_directory_debug}")
-
-        set(core_library_debug "${core_directory_debug}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}realm-dbg${CMAKE_STATIC_LIBRARY_SUFFIX}")
-        set(core_library_release "${core_directory_release}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}realm${CMAKE_STATIC_LIBRARY_SUFFIX}")
-        set(core_parser_library_debug "${core_directory_debug}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}realm-parser-dbg${CMAKE_STATIC_LIBRARY_SUFFIX}")
-        set(core_parser_library_release "${core_directory_release}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}realm-parser${CMAKE_STATIC_LIBRARY_SUFFIX}")
-        set(core_libraries ${core_library_debug} ${core_library_release} ${core_parser_library_debug} ${core_parser_library_release})
-
-        download_realm_tarball(${url_debug} ${core_directory_debug} ${core_library_debug} ${core_parser_library_debug})
-        download_realm_tarball(${url_release} ${core_directory_release} ${core_library_release} ${core_parser_library_release})
-    else()
-        if(APPLE)
-            set(basename "realm-core-cocoa")
-            set(compression "tar.xz")
-            set(platform "-macosx")
-        elseif(REALM_PLATFORM STREQUAL "Android")
-            set(basename "realm-core-android")
-            set(compression "tar.gz")
-            set(platform "-android-${ANDROID_ABI}")
-        endif()
-
-        set(tarball_name "${basename}-v${core_version}.${compression}")
-        set(url "https://static.realm.io/downloads/core/${tarball_name}")
-        set(core_directory_parent "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}")
-        set(core_directory "${core_directory_parent}/realm-core-${core_version}")
-
-        set(core_library_debug ${core_directory}/${library_directory}/${CMAKE_STATIC_LIBRARY_PREFIX}realm${platform}-dbg${CMAKE_STATIC_LIBRARY_SUFFIX})
-        set(core_library_release ${core_directory}/${library_directory}/${CMAKE_STATIC_LIBRARY_PREFIX}realm${platform}${CMAKE_STATIC_LIBRARY_SUFFIX})
-        set(core_parser_library_debug ${core_directory}/${library_directory}/${CMAKE_STATIC_LIBRARY_PREFIX}realm-parser${platform}-dbg${CMAKE_STATIC_LIBRARY_SUFFIX})
-        set(core_parser_library_release ${core_directory}/${library_directory}/${CMAKE_STATIC_LIBRARY_PREFIX}realm-parser${platform}${CMAKE_STATIC_LIBRARY_SUFFIX})
-        set(core_libraries ${core_library_debug} ${core_library_release} ${core_parser_library_debug} ${core_parser_library_release})
-
-        download_realm_tarball(${url} ${core_directory} "${core_libraries}")
-    endif()
-
-    add_custom_target(realm-core DEPENDS ${core_libraries})
-
-    add_library(realm STATIC IMPORTED)
-    add_dependencies(realm realm-core)
-    set_property(TARGET realm PROPERTY IMPORTED_LOCATION_DEBUG ${core_library_debug})
-    set_property(TARGET realm PROPERTY IMPORTED_LOCATION_COVERAGE ${core_library_debug})
-    set_property(TARGET realm PROPERTY IMPORTED_LOCATION_RELEASE ${core_library_release})
-    set_property(TARGET realm PROPERTY IMPORTED_LOCATION ${core_library_release})
-
-    set_property(TARGET realm PROPERTY INTERFACE_LINK_LIBRARIES ${CRYPTO_LIBRARIES} Threads::Threads)
-
-    # Create directories that are included in INTERFACE_INCLUDE_DIRECTORIES, as CMake requires they exist at
-    # configure time, when they'd otherwise not be created until we download and extract core.
-    file(MAKE_DIRECTORY ${core_directory}/include)
-    set_property(TARGET realm PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${core_directory}/include)
-
-    add_library(realm-parser STATIC IMPORTED)
-    add_dependencies(realm-parser realm-core)
-    set_property(TARGET realm-parser PROPERTY IMPORTED_LOCATION_DEBUG ${core_parser_library_debug})
-    set_property(TARGET realm-parser PROPERTY IMPORTED_LOCATION_COVERAGE ${core_parser_library_debug})
-    set_property(TARGET realm-parser PROPERTY IMPORTED_LOCATION_RELEASE ${core_parser_library_release})
-    set_property(TARGET realm-parser PROPERTY IMPORTED_LOCATION ${core_parser_library_release})
-endfunction()
-
-macro(build_realm_core)
-    set(core_prefix_directory "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/realm-core")
-
-    ExternalProject_Add(realm-core
-        PREFIX ${core_prefix_directory}
-        BUILD_IN_SOURCE 1
-        UPDATE_DISCONNECTED 1
-        INSTALL_COMMAND ""
-        CONFIGURE_COMMAND cmake -B build.debug -DOpenSSL_DIR=${CMAKE_BINARY_DIR}/openssl/lib/cmake/OpenSSL -D CMAKE_BUILD_TYPE=Debug ${CORE_SANITIZER_FLAGS} -G Ninja
-                       && cmake -B build.release -DOpenSSL_DIR=${CMAKE_BINARY_DIR}/openssl/lib/cmake/OpenSSL -D CMAKE_BUILD_TYPE=RelWithDebInfo ${CORE_SANITIZER_FLAGS} -G Ninja
-                       
-        BUILD_COMMAND cmake --build build.debug --target Storage --target QueryParser
-                   && cmake --build build.release --target Storage --target QueryParser
-
-        ${USES_TERMINAL_BUILD}
-        ${ARGN}
-        )
-    ExternalProject_Get_Property(realm-core SOURCE_DIR)
-
-    set(core_debug_binary_dir "${SOURCE_DIR}/build.debug")
-    set(core_release_binary_dir "${SOURCE_DIR}/build.release")
-    set(core_library_debug "${core_debug_binary_dir}/src/realm/${CMAKE_STATIC_LIBRARY_PREFIX}realm-dbg${CMAKE_STATIC_LIBRARY_SUFFIX}")
-    set(core_library_release "${core_release_binary_dir}/src/realm/${CMAKE_STATIC_LIBRARY_PREFIX}realm${CMAKE_STATIC_LIBRARY_SUFFIX}")
-    set(core_parser_library_debug "${core_debug_binary_dir}/src/realm/parser/${CMAKE_STATIC_LIBRARY_PREFIX}realm-parser-dbg${CMAKE_STATIC_LIBRARY_SUFFIX}")
-    set(core_parser_library_release "${core_release_binary_dir}/src/realm/parser/${CMAKE_STATIC_LIBRARY_PREFIX}realm-parser${CMAKE_STATIC_LIBRARY_SUFFIX}")
-
-    ExternalProject_Add_Step(realm-core ensure-libraries
-        DEPENDEES build
-        BYPRODUCTS ${core_library_debug} ${core_library_release}
-                   ${core_parser_library_debug} ${core_parser_library_release}
-        )
-
-    set(core_generated_headers_dir_debug "${core_debug_binary_dir}/src")
-    set(core_generated_headers_dir_release "${core_release_binary_dir}/src")
-
-    add_library(realm STATIC IMPORTED)
-    add_dependencies(realm realm-core)
-    set_property(TARGET realm PROPERTY IMPORTED_LOCATION_DEBUG ${core_library_debug})
-    set_property(TARGET realm PROPERTY IMPORTED_LOCATION_COVERAGE ${core_library_debug})
-    set_property(TARGET realm PROPERTY IMPORTED_LOCATION_RELEASE ${core_library_release})
-    set_property(TARGET realm PROPERTY IMPORTED_LOCATION ${core_library_release})
-
-    set_property(TARGET realm PROPERTY INTERFACE_LINK_LIBRARIES ${CRYPTO_LIBRARIES} Threads::Threads)
-
-    # Create directories that are included in INTERFACE_INCLUDE_DIRECTORIES, as CMake requires they exist at
-    # configure time, when they'd otherwise not be created until we download and build core.
-    file(MAKE_DIRECTORY "${core_generated_headers_dir_debug}" "${core_generated_headers_dir_release}" "${SOURCE_DIR}/src")
-
-    set_property(TARGET realm PROPERTY INTERFACE_INCLUDE_DIRECTORIES
-        ${SOURCE_DIR}/src
-        $<$<CONFIG:Debug>:${core_generated_headers_dir_debug}>
-        $<$<NOT:$<CONFIG:Debug>>:${core_generated_headers_dir_release}>
-    )
-
-    add_library(realm-parser STATIC IMPORTED)
-    add_dependencies(realm realm-core)
-    set_property(TARGET realm-parser PROPERTY IMPORTED_LOCATION_DEBUG ${core_parser_library_debug})
-    set_property(TARGET realm-parser PROPERTY IMPORTED_LOCATION_COVERAGE ${core_parser_library_debug})
-    set_property(TARGET realm-parser PROPERTY IMPORTED_LOCATION_RELEASE ${core_parser_library_release})
-    set_property(TARGET realm-parser PROPERTY IMPORTED_LOCATION ${core_parser_library_release})
-endmacro()
-
-function(clone_and_build_realm_core branch)
-    build_realm_core(GIT_REPOSITORY "https://github.com/realm/realm-core.git"
-                     GIT_TAG ${branch}
-                     )
-endfunction()
-
-function(build_existing_realm_core core_directory)
-    get_filename_component(core_directory ${core_directory} ABSOLUTE)
-
-    build_realm_core(SOURCE_DIR ${core_directory}
-                     URL ""
-                     BUILD_ALWAYS 1
-                     )
-endfunction()
-
-macro(build_realm_sync)
-    set(sync_prefix_directory "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/realm-sync")
-
-    ExternalProject_Get_Property(realm-core SOURCE_DIR)
-    set(core_directory ${SOURCE_DIR})
-
-    separate_arguments(sync_cfg_args UNIX_COMMAND "-DREALM_BUILD_DOGLESS=OFF ${CORE_SANITIZER_FLAGS} -G Ninja")
-    ExternalProject_Add(realm-sync-lib
-        DEPENDS realm-core
-        PREFIX ${sync_prefix_directory}
-        BUILD_IN_SOURCE 1
-        UPDATE_DISCONNECTED 1
-        INSTALL_COMMAND ""
-        CONFIGURE_COMMAND cmake -B build.debug -DCMAKE_BUILD_TYPE=Debug -DRealmCore_DIR=${core_directory}/build.debug ${sync_cfg_args}
-                       && cmake -B build.release -DCMAKE_BUILD_TYPE=RelWithDebInfo -DRealmCore_DIR=${core_directory}/build.release ${sync_cfg_args}
-        BUILD_COMMAND cmake --build build.debug --target Sync --target SyncServer
-                   && cmake --build build.release --target Sync --target SyncServer
-             ${USES_TERMINAL_BUILD}
-        ${ARGN}
-        )
-
-    ExternalProject_Get_Property(realm-sync-lib SOURCE_DIR)
-
-    set(sync_debug_binary_dir "${SOURCE_DIR}/build.debug")
-    set(sync_release_binary_dir "${SOURCE_DIR}/build.release")
-    set(sync_library_debug "${sync_debug_binary_dir}/src/realm/${CMAKE_STATIC_LIBRARY_PREFIX}realm-sync-dbg${CMAKE_STATIC_LIBRARY_SUFFIX}")
-    set(sync_library_release "${sync_release_binary_dir}/src/realm/${CMAKE_STATIC_LIBRARY_PREFIX}realm-sync${CMAKE_STATIC_LIBRARY_SUFFIX}")
-
-    ExternalProject_Add_Step(realm-sync-lib ensure-libraries
-        BYPRODUCTS ${sync_library_debug} ${sync_library_release}
-        DEPENDEES build
-        )
-
-    add_library(realm-sync STATIC IMPORTED)
-    add_dependencies(realm-sync realm-sync-lib)
-
-    set_property(TARGET realm-sync PROPERTY IMPORTED_LOCATION_DEBUG ${sync_library_debug})
-    set_property(TARGET realm-sync PROPERTY IMPORTED_LOCATION_COVERAGE ${sync_library_debug})
-    set_property(TARGET realm-sync PROPERTY IMPORTED_LOCATION_RELEASE ${sync_library_release})
-    set_property(TARGET realm-sync PROPERTY IMPORTED_LOCATION ${sync_library_release})
-
-    set_property(TARGET realm-sync PROPERTY INTERFACE_LINK_LIBRARIES ${SSL_LIBRARIES})
-
-    # Create directories that are included in INTERFACE_INCLUDE_DIRECTORIES, as CMake requires they exist at
-    # configure time, when they'd otherwise not be created until we download and build sync.
-    file(MAKE_DIRECTORY ${SOURCE_DIR}/src)
-    set_property(TARGET realm-sync PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${SOURCE_DIR}/src)
-
-    # Sync server library is built as part of the sync library build
-    set(sync_server_library_debug "${sync_debug_binary_dir}/src/realm/${CMAKE_STATIC_LIBRARY_PREFIX}realm-server-dbg${CMAKE_STATIC_LIBRARY_SUFFIX}")
-    set(sync_server_library_release "${sync_release_binary_dir}/src/realm/${CMAKE_STATIC_LIBRARY_PREFIX}realm-server${CMAKE_STATIC_LIBRARY_SUFFIX}")
-
-    ExternalProject_Add_Step(realm-sync-lib ensure-server-libraries
-        BYPRODUCTS ${sync_server_library_debug} ${sync_server_library_release}
-        DEPENDEES build
-        )
-
-    add_library(realm-sync-server STATIC IMPORTED)
-    add_dependencies(realm-sync-server realm-sync-lib)
-
-    set_property(TARGET realm-sync-server PROPERTY IMPORTED_LOCATION_DEBUG ${sync_server_library_debug})
-    set_property(TARGET realm-sync-server PROPERTY IMPORTED_LOCATION_COVERAGE ${sync_server_library_debug})
-    set_property(TARGET realm-sync-server PROPERTY IMPORTED_LOCATION_RELEASE ${sync_server_library_release})
-    set_property(TARGET realm-sync-server PROPERTY IMPORTED_LOCATION ${sync_server_library_release})
-
-    find_package(PkgConfig)
-    pkg_check_modules(YAML QUIET yaml-cpp)
-    set_property(TARGET realm-sync-server PROPERTY INTERFACE_LINK_LIBRARIES ${SSL_LIBRARIES} ${YAML_LDFLAGS})
-endmacro()
-
-function(build_existing_realm_sync sync_directory)
-    get_filename_component(sync_directory ${sync_directory} ABSOLUTE)
-    build_realm_sync(URL ""
-                     SOURCE_DIR ${sync_directory}
-                     BUILD_ALWAYS 1
-                     )
-
-endfunction()
-
-function(clone_and_build_realm_sync branch)
-    set(cmake_files ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY})
-
-    build_realm_sync(GIT_REPOSITORY "git@github.com:realm/realm-sync.git"
-                     GIT_TAG ${branch}
-                     CONFIGURE_COMMAND ${config_cmd}
-                     )
-
-endfunction()

+ 0 - 41
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/CMake/Sanitizers.cmake

@@ -1,41 +0,0 @@
-###########################################################################
-#
-# 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.
-#
-###########################################################################
-
-option(SANITIZE_ADDRESS "build with ASan")
-option(SANITIZE_THREAD "build with TSan")
-option(SANITIZE_UNDEFINED "build with UBSan")
-
-if(SANITIZE_ADDRESS)
-    set(SANITIZER_FLAGS "${SANITIZER_FLAGS} -fsanitize=address")
-    set(CORE_SANITIZER_FLAGS ${CORE_SANITIZER_FLAGS};-D;REALM_ASAN=ON)
-endif()
-
-if(SANITIZE_THREAD)
-    set(SANITIZER_FLAGS "${SANITIZER_FLAGS} -fsanitize=thread")
-    set(CORE_SANITIZER_FLAGS ${CORE_SANITIZER_FLAGS};-D;REALM_TSAN=ON)
-endif()
-
-if(SANITIZE_UNDEFINED)
-    set(SANITIZER_FLAGS "${SANITIZER_FLAGS} -fsanitize=undefined")
-    set(CORE_SANITIZER_FLAGS ${CORE_SANITIZER_FLAGS};-D;REALM_USAN=ON)
-endif()
-
-if(SANITIZE_ADDRESS OR SANITIZE_THREAD OR SANITIZE_UNDEFINED)
-    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${SANITIZER_FLAGS} -fno-omit-frame-pointer")
-    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${SANITIZER_FLAGS}")
-endif()

+ 0 - 46
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/CMakeLists.txt

@@ -1,46 +0,0 @@
-cmake_minimum_required(VERSION 3.2.0)
-
-if(REALM_PLATFORM STREQUAL "Android")
-    # This must be before project()
-    set(CMAKE_TOOLCHAIN_FILE "${ANDROID_NDK}/build/cmake/android.toolchain.cmake")
-    set(ANDROID_ABI "x86" CACHE STRING "")
-    set(ANDROID_NATIVE_API_LEVEL "android-16" CACHE STRING "")
-endif()
-
-set(CMAKE_BUILD_TYPE Debug CACHE STRING "")
-project(realm-object-store)
-
-list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake")
-
-include(CodeCoverage)
-include(CompilerFlags)
-include(Sanitizers)
-
-# Sync is disabled unless -DREALM_ENABLE_SYNC=1 is specified when invoking CMake.
-# FIXME: Flip the default once we can build against prebuilt sync binaries.
-set(REALM_ENABLE_SYNC OFF CACHE BOOL "")
-
-if(REALM_SYNC_PREFIX AND NOT REALM_CORE_PREFIX)
-    message(FATAL_ERROR "REALM_CORE_PREFIX must be set when specifying REALM_SYNC_PREFIX.")
-endif()
-if(REALM_SYNC_PREFIX AND NOT REALM_ENABLE_SYNC)
-    message(FATAL_ERROR "REALM_ENABLE_SYNC must be set when specifying REALM_SYNC_PREFIX.")
-endif()
-if(REALM_CORE_PREFIX AND REALM_ENABLE_SYNC AND NOT REALM_SYNC_PREFIX)
-    message(FATAL_ERROR "REALM_SYNC_PREFIX must be set when specifying REALM_CORE_PREFIX when REALM_ENABLE_SYNC is set.")
-endif()
-
-set(REALM_ENABLE_SERVER OFF CACHE BOOL "Enable the server-only functionality.")
-if(REALM_ENABLE_SERVER AND NOT REALM_ENABLE_SYNC)
-    message(FATAL_ERROR "REALM_ENABLE_SERVER requires REALM_ENABLE_SYNC.")
-endif()
-
-include(RealmCore)
-use_realm_core("${REALM_ENABLE_SYNC}" "${REALM_CORE_PREFIX}" "${REALM_SYNC_PREFIX}")
-
-if(REALM_ENABLE_SYNC)
-  add_definitions(-DREALM_ENABLE_SYNC)
-endif()
-
-add_subdirectory(src)
-add_subdirectory(tests)

+ 0 - 23
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/Dockerfile

@@ -1,23 +0,0 @@
-FROM ubuntu:xenial
-
-RUN apt-get update && \
-    apt-get install -y wget build-essential lcov curl cmake gcovr libprocps4-dev libssl-dev \
-      git python-cheetah libuv1-dev ninja-build adb xutils-dev
-
-# Install the Android NDK
-RUN mkdir -p /tmp/android-ndk && \
-    cd /tmp/android-ndk && \
-    wget -q http://dl.google.com/android/ndk/android-ndk-r10e-linux-x86_64.bin -O android-ndk.bin && \
-    chmod a+x ./android-ndk.bin && sync && ./android-ndk.bin && \
-    mv ./android-ndk-r10e /opt/android-ndk && \
-    chmod -R a+rX /opt/android-ndk && \
-    rm -rf /tmp/android-ndk
-
-ENV ANDROID_NDK_PATH /opt/android-ndk
-
-# Ensure a new enough version of CMake is available.
-RUN cd /opt \
-    && wget https://cmake.org/files/v3.15/cmake-3.15.2-Linux-x86_64.tar.gz \
-        && tar zxvf cmake-3.15.2-Linux-x86_64.tar.gz
-
-ENV PATH "/opt/cmake-3.15.2-Linux-x86_64/bin:$PATH"

+ 0 - 187
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/Jenkinsfile

@@ -1,187 +0,0 @@
-#!groovy
-
-@Library('realm-ci') _
-
-def getSourceArchive() {
-  deleteDir()
-  unstash 'source'
-}
-
-def readGitTag() {
-  sh "git describe --exact-match --tags HEAD | tail -n 1 > tag.txt 2>&1 || true"
-  def tag = readFile('tag.txt').trim()
-  return tag
-}
-
-def readGitSha() {
-  sh "git rev-parse HEAD | cut -b1-8 > sha.txt"
-  def sha = readFile('sha.txt').readLines().last().trim()
-  return sha
-}
-
-def buildDockerEnv(name, dockerfile='Dockerfile', extra_args='') {
-  docker.withRegistry("https://${env.DOCKER_REGISTRY}", "ecr:eu-west-1:aws-ci-user") {
-    sh "sh ./workflow/docker_build_wrapper.sh $name . ${extra_args}"
-  }
-  return docker.image(name)
-}
-
-def publishCoverageReport(String label) {
-  // Unfortunately, we cannot add a title or tag to individual coverage reports.
-  echo "Unstashing coverage-${label}"
-  unstash("coverage-${label}")
-
-  step([
-    $class: 'CoberturaPublisher',
-    autoUpdateHealth: false,
-    autoUpdateStability: false,
-    coberturaReportFile: "${label}.build/coverage.xml",
-    failNoReports: true,
-    failUnhealthy: false,
-    failUnstable: false,
-    maxNumberOfBuilds: 0,
-    onlyStable: false,
-    sourceEncoding: 'ASCII',
-    zoomCoverageChart: false
-  ])
-}
-
-if (env.BRANCH_NAME == 'master') {
-  env.DOCKER_PUSH = "1"
-}
-
-def doDockerBuild(String flavor, Boolean enableSync, String sanitizerFlags = "") {
-  def sync = enableSync ? "sync" : ""
-  def label = "${flavor}${enableSync ? '-sync' : ''}"
-
-  return {
-    node('docker') {
-      getSourceArchive()
-      def image = buildDockerEnv("ci/realm-object-store:${flavor}")
-      sshagent(['realm-ci-ssh']) {
-        image.inside("-v /etc/passwd:/etc/passwd:ro -v ${env.HOME}:${env.HOME} -v ${env.SSH_AUTH_SOCK}:${env.SSH_AUTH_SOCK} -e HOME=${env.HOME}") {
-          sh "./workflow/build.sh ${flavor} ${sync} ${sanitizerFlags}"
-        }
-      }
-    }
-  }
-}
-
-def doAndroidDockerBuild() {
-  return {
-    node('docker') {
-      getSourceArchive()
-      wrap([$class: 'AnsiColorBuildWrapper']) {
-        def image = docker.build('realm-object-store:ndk21', '-f android.Dockerfile .')
-        docker.image('tracer0tong/android-emulator').withRun { emulator ->
-          image.inside("--link ${emulator.id}:emulator") {
-            sh """
-              cmake -B build -DREALM_PLATFORM=Android -DANDROID_NDK=\${ANDROID_NDK} -GNinja -DCMAKE_MAKE_PROGRAM=ninja
-              cmake --build build
-              adb connect emulator
-              timeout 10m adb wait-for-device
-              adb push build/tests/tests /data/local/tmp
-              adb shell '/data/local/tmp/tests || echo __ADB_FAIL__' | tee adb.log
-              ! grep __ADB_FAIL__ adb.log
-            """
-          }
-        }
-      }
-    }
-  }
-}
-
-def doBuild(String nodeSpec, String flavor, Boolean enableSync, String version) {
-  def sync = enableSync ? "sync" : "false"
-  def label = "${flavor}${enableSync ? '-sync' : ''}"
-  return {
-    node(nodeSpec) {
-      getSourceArchive()
-      sshagent(['realm-ci-ssh']) {
-        sh "./workflow/test_coverage.sh ${sync} ${version} && mv coverage.build ${label}.build"
-      }
-      echo "Stashing coverage-${label}"
-      stash includes: "${label}.build/coverage.xml", name: "coverage-${label}"
-    }
-  }
-}
-
-def doWindowsBuild() {
-  return {
-    node('windows') {
-      getSourceArchive()
-
-      bat """
-        "${tool 'cmake'}" . -DCMAKE_SYSTEM_VERSION="8.1"
-        "${tool 'cmake'}" --build . --config Release
-        tests\\Release\\tests.exe
-      """
-    }
-  }
-}
-
-def doWindowsUniversalBuild() {
-  return {
-    node('windows') {
-      getSourceArchive()
-
-      bat """
-        "${tool 'cmake'}" . -DCMAKE_SYSTEM_NAME="WindowsStore" -DCMAKE_SYSTEM_VERSION="10.0"
-        "${tool 'cmake'}" --build . --config Release --target realm-object-store
-      """
-    }
-  }
-}
-
-def setBuildName(newBuildName) {
-  currentBuild.displayName = "${currentBuild.displayName} - ${newBuildName}"
-}
-
-stage('prepare') {
-  node('docker') {
-    checkout scm
-    sh 'git clean -ffdx -e .????????'
-    sshagent(['realm-ci-ssh']) {
-      sh 'git submodule update --init --recursive'
-    }
-
-    gitTag = readGitTag()
-    gitSha = readGitSha()
-    echo "tag: ${gitTag}"
-    if (gitTag == "") {
-      echo "No tag given for this build"
-      setBuildName("${gitSha}")
-    } else {
-      echo "Building release: '${gitTag}'"
-      setBuildName("Tag ${gitTag}")
-    }
-
-    stash includes: '**', name: 'source'
-  }
-}
-
-stage('unit-tests') {
-  parallel(
-    linux: doDockerBuild('linux', false),
-    linux_sync: doDockerBuild('linux', true),
-    linux_asan: doDockerBuild('linux', true, '-DSANITIZE_ADDRESS=1'),
-    linux_tsan: doDockerBuild('linux', true, '-DSANITIZE_THREAD=1'),
-    android: doAndroidDockerBuild(),
-    macos: doBuild('osx', 'macOS', false, ''),
-    macos_sync: doBuild('osx', 'macOS', true, ''),
-    win32: doWindowsBuild(),
-    windows_universal: doWindowsUniversalBuild()
-  )
-  currentBuild.result = 'SUCCESS'
-}
-
-stage('publish') {
-  node('docker') {
-    // we need sources to allow the coverage report to display them
-    rlmCheckout(scm)
-    // coverage reports assume sources are in the parent directory
-    dir("build") {
-      publishCoverageReport('macOS-sync')
-    }
-  }
-}

+ 0 - 269
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/LICENSE

@@ -1,269 +0,0 @@
-TABLE OF CONTENTS
-
-1. Apache License version 2.0
-2. Realm Components
-3. Export Compliance
-
--------------------------------------------------------------------------------
-
-                                 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.
-
-   END OF TERMS AND CONDITIONS
-
-   APPENDIX: How to apply the Apache License to your work.
-
-      To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "{}"
-      replaced with your own identifying information. (Don't include
-      the brackets!)  The text should be enclosed in the appropriate
-      comment syntax for the file format. We also recommend that a
-      file or class name and description of purpose be included on the
-      same "printed page" as the copyright notice for easier
-      identification within third-party archives.
-
-   Copyright {yyyy} {name of copyright owner}
-
-   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.
-
-
-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 Core component
-
-  Realm Core Binary License
-
-  Copyright (c) 2011-2016 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.
-
-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
-located in a country that is subject to United States export restriction or embargo,
-including Cuba, Iran, North Korea, Sudan, Syria or the Crimea region, and that you
-are not on the Department of Commerce list of Denied Persons, Unverified Parties,
-or affiliated with a Restricted Entity.
-
-You agree to comply with all export, re-export and import restrictions and
-regulations of the 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, the Software to any prohibited
-country, including Cuba, Iran, North Korea, Sudan, Syria or the Crimea region,
-or to any person or organization on or affiliated with the Department of
-Commerce lists of Denied Persons, Unverified Parties or Restricted Entities, or
-otherwise in violation of any such restrictions or regulations.

+ 0 - 4
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/dependencies.list

@@ -1,4 +0,0 @@
-REALM_CORE_VERSION=6.0.10
-REALM_SYNC_VERSION=5.0.9
-REALM_CORE_PACKAGING=2
-OPENSSL_VERSION=1.1.1b

+ 0 - 142
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/CMakeLists.txt

@@ -1,142 +0,0 @@
-set(SOURCES
-    binding_callback_thread_observer.cpp
-    collection_notifications.cpp
-    index_set.cpp
-    list.cpp
-    object.cpp
-    object_changeset.cpp
-    object_schema.cpp
-    object_store.cpp
-    results.cpp
-    schema.cpp
-    shared_realm.cpp
-    thread_safe_reference.cpp
-
-    impl/collection_change_builder.cpp
-    impl/collection_notifier.cpp
-    impl/list_notifier.cpp
-    impl/object_notifier.cpp
-    impl/realm_coordinator.cpp
-    impl/results_notifier.cpp
-    impl/transact_log_handler.cpp
-    impl/weak_realm_notifier.cpp
-    util/scheduler.cpp
-    util/uuid.cpp)
-
-set(HEADERS
-    binding_callback_thread_observer.hpp
-    collection_notifications.hpp
-    feature_checks.hpp
-    index_set.hpp
-    keypath_helpers.hpp
-    list.hpp
-    object.hpp
-    object_accessor.hpp
-    object_changeset.hpp
-    object_schema.hpp
-    object_store.hpp
-    property.hpp
-    results.hpp
-    schema.hpp
-    shared_realm.hpp
-    thread_safe_reference.hpp
-
-    impl/apple/external_commit_helper.hpp
-    impl/apple/keychain_helper.hpp
-    impl/epoll/external_commit_helper.hpp
-    impl/generic/external_commit_helper.hpp
-
-    impl/collection_change_builder.hpp
-    impl/collection_notifier.hpp
-    impl/external_commit_helper.hpp
-    impl/list_notifier.hpp
-    impl/notification_wrapper.hpp
-    impl/object_accessor_impl.hpp
-    impl/object_notifier.hpp
-    impl/realm_coordinator.hpp
-    impl/results_notifier.hpp
-    impl/transact_log_handler.hpp
-    impl/weak_realm_notifier.hpp
-
-    util/android/scheduler.hpp
-    util/apple/scheduler.hpp
-    util/generic/scheduler.hpp
-    util/uv/scheduler.hpp
-
-    util/aligned_union.hpp
-    util/atomic_shared_ptr.hpp
-    util/checked_mutex.hpp
-    util/copyable_atomic.hpp
-    util/event_loop_dispatcher.hpp
-    util/scheduler.hpp
-    util/tagged_bool.hpp
-    util/uuid.hpp)
-
-if(APPLE)
-    list(APPEND SOURCES impl/apple/external_commit_helper.cpp impl/apple/keychain_helper.cpp)
-elseif(REALM_HAVE_EPOLL)
-    list(APPEND SOURCES impl/epoll/external_commit_helper.cpp)
-elseif(CMAKE_SYSTEM_NAME MATCHES "^Windows")
-    list(APPEND SOURCES impl/windows/external_commit_helper.cpp)
-else()
-    list(APPEND SOURCES impl/generic/external_commit_helper.cpp)
-endif()
-
-set(INCLUDE_DIRS
-    ${UV_INCLUDE_DIR}
-    ${CMAKE_CURRENT_SOURCE_DIR})
-
-if(REALM_ENABLE_SYNC)
-    list(APPEND HEADERS
-        sync/async_open_task.hpp
-        sync/partial_sync.hpp
-        sync/subscription_state.hpp
-        sync/sync_config.hpp
-        sync/sync_manager.hpp
-        sync/sync_session.hpp
-        sync/sync_user.hpp
-        sync/impl/sync_client.hpp
-        sync/impl/sync_file.hpp
-        sync/impl/sync_metadata.hpp
-        sync/impl/work_queue.hpp)
-    list(APPEND SOURCES
-        sync/async_open_task.cpp
-        sync/partial_sync.cpp
-        sync/sync_config.cpp
-        sync/sync_manager.cpp
-        sync/sync_session.cpp
-        sync/sync_user.cpp
-        sync/impl/sync_file.cpp
-        sync/impl/sync_metadata.cpp
-        sync/impl/work_queue.cpp)
-    if(APPLE)
-        list(APPEND SOURCES
-            sync/impl/apple/network_reachability_observer.cpp
-            sync/impl/apple/system_configuration.cpp)
-    endif()
-    find_package(ZLIB REQUIRED)
-    list(APPEND INCLUDE_DIRS ${ZLIB_INCLUDE_DIRS})
-endif()
-
-if(REALM_ENABLE_SERVER)
-    list(APPEND HEADERS
-        server/adapter.hpp
-        server/admin_realm.hpp
-        server/global_notifier.hpp)
-    list(APPEND SOURCES
-        server/adapter.cpp
-        server/admin_realm.cpp
-        server/global_notifier.cpp)
-    list(APPEND INCLUDE_DIRS ../external/json)
-endif()
-
-add_library(realm-object-store STATIC ${SOURCES} ${HEADERS})
-set_target_properties(realm-object-store PROPERTIES POSITION_INDEPENDENT_CODE 1)
-target_compile_definitions(realm-object-store PRIVATE ${PLATFORM_DEFINES})
-target_include_directories(realm-object-store PUBLIC ${INCLUDE_DIRS})
-target_link_libraries(realm-object-store PUBLIC realm ${PLATFORM_LIBRARIES})
-
-if(REALM_ENABLE_SYNC)
-    # Add the sync libraries separately to reduce merge conflicts.
-    target_link_libraries(realm-object-store PUBLIC realm-sync ${ZLIB_LIBRARIES})
-endif()

+ 0 - 23
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/binding_callback_thread_observer.cpp

@@ -1,23 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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;
-}

+ 0 - 42
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/binding_callback_thread_observer.hpp

@@ -1,42 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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_OS_BINDING_CALLBACK_THREAD_OBSERVER_HPP
-#define REALM_OS_BINDING_CALLBACK_THREAD_OBSERVER_HPP
-
-#include <exception>
-
-namespace realm {
-// Interface for bindings interested in registering callbacks before/after the ObjectStore thread runs.
-// This is for example helpful to attach/detach the pthread to the JavaVM in order to be able to perform JNI calls.
-class BindingCallbackThreadObserver {
-public:
-    // This method is called just before the thread is started
-    virtual void did_create_thread() = 0;
-
-    // This method is called just before the thread is being destroyed
-    virtual void will_destroy_thread() = 0;
-
-    // This method is called with any exception throws by client.run().
-    virtual void handle_error(std::exception const& e) = 0;
-};
-
-extern BindingCallbackThreadObserver* g_binding_callback_thread_observer;
-}
-
-#endif // REALM_OS_BINDING_CALLBACK_THREAD_OBSERVER_HPP

+ 0 - 180
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/binding_context.hpp

@@ -1,180 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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 BINDING_CONTEXT_HPP
-#define BINDING_CONTEXT_HPP
-
-#include "index_set.hpp"
-
-#include <realm/keys.hpp>
-
-#include <memory>
-#include <tuple>
-#include <unordered_map>
-#include <vector>
-
-namespace realm {
-// BindingContext is the extension point for adding binding-specific behavior to
-// a SharedRealm. It can be used to store additional data associated with the
-// Realm which is needed by the binding, and there are several methods which
-// can be overridden to receive notifications of state changes within the Realm.
-//
-// A simple implementation which lets the user register functions to be
-// called on refresh could look like the following:
-//
-// class BindingContextImplementation : public BindingContext {
-// public:
-//     // A token returned from add_notification that can be used to remove the
-//     // notification later
-//     struct token : private std::list<std::function<void ()>>::iterator {
-//         token(std::list<std::function<void ()>>::iterator it) : std::list<std::function<void ()>>::iterator(it) { }
-//         friend class DelegateImplementation;
-//     };
-//
-//     token add_notification(std::function<void ()> func)
-//     {
-//         m_registered_notifications.push_back(std::move(func));
-//         return token(std::prev(m_registered_notifications.end()));
-//     }
-//
-//     void remove_notification(token entry)
-//     {
-//         m_registered_notifications.erase(entry);
-//     }
-//
-//     // Override the did_change method to call each registered notification
-//     void did_change(std::vector<ObserverState> const&, std::vector<void*> const&, bool) override
-//     {
-//         // Loop oddly so that unregistering a notification from within the
-//         // registered function works
-//         for (auto it = m_registered_notifications.begin(); it != m_registered_notifications.end(); ) {
-//             (*it++)();
-//         }
-//     }
-//
-// private:
-//     std::list<std::function<void ()>> m_registered_notifications;
-// };
-class Realm;
-class Schema;
-class BindingContext {
-public:
-    virtual ~BindingContext() = default;
-
-    std::weak_ptr<Realm> realm;
-
-    // Called when the Realm is about to send notifications about Realm,
-    // Collection or Object changes. This method will be called even if
-    // no notification callbacks have been registered.
-    virtual void will_send_notifications() { }
-
-    // Called when the Realm is done sending all change notifications. This method
-    // will be called even if no notification callbacks have been registered.
-    virtual void did_send_notifications() { }
-
-    // Called by the Realm when refresh called or a notification arrives which
-    // is triggered through write transaction committed by itself or a different
-    // Realm instance.
-    virtual void before_notify() { }
-
-    // Called by the Realm when a write transaction is committed to the file by
-    // a different Realm instance (possibly in a different process)
-    virtual void changes_available() { }
-
-    struct ObserverState;
-
-    // Override this function if you want to receive detailed information about
-    // external changes to a specific set of objects.
-    // This is called before each operation which may advance the read
-    // transaction to include
-    // ObserverStates for each row for which detailed change information is
-    // desired.
-    virtual std::vector<ObserverState> get_observed_rows() { return {}; }
-
-    // Called immediately before the read transaction is advanced if detailed
-    // change information was requested (by returning a non-empty array from
-    // get_observed_rows()).
-    // The observers vector is the vector returned by get_observed_row(),
-    // updated with change information. The invalidated vector is a list of the
-    // `info` fields of observed rows which will be deleted.
-    virtual void will_change(std::vector<ObserverState> const& observers,
-                             std::vector<void*> const& invalidated);
-
-    // Called immediately after the read transaction version is advanced. Unlike
-    // will_change(), this is called even if detailed change information was not
-    // requested or if the Realm is not actually in a read transaction, although
-    // both vectors will be empty in that case.
-    virtual void did_change(std::vector<ObserverState> const& observers,
-                            std::vector<void*> const& invalidated,
-                            bool version_changed=true);
-
-    // Called immediately after the corresponding Realm's schema is changed through
-    // update_schema()/set_schema_subset() or the schema is changed by another Realm
-    // instance. The parameter is a schema reference which is the same as the return
-    // value of Realm::schema().
-    virtual void schema_did_change(Schema const&) {}
-
-    // Change information for a single field of a row
-    struct ColumnInfo {
-        // What kind of change occurred?
-        // Always Set or None for everything but LinkList columns.
-        enum class Kind {
-            None,   // No change
-            Set,    // The value or entries at `indices` were assigned to
-            Insert, // New values were inserted at each of the indices given
-            Remove, // Values were removed at each of the indices given
-            SetAll  // The entire LinkList has been replaced with a new set of values
-        } kind = Kind::None;
-        // The indices where things happened for Set, Insert and Remove on
-        // LinkList columns. Not used for other types or for None or SetAll.
-        IndexSet indices;
-    };
-
-    // Information about an observed row in a table
-    //
-    // Each object which needs detailed change information should have an
-    // ObserverState entry in the vector returned from get_observed_rows(), with
-    // the initial table and row indexes set (and optionally the info field).
-    // The Realm parses the transaction log, and populates the `changes` vector
-    // in each ObserverState with information about what changes were made.
-    struct ObserverState {
-        // Table and row which is observed
-        realm::TableKey table_key;
-        int64_t obj_key;
-
-        // Opaque userdata for the delegate's use
-        void* info;
-
-        // Populated with information about which columns were changed
-        // May be shorter than the actual number of columns if the later columns
-        // are not modified
-        std::unordered_map<int64_t, ColumnInfo> changes;
-
-        // Simple lexographic ordering
-        friend bool operator<(ObserverState const& lft, ObserverState const& rgt)
-        {
-            return std::tie(lft.table_key, lft.obj_key) < std::tie(rgt.table_key, rgt.obj_key);
-        }
-    };
-};
-
-inline void BindingContext::will_change(std::vector<ObserverState> const&, std::vector<void*> const&) { }
-inline void BindingContext::did_change(std::vector<ObserverState> const&, std::vector<void*> const&, bool) { }
-} // namespace realm
-
-#endif /* BINDING_CONTEXT_HPP */

+ 0 - 61
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/collection_notifications.cpp

@@ -1,61 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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);
-}

+ 0 - 183
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/collection_notifications.hpp

@@ -1,183 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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_COLLECTION_NOTIFICATIONS_HPP
-#define REALM_COLLECTION_NOTIFICATIONS_HPP
-
-#include "index_set.hpp"
-#include "util/atomic_shared_ptr.hpp"
-
-#include <exception>
-#include <memory>
-#include <type_traits>
-#include <unordered_map>
-#include <vector>
-
-namespace realm {
-namespace _impl {
-    class CollectionNotifier;
-}
-
-// A token which keeps an asynchronous query alive
-struct NotificationToken {
-    NotificationToken() = default;
-    NotificationToken(std::shared_ptr<_impl::CollectionNotifier> notifier, uint64_t token);
-    ~NotificationToken();
-
-    NotificationToken(NotificationToken&&);
-    NotificationToken& operator=(NotificationToken&&);
-
-    NotificationToken(NotificationToken const&) = delete;
-    NotificationToken& operator=(NotificationToken const&) = delete;
-
-    void suppress_next();
-
-private:
-    util::AtomicSharedPtr<_impl::CollectionNotifier> m_notifier;
-    uint64_t m_token;
-};
-
-struct CollectionChangeSet {
-    struct Move {
-        size_t from;
-        size_t to;
-
-        bool operator==(Move m) const noexcept { return from == m.from && to == m.to; }
-    };
-
-    // Indices which were removed from the _old_ collection
-    IndexSet deletions;
-
-    // Indices in the _new_ collection which are new insertions
-    IndexSet insertions;
-
-    // Indices of objects in the _old_ collection which were modified
-    IndexSet modifications;
-
-    // Indices in the _new_ collection which were modified. This will always
-    // have the same number of indices as `modifications` and conceptually
-    // represents the same entries, just in different versions of the collection.
-    // It exists for the sake of code which finds it easier to process
-    // modifications after processing deletions and insertions rather than before.
-    IndexSet modifications_new;
-
-    // Rows in the collection which moved.
-    //
-    // Every `from` index will also be present in `deletions` and every `to`
-    // index will be present in `insertions`.
-    //
-    // This is currently not reliably calculated for all types of collections. A
-    // reported move will always actually be a move, but there may also be
-    // unreported moves which show up only as a delete/insert pair.
-    std::vector<Move> moves;
-
-    // Per-column version of `modifications`
-    std::unordered_map<int64_t, IndexSet> columns;
-
-    bool empty() const noexcept
-    {
-        return deletions.empty() && insertions.empty() && modifications.empty()
-            && modifications_new.empty() && moves.empty();
-    }
-};
-
-// A type-erasing wrapper for the callback for collection notifications. Can be
-// constructed with either any callable compatible with the signature
-// `void (CollectionChangeSet, std::exception_ptr)`, an object with member
-// functions `void before(CollectionChangeSet)`, `void after(CollectionChangeSet)`,
-// `void error(std::exception_ptr)`, or a pointer to such an object. If a pointer
-// is given, the caller is responsible for ensuring that the pointed-to object
-// outlives the collection.
-class CollectionChangeCallback {
-public:
-    CollectionChangeCallback(std::nullptr_t={}) { }
-
-    template<typename Callback>
-    CollectionChangeCallback(Callback cb) : m_impl(make_impl(std::move(cb))) { }
-    template<typename Callback>
-    CollectionChangeCallback& operator=(Callback cb) { m_impl = make_impl(std::move(cb)); return *this; }
-
-    // Explicitly default the copy/move constructors as otherwise they'll use
-    // the above ones and add an extra layer of wrapping
-    CollectionChangeCallback(CollectionChangeCallback&&) = default;
-    CollectionChangeCallback(CollectionChangeCallback const&) = default;
-    CollectionChangeCallback& operator=(CollectionChangeCallback&&) = default;
-    CollectionChangeCallback& operator=(CollectionChangeCallback const&) = default;
-
-    void before(CollectionChangeSet const& c) { m_impl->before(c); }
-    void after(CollectionChangeSet const& c) { m_impl->after(c); }
-    void error(std::exception_ptr e) { m_impl->error(e); }
-
-    explicit operator bool() const { return !!m_impl; }
-
-private:
-    struct Base {
-        virtual ~Base() {}
-        virtual void before(CollectionChangeSet const&)=0;
-        virtual void after(CollectionChangeSet const&)=0;
-        virtual void error(std::exception_ptr)=0;
-    };
-
-    template<typename Callback, typename = decltype(std::declval<Callback>()(CollectionChangeSet(), std::exception_ptr()))>
-    std::shared_ptr<Base> make_impl(Callback cb)
-    {
-        return std::make_shared<Impl<Callback>>(std::move(cb));
-    }
-
-    template<typename Callback, typename = decltype(std::declval<Callback>().after(CollectionChangeSet())), typename = void>
-    std::shared_ptr<Base> make_impl(Callback cb)
-    {
-        return std::make_shared<Impl2<Callback>>(std::move(cb));
-    }
-
-    template<typename Callback, typename = decltype(std::declval<Callback>().after(CollectionChangeSet())), typename = void>
-    std::shared_ptr<Base> make_impl(Callback* cb)
-    {
-        return std::make_shared<Impl3<Callback>>(cb);
-    }
-
-    template<typename T>
-    struct Impl : public Base {
-        T impl;
-        Impl(T impl) : impl(std::move(impl)) { }
-        void before(CollectionChangeSet const&) override { }
-        void after(CollectionChangeSet const& change) override { impl(change, {}); }
-        void error(std::exception_ptr error) override { impl({}, error); }
-    };
-    template<typename T>
-    struct Impl2 : public Base {
-        T impl;
-        Impl2(T impl) : impl(std::move(impl)) { }
-        void before(CollectionChangeSet const& c) override { impl.before(c); }
-        void after(CollectionChangeSet const& c) override { impl.after(c); }
-        void error(std::exception_ptr error) override { impl.error(error); }
-    };
-    template<typename T>
-    struct Impl3 : public Base {
-        T* impl;
-        Impl3(T* impl) : impl(impl) { }
-        void before(CollectionChangeSet const& c) override { impl->before(c); }
-        void after(CollectionChangeSet const& c) override { impl->after(c); }
-        void error(std::exception_ptr error) override { impl->error(error); }
-    };
-
-    std::shared_ptr<Base> m_impl;
-};
-} // namespace realm
-
-#endif // REALM_COLLECTION_NOTIFICATIONS_HPP

+ 0 - 30
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/feature_checks.hpp

@@ -1,30 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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_OS_FEATURE_CHECKS_HPP
-#define REALM_OS_FEATURE_CHECKS_HPP
-
-#include <realm/version.hpp>
-
-#if REALM_ENABLE_SYNC
-
-#include <realm/sync/version.hpp>
-
-#endif // REALM_ENABLE_SYNC
-
-#endif // REALM_OS_FEATURE_CHECKS_HPP

+ 0 - 243
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/apple/external_commit_helper.cpp

@@ -1,243 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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 <realm/db_options.hpp>
-#include <realm/util/fifo_helper.hpp>
-
-#include <asl.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <sstream>
-#include <sys/event.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <system_error>
-#include <unistd.h>
-
-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<std::string>()(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<std::string>()(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);
-    }
-}

+ 0 - 80
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/apple/external_commit_helper.hpp

@@ -1,80 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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 <thread>
-
-namespace realm {
-class Realm;
-
-namespace _impl {
-class RealmCoordinator;
-
-class ExternalCommitHelper {
-public:
-    ExternalCommitHelper(RealmCoordinator& parent);
-    ~ExternalCommitHelper();
-
-    void notify_others();
-
-private:
-    // A RAII holder for a file descriptor which automatically closes the wrapped
-    // fd when it's deallocated
-    class FdHolder {
-    public:
-        FdHolder() = default;
-        ~FdHolder() { close(); }
-        operator int() const { return m_fd; }
-
-        FdHolder& operator=(int newFd) {
-            close();
-            m_fd = newFd;
-            return *this;
-        }
-
-    private:
-        int m_fd = -1;
-        void close();
-
-        FdHolder& operator=(FdHolder const&) = delete;
-        FdHolder(FdHolder const&) = delete;
-    };
-
-    void listen();
-
-    RealmCoordinator& m_parent;
-
-    // The listener thread
-    std::thread m_thread;
-
-    // Pipe which is waited on for changes and written to when there is a new
-    // commit to notify others of. When using a named pipe m_notify_fd is
-    // read-write and m_notify_fd_write is unused; when using an anonymous pipe
-    // (on tvOS) m_notify_fd is read-only and m_notify_fd_write is write-only.
-    FdHolder m_notify_fd;
-    FdHolder m_notify_fd_write;
-
-    // File descriptor for the kqueue
-    FdHolder m_kq;
-
-    // The two ends of an anonymous pipe used to notify the kqueue() thread that
-    // it should be shut down.
-    FdHolder m_shutdown_read_fd;
-    FdHolder m_shutdown_write_fd;
-};
-} // namespace _impl
-} // namespace realm

+ 0 - 143
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/apple/keychain_helper.cpp

@@ -1,143 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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 <realm/util/cf_ptr.hpp>
-#include <realm/util/optional.hpp>
-
-#include <Security/Security.h>
-
-#include <string>
-
-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<CFStringRef> convert_string(const std::string& string)
-{
-    auto result = adoptCF(CFStringCreateWithBytes(nullptr, reinterpret_cast<const UInt8*>(string.data()),
-                                                  string.size(), kCFStringEncodingASCII, false));
-    if (!result) {
-        throw std::bad_alloc();
-    }
-    return result;
-}
-#endif
-
-CFPtr<CFMutableDictionaryRef> build_search_dictionary(CFStringRef account, CFStringRef service,
-                                                      __unused util::Optional<std::string> 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<std::vector<char>> 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<CFDataRef> 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<const char *>(CFDataGetBytePtr(key_data.get()));
-    return std::vector<char>(key_bytes, key_bytes + key_size);
-}
-
-void set_key(const std::vector<char>& 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<const UInt8 *>(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<char> metadata_realm_encryption_key(bool check_legacy_service)
-{
-    CFStringRef account = CFSTR("metadata");
-    CFStringRef legacy_service = CFSTR("io.realm.sync.keychain");
-
-    CFPtr<CFStringRef> 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<char> key(key_size);
-    arc4random_buf(key.data(), key_size);
-    set_key(key, account, service.get());
-    return key;
-}
-
-}   // keychain
-}   // realm

+ 0 - 39
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/apple/keychain_helper.hpp

@@ -1,39 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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_OS_KEYCHAIN_HELPER_HPP
-#define REALM_OS_KEYCHAIN_HELPER_HPP
-
-#include <cstdint>
-#include <stdexcept>
-#include <vector>
-
-namespace realm {
-namespace keychain {
-
-std::vector<char> metadata_realm_encryption_key(bool check_legacy_service);
-
-class KeychainAccessException : public std::runtime_error {
-public:
-    KeychainAccessException(int32_t error_code);
-};
-
-}
-}
-
-#endif // REALM_OS_KEYCHAIN_HELPER_HPP

+ 0 - 673
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/collection_change_builder.cpp

@@ -1,673 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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 <realm/util/assert.hpp>
-
-#include <algorithm>
-
-using namespace realm;
-using namespace realm::_impl;
-
-CollectionChangeBuilder::CollectionChangeBuilder(IndexSet deletions,
-                                                 IndexSet insertions,
-                                                 IndexSet modifications,
-                                                 std::vector<Move> 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<int64_t> 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<typename Func>
-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<RowInfo>& 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<Match> m_longest_matches;
-
-    LongestCommonSubsequenceCalculator(std::vector<Row>& a, std::vector<Row>& 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<Row> &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<Length> prev;
-        // The length of the matching block for each `j` for the row currently being checked
-        std::vector<Length> 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<RowInfo>& 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<LongestCommonSubsequenceCalculator::Row> 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<typename T>
-void verify_changeset(std::vector<T> const& prev_rows,
-                      std::vector<T> 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<void>(prev_rows);
-    static_cast<void>(next_rows);
-    static_cast<void>(changeset);
-#endif
-}
-
-void calculate(CollectionChangeBuilder& ret,
-               std::vector<RowInfo> old_rows, std::vector<RowInfo> new_rows,
-               std::function<bool (int64_t)> 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<int64_t> const& prev_rows,
-                                                           std::vector<int64_t> const& next_rows,
-                                                           std::function<bool (int64_t)> key_did_change,
-                                                           bool in_table_order)
-{
-
-    auto build_row_info = [](auto& rows) {
-        std::vector<RowInfo> 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<size_t> const& prev_rows,
-                                                           std::vector<size_t> const& next_rows,
-                                                           std::function<bool (int64_t)> key_did_change)
-{
-
-    auto build_row_info = [](auto& rows) {
-        std::vector<RowInfo> info;
-        info.reserve(rows.size());
-        for (size_t i = 0; i < rows.size(); ++i)
-            info.push_back({static_cast<int64_t>(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)
-    };
-}

+ 0 - 81
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/collection_change_builder.hpp

@@ -1,81 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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_COLLECTION_CHANGE_BUILDER_HPP
-#define REALM_COLLECTION_CHANGE_BUILDER_HPP
-
-#include "collection_notifications.hpp"
-
-#include <realm/keys.hpp>
-
-#include <functional>
-#include <unordered_set>
-#include <vector>
-
-namespace realm {
-namespace _impl {
-
-class CollectionChangeBuilder : public CollectionChangeSet {
-public:
-    CollectionChangeBuilder(CollectionChangeBuilder const&) = default;
-    CollectionChangeBuilder(CollectionChangeBuilder&&) = default;
-    CollectionChangeBuilder& operator=(CollectionChangeBuilder const&) = default;
-    CollectionChangeBuilder& operator=(CollectionChangeBuilder&&) = default;
-
-    CollectionChangeBuilder(IndexSet deletions = {},
-                            IndexSet insertions = {},
-                            IndexSet modification = {},
-                            std::vector<Move> moves = {});
-
-    // Calculate where rows need to be inserted or deleted from old_rows to turn
-    // it into new_rows, and check all matching rows for modifications
-    static CollectionChangeBuilder calculate(std::vector<int64_t> const& old_rows,
-                                             std::vector<int64_t> const& new_rows,
-                                             std::function<bool (int64_t)> key_did_change,
-                                             bool in_table_order);
-    static CollectionChangeBuilder calculate(std::vector<size_t> const& old_rows,
-                                             std::vector<size_t> const& new_rows,
-                                             std::function<bool (int64_t)> key_did_change);
-
-    // generic operations {
-    CollectionChangeSet finalize() &&;
-    void merge(CollectionChangeBuilder&&);
-
-    void insert(size_t ndx, size_t count=1, bool track_moves=true);
-    void modify(size_t ndx, size_t col=-1);
-    void erase(size_t ndx);
-    void clear(size_t old_size);
-    // }
-
-    // operations only implemented for LinkList semantics {
-    void clean_up_stale_moves();
-    void move(size_t from, size_t to);
-    // }
-
-private:
-    bool m_track_columns = true;
-
-    template<typename Func>
-    void for_each_col(Func&& f);
-
-    void verify();
-};
-} // namespace _impl
-} // namespace realm
-
-#endif // REALM_COLLECTION_CHANGE_BUILDER_HPP

+ 0 - 500
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/collection_notifier.cpp

@@ -1,500 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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 <realm/db.hpp>
-
-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<bool (ObjectChangeSet::ObjectKeyType)>
-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<RelatedTable>& 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<RelatedTable> 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<ObjKey>(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> 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<std::mutex> 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<CollectionNotifier::Callback>::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<std::mutex> lock(m_realm_mutex);
-    m_realm = nullptr;
-}
-
-bool CollectionNotifier::is_alive() const noexcept
-{
-    std::lock_guard<std::mutex> lock(m_realm_mutex);
-    return m_realm != nullptr;
-}
-
-std::unique_lock<std::mutex> CollectionNotifier::lock_target()
-{
-    return std::unique_lock<std::mutex>{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<std::mutex> 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<typename Fn>
-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<Transaction> 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<std::shared_ptr<CollectionNotifier>> 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<VersionID::version_type> 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<CollectionNotifier> notifier)
-{
-    m_notifiers.push_back(notifier);
-    m_coordinator->register_notifier(notifier);
-}

+ 0 - 353
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/collection_notifier.hpp

@@ -1,353 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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_BACKGROUND_COLLECTION_HPP
-#define REALM_BACKGROUND_COLLECTION_HPP
-
-#include "object_changeset.hpp"
-#include "impl/collection_change_builder.hpp"
-#include "util/checked_mutex.hpp"
-
-#include <realm/util/assert.hpp>
-#include <realm/version_id.hpp>
-#include <realm/keys.hpp>
-#include <realm/table_ref.hpp>
-
-#include <array>
-#include <atomic>
-#include <exception>
-#include <functional>
-#include <mutex>
-#include <unordered_map>
-#include <unordered_set>
-
-namespace realm {
-class Realm;
-class Transaction;
-
-namespace _impl {
-class RealmCoordinator;
-
-struct ListChangeInfo {
-    TableKey table_key;
-    int64_t row_key;
-    int64_t col_key;
-    CollectionChangeBuilder* changes;
-};
-
-// FIXME: this should be in core
-using TableKeyType = decltype(TableKey::value);
-using ObjKeyType = decltype(ObjKey::value);
-
-struct TransactionChangeInfo {
-    std::vector<ListChangeInfo> lists;
-    std::unordered_map<TableKeyType, ObjectChangeSet> tables;
-    bool track_all;
-    bool schema_changed;
-};
-
-class DeepChangeChecker {
-public:
-    struct OutgoingLink {
-        int64_t col_key;
-        bool is_list;
-    };
-    struct RelatedTable {
-        TableKey table_key;
-        std::vector<OutgoingLink> links;
-    };
-
-    DeepChangeChecker(TransactionChangeInfo const& info, Table const& root_table,
-                      std::vector<RelatedTable> const& related_tables);
-
-    bool operator()(int64_t obj_key);
-
-    // Recursively add `table` and all tables it links to to `out`, along with
-    // information about the links from them
-    static void find_related_tables(std::vector<RelatedTable>& out, Table const& table);
-
-private:
-    TransactionChangeInfo const& m_info;
-    Table const& m_root_table;
-    const TableKey m_root_table_key;
-    ObjectChangeSet const* const m_root_object_changes;
-    std::unordered_map<TableKeyType, std::unordered_set<ObjKeyType>> m_not_modified;
-    std::vector<RelatedTable> const& m_related_tables;
-
-    struct Path {
-        int64_t obj_key;
-        int64_t col_key;
-        bool depth_exceeded;
-    };
-    std::array<Path, 4> m_current_path;
-
-    bool check_row(Table const& table, ObjKeyType obj_key, size_t depth = 0);
-    bool check_outgoing_links(TableKey table_key, Table const& table,
-                              int64_t obj_key, size_t depth = 0);
-};
-
-// A base class for a notifier that keeps a collection up to date and/or
-// generates detailed change notifications on a background thread. This manages
-// most of the lifetime-management issues related to sharing an object between
-// the worker thread and the collection on the target thread, along with the
-// thread-safe callback collection.
-class CollectionNotifier {
-public:
-    CollectionNotifier(std::shared_ptr<Realm>);
-    virtual ~CollectionNotifier();
-
-    // ------------------------------------------------------------------------
-    // Public API for the collections using this to get notifications:
-
-    // Stop receiving notifications from this background worker
-    // This must be called in the destructor of the collection
-    void unregister() noexcept;
-
-    // Add a callback to be called each time the collection changes
-    // This can only be called from the target collection's thread
-    // Returns a token which can be passed to remove_callback()
-    uint64_t add_callback(CollectionChangeCallback callback) REQUIRES(!m_callback_mutex);
-    // Remove a previously added token. The token is no longer valid after
-    // calling this function and must not be used again. This function can be
-    // called from any thread.
-    void remove_callback(uint64_t token) REQUIRES(!m_callback_mutex);
-
-    void suppress_next_notification(uint64_t token) REQUIRES(!m_callback_mutex);
-
-    // ------------------------------------------------------------------------
-    // API for RealmCoordinator to manage running things and calling callbacks
-
-    bool is_for_realm(Realm&) const noexcept;
-    Realm* get_realm() const noexcept { return m_realm.get(); }
-
-    // Get the Transaction version which this collection can attach to (if it's
-    // in handover mode), or can deliver to (if it's been handed over to the BG worker alredad)
-    // precondition: RealmCoordinator::m_notifier_mutex is locked
-    VersionID version() const noexcept { return m_sg_version; }
-
-    // Release references to all core types
-    // This is called on the worker thread to ensure that non-thread-safe things
-    // can be destroyed on the correct thread, even if the last reference to the
-    // CollectionNotifier is released on a different thread
-    virtual void release_data() noexcept;
-
-    // Prepare to deliver the new collection and call callbacks.
-    // Returns whether or not it has anything to deliver.
-    // precondition: RealmCoordinator::m_notifier_mutex is locked
-    bool package_for_delivery() REQUIRES(!m_callback_mutex);
-
-    // Pass the given error to all registered callbacks, then remove them
-    // precondition: RealmCoordinator::m_notifier_mutex is unlocked
-    void deliver_error(std::exception_ptr) REQUIRES(!m_callback_mutex);
-
-    // Call each of the given callbacks with the changesets prepared by package_for_delivery()
-    // precondition: RealmCoordinator::m_notifier_mutex is unlocked
-    void before_advance() REQUIRES(!m_callback_mutex);
-    void after_advance() REQUIRES(!m_callback_mutex);
-
-    bool is_alive() const noexcept;
-
-    // precondition: RealmCoordinator::m_notifier_mutex is locked *or* is called on worker thread
-    bool has_run() const noexcept { return m_has_run; }
-
-    // Attach the handed-over query to `sg`. Must not be already attached to a Transaction.
-    // precondition: RealmCoordinator::m_notifier_mutex is locked
-    void attach_to(std::shared_ptr<Transaction> sg);
-
-    // Set `info` as the new ChangeInfo that will be populated by the next
-    // transaction advance, and register all required information in it
-    // precondition: RealmCoordinator::m_notifier_mutex is locked
-    void add_required_change_info(TransactionChangeInfo& info);
-
-    // precondition: RealmCoordinator::m_notifier_mutex is unlocked
-    virtual void run() = 0;
-
-    // precondition: RealmCoordinator::m_notifier_mutex is locked
-    void prepare_handover() REQUIRES(!m_callback_mutex);
-
-    template <typename T>
-    class Handle;
-
-    bool have_callbacks() const noexcept { return m_have_callbacks; }
-protected:
-    void add_changes(CollectionChangeBuilder change) REQUIRES(!m_callback_mutex);
-    void set_table(ConstTableRef table);
-    std::unique_lock<std::mutex> lock_target();
-    Transaction& source_shared_group();
-
-    bool all_related_tables_covered(const TableVersions& versions);
-    std::function<bool (ObjectChangeSet::ObjectKeyType)> get_modification_checker(TransactionChangeInfo const&, ConstTableRef);
-
-    // The actual change, calculated in run() and delivered in prepare_handover()
-    CollectionChangeBuilder m_change;
-
-private:
-    virtual void do_attach_to(Transaction&) { }
-    virtual void do_prepare_handover(Transaction&) { }
-    virtual bool do_add_required_change_info(TransactionChangeInfo&) = 0;
-    virtual bool prepare_to_deliver() { return true; }
-
-    mutable std::mutex m_realm_mutex;
-    std::shared_ptr<Realm> m_realm;
-
-    VersionID m_sg_version;
-    std::shared_ptr<Transaction> m_sg;
-
-    bool m_has_run = false;
-    bool m_error = false;
-    std::vector<DeepChangeChecker::RelatedTable> m_related_tables;
-
-    struct Callback {
-        CollectionChangeCallback fn;
-        CollectionChangeBuilder accumulated_changes;
-        CollectionChangeSet changes_to_deliver;
-        uint64_t token;
-        bool initial_delivered;
-        bool skip_next;
-    };
-
-    // Currently registered callbacks and a mutex which must always be held
-    // while doing anything with them or m_callback_index
-    util::CheckedMutex m_callback_mutex;
-    std::vector<Callback> m_callbacks;
-
-    // Cached value for if m_callbacks is empty, needed to avoid deadlocks in
-    // run() due to lock-order inversion between m_callback_mutex and m_target_mutex
-    // It's okay if this value is stale as at worst it'll result in us doing
-    // some extra work.
-    std::atomic<bool> m_have_callbacks = {false};
-
-    // Iteration variable for looping over callbacks
-    // remove_callback() updates this when needed
-    size_t m_callback_index = -1;
-    // The number of callbacks which were present when the notifier was packaged
-    // for delivery which are still present.
-    // Updated by packaged_for_delivery and removd_callback(), and used in
-    // for_each_callback() to avoid calling callbacks registered during delivery.
-    size_t m_callback_count = -1;
-
-    uint64_t m_next_token = 0;
-
-    template<typename Fn>
-    void for_each_callback(Fn&& fn) REQUIRES(!m_callback_mutex);
-
-    std::vector<Callback>::iterator find_callback(uint64_t token);
-};
-
-// A smart pointer to a CollectionNotifier that unregisters the notifier when
-// the pointer is destroyed. Movable. Copying will produce a null Handle.
-template <typename T>
-class CollectionNotifier::Handle : public std::shared_ptr<T> {
-public:
-    using std::shared_ptr<T>::shared_ptr;
-
-    Handle() = default;
-    ~Handle() { reset(); }
-
-    // Copying a Handle produces a null Handle.
-    Handle(const Handle&) : Handle() { }
-    Handle& operator=(const Handle& other)
-    {
-        if (this != &other) {
-            reset();
-        }
-        return *this;
-    }
-
-    Handle(Handle&&) = default;
-    Handle& operator=(Handle&& other)
-    {
-        reset();
-        std::shared_ptr<T>::operator=(std::move(other));
-        return *this;
-    }
-
-    template<typename U>
-    Handle& operator=(std::shared_ptr<U>&& other)
-    {
-        reset();
-        std::shared_ptr<T>::operator=(std::move(other));
-        return *this;
-    }
-
-    void reset()
-    {
-        if (*this) {
-            this->get()->unregister();
-            std::shared_ptr<T>::reset();
-        }
-    }
-};
-
-// A package of CollectionNotifiers for a single Realm instance which is passed
-// around to the various places which need to actually trigger the notifications
-class NotifierPackage {
-public:
-    NotifierPackage() = default;
-    NotifierPackage(std::exception_ptr error,
-                    std::vector<std::shared_ptr<CollectionNotifier>> notifiers,
-                    RealmCoordinator* coordinator);
-
-    explicit operator bool() { return !m_notifiers.empty(); }
-
-    // Get the version which this package can deliver into, or VersionID{} if
-    // it has not yet been packaged
-    util::Optional<VersionID> version() { return m_version; }
-
-    // Package the notifiers for delivery, blocking if they aren't ready for
-    // the given version.
-    // No-op if called multiple times
-    void package_and_wait(util::Optional<VersionID::version_type> target_version);
-
-    // Send the before-change notifications
-    void before_advance();
-    // Deliver the payload associated with the contained notifiers and/or the error
-    void deliver(Transaction& sg);
-    // Send the after-change notifications
-    void after_advance();
-
-    void add_notifier(std::shared_ptr<CollectionNotifier> notifier);
-
-private:
-    util::Optional<VersionID> m_version;
-    std::vector<std::shared_ptr<CollectionNotifier>> m_notifiers;
-
-    RealmCoordinator* m_coordinator = nullptr;
-    std::exception_ptr m_error;
-};
-
-// Find which column of the row in the table contains the given container.
-//
-// LinkViews and Subtables know what row of their parent they're in, but not
-// what column, so we have to just check each one.
-template<typename Table, typename T, typename U>
-size_t find_container_column(Table& table, size_t row_ndx, T const& expected, int type, U (Table::*getter)(size_t, size_t))
-{
-    for (size_t i = 0, count = table.get_column_count(); i != count; ++i) {
-        if (table.get_column_type(i) == type && (table.*getter)(i, row_ndx) == expected) {
-            return i;
-        }
-    }
-    REALM_UNREACHABLE();
-}
-
-
-} // namespace _impl
-} // namespace realm
-
-#endif /* REALM_BACKGROUND_COLLECTION_HPP */

+ 0 - 299
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/epoll/external_commit_helper.cpp

@@ -1,299 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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/external_commit_helper.hpp"
-#include "impl/realm_coordinator.hpp"
-#include <realm/util/fifo_helper.hpp>
-
-#include <realm/util/assert.hpp>
-#include <realm/db.hpp>
-
-#include <algorithm>
-#include <errno.h>
-#include <fcntl.h>
-#include <sstream>
-#include <stdlib.h>
-#include <sys/epoll.h>
-#include <sys/time.h>
-#include <unistd.h>
-
-#ifdef __ANDROID__
-#include <android/log.h>
-#define ANDROID_LOG __android_log_print
-#else
-#define ANDROID_LOG(...)
-#endif
-
-using namespace realm;
-using namespace realm::_impl;
-
-#define LOGE(...) do { \
-    fprintf(stderr, __VA_ARGS__); \
-    ANDROID_LOG(ANDROID_LOG_ERROR, "REALM", __VA_ARGS__); \
-} while (0)
-
-namespace {
-// Write a byte to a pipe to notify anyone waiting for data on the pipe
-void notify_fd(int 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.
-        if (ret != 0) {
-            int err = errno;
-            if (err != EAGAIN) {
-                throw std::system_error(err, std::system_category());
-            }
-        }
-        std::vector<uint8_t> buff(1024);
-        read(fd, buff.data(), buff.size());
-    }
-}
-} // anonymous namespace
-
-class ExternalCommitHelper::DaemonThread {
-public:
-    DaemonThread();
-    ~DaemonThread();
-
-    void add_commit_helper(ExternalCommitHelper* helper);
-    // Return true if the m_helper_list is empty after removal.
-    void remove_commit_helper(ExternalCommitHelper* helper);
-
-    static DaemonThread& shared();
-private:
-    void listen();
-
-    // To protect the accessing m_helpers on the daemon thread.
-    std::mutex m_mutex;
-    std::vector<ExternalCommitHelper*> m_helpers;
-    // The listener thread
-    std::thread m_thread;
-    // File descriptor for epoll
-    FdHolder m_epoll_fd;
-    // The two ends of an anonymous pipe used to notify the kqueue() thread that it should be shut down.
-    FdHolder m_shutdown_read_fd;
-    FdHolder m_shutdown_write_fd;
-    // Daemon thread id. For checking unexpected dead locks.
-    std::thread::id m_thread_id;
-};
-
-
-void ExternalCommitHelper::FdHolder::close()
-{
-    if (m_fd != -1) {
-        ::close(m_fd);
-    }
-    m_fd = -1;
-}
-
-ExternalCommitHelper::ExternalCommitHelper(RealmCoordinator& parent)
-: m_parent(parent)
-{
-    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());
-
-    // 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.
-
-    path = parent.get_path() + ".note";
-    bool fifo_created = util::try_create_fifo(path);
-    if (!fifo_created && !temp_dir.empty()) {
-        path = util::format("%1realm_%2.note", temp_dir, std::hash<std::string>()(parent.get_path()));
-        fifo_created = util::try_create_fifo(path);
-    }
-    if (!fifo_created && !sys_temp_dir.empty()) {
-        path = util::format("%1realm_%2.note", sys_temp_dir, std::hash<std::string>()(parent.get_path()));
-        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());
-    }
-
-    // Lock is inside add_commit_helper.
-    DaemonThread::shared().add_commit_helper(this);
-}
-
-ExternalCommitHelper::~ExternalCommitHelper()
-{
-    DaemonThread::shared().remove_commit_helper(this);
-}
-
-ExternalCommitHelper::DaemonThread::DaemonThread()
-{
-    m_epoll_fd = epoll_create(1);
-    if (m_epoll_fd == -1) {
-        throw std::system_error(errno, std::system_category());
-    }
-
-    // Create the anonymous pipe
-    int pipe_fd[2];
-    int ret = pipe(pipe_fd);
-    if (ret == -1) {
-        throw std::system_error(errno, std::system_category());
-    }
-
-    m_shutdown_read_fd = pipe_fd[0];
-    m_shutdown_write_fd = pipe_fd[1];
-
-    epoll_event event{};
-    event.events = EPOLLIN;
-    event.data.fd = m_shutdown_read_fd;
-    ret = epoll_ctl(m_epoll_fd, EPOLL_CTL_ADD, m_shutdown_read_fd, &event);
-    if (ret != 0) {
-        int err = errno;
-        throw std::system_error(err, std::system_category());
-    }
-
-    m_thread = std::thread([=] {
-        try {
-            listen();
-        }
-        catch (std::exception const& e) {
-            LOGE("uncaught exception in notifier thread: %s: %s\n", typeid(e).name(), e.what());
-            throw;
-        }
-        catch (...) {
-            LOGE("uncaught exception in notifier thread\n");
-            throw;
-        }
-    });
-    m_thread_id = m_thread.get_id();
-}
-
-ExternalCommitHelper::DaemonThread::~DaemonThread()
-{
-    notify_fd(m_shutdown_write_fd);
-    m_thread.join(); // Wait for the thread to exit
-}
-
-ExternalCommitHelper::DaemonThread& ExternalCommitHelper::DaemonThread::shared()
-{
-    static DaemonThread daemon_thread;
-    return daemon_thread;
-}
-
-void ExternalCommitHelper::DaemonThread::add_commit_helper(ExternalCommitHelper* helper)
-{
-    // Called in the deamon thread loop, dead lock will happen.
-    REALM_ASSERT(std::this_thread::get_id() != m_thread_id);
-
-    std::lock_guard<std::mutex> lock(m_mutex);
-
-    m_helpers.push_back(helper);
-
-    epoll_event event{};
-    event.events = EPOLLIN | EPOLLET;
-    event.data.fd = helper->m_notify_fd;
-    int ret = epoll_ctl(m_epoll_fd, EPOLL_CTL_ADD, helper->m_notify_fd, &event);
-    if (ret != 0) {
-        int err = errno;
-        throw std::system_error(err, std::system_category());
-    }
-}
-
-void ExternalCommitHelper::DaemonThread::remove_commit_helper(ExternalCommitHelper* helper)
-{
-    // Called in the deamon thread loop, dead lock will happen.
-    REALM_ASSERT(std::this_thread::get_id() != m_thread_id);
-
-    std::lock_guard<std::mutex> lock(m_mutex);
-
-    m_helpers.erase(std::remove(m_helpers.begin(), m_helpers.end(), helper), m_helpers.end());
-
-    // In kernel versions before 2.6.9, the EPOLL_CTL_DEL operation required a non-NULL pointer in event, even
-    // though this argument is ignored. See man page of epoll_ctl.
-    epoll_event event{};
-    epoll_ctl(m_epoll_fd, EPOLL_CTL_DEL, helper->m_notify_fd, &event);
-}
-
-void ExternalCommitHelper::DaemonThread::listen()
-{
-    pthread_setname_np(pthread_self(), "Realm notification listener");
-
-    int ret;
-
-    while (true) {
-        epoll_event ev{};
-        ret = epoll_wait(m_epoll_fd, &ev, 1, -1);
-
-        if (ret == -1 && errno == EINTR) {
-            // Interrupted system call, try again.
-            continue;
-        }
-
-        if (ret == -1) {
-            int err = errno;
-            throw std::system_error(err, std::system_category());
-        }
-        if (ret == 0) {
-            // Spurious wakeup; just wait again
-            continue;
-        }
-
-        if (ev.data.u32 == (uint32_t)m_shutdown_read_fd) {
-            return;
-        }
-
-        {
-            std::lock_guard<std::mutex> lock(m_mutex);
-            for (auto helper : m_helpers) {
-                if (ev.data.u32 == (uint32_t)helper->m_notify_fd) {
-                    helper->m_parent.on_change();
-                }
-            }
-        }
-    }
-}
-
-void ExternalCommitHelper::notify_others()
-{
-    notify_fd(m_notify_fd);
-}

+ 0 - 70
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/epoll/external_commit_helper.hpp

@@ -1,70 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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 <memory>
-#include <mutex>
-#include <thread>
-#include <vector>
-
-namespace realm {
-
-namespace _impl {
-class RealmCoordinator;
-
-class ExternalCommitHelper {
-public:
-    ExternalCommitHelper(RealmCoordinator& parent);
-    ~ExternalCommitHelper();
-
-    void notify_others();
-
-private:
-    // A RAII holder for a file descriptor which automatically closes the wrapped
-    // fd when it's deallocated
-    class FdHolder {
-    public:
-        FdHolder() = default;
-        ~FdHolder() { close(); }
-        operator int() const { return m_fd; }
-
-        FdHolder& operator=(int new_fd) {
-            close();
-            m_fd = new_fd;
-            return *this;
-        }
-
-    private:
-        int m_fd = -1;
-        void close();
-
-        FdHolder& operator=(FdHolder const&) = delete;
-        FdHolder(FdHolder const&) = delete;
-    };
-
-    class DaemonThread;
-
-    RealmCoordinator& m_parent;
-
-    // Read-write file descriptor for the named pipe which is waited on for
-    // changes and written to when a commit is made
-    FdHolder m_notify_fd;
-};
-
-} // namespace _impl
-} // namespace realm
-

+ 0 - 40
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/external_commit_helper.hpp

@@ -1,40 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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_EXTERNAL_COMMIT_HELPER_HPP
-#define REALM_EXTERNAL_COMMIT_HELPER_HPP
-
-#include <realm/util/features.h>
-
-#if (defined(REALM_HAVE_EPOLL) && REALM_HAVE_EPOLL) || REALM_ANDROID || (defined(REALM_PLATFORM_NODE) && REALM_PLATFORM_NODE && !REALM_PLATFORM_APPLE && !defined(_WIN32))
-#define REALM_USE_EPOLL 1
-#else
-#define REALM_USE_EPOLL 0
-#endif
-
-#if REALM_PLATFORM_APPLE
-#include "impl/apple/external_commit_helper.hpp"
-#elif REALM_USE_EPOLL
-#include "impl/epoll/external_commit_helper.hpp"
-#elif defined(_WIN32)
-#include "impl/windows/external_commit_helper.hpp"
-#else
-#include "impl/generic/external_commit_helper.hpp"
-#endif
-
-#endif // REALM_EXTERNAL_COMMIT_HELPER_HPP

+ 0 - 50
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/generic/external_commit_helper.cpp

@@ -1,50 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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 <realm/history.hpp>
-#include <realm/replication.hpp>
-
-using namespace realm;
-using namespace realm::_impl;
-
-ExternalCommitHelper::ExternalCommitHelper(RealmCoordinator& parent)
-: m_parent(parent)
-, m_history(realm::make_in_realm_history(parent.get_path()))
-, m_sg(*m_history, TransactionOptions(parent.is_in_memory() ? TransactionOptions::Durability::MemOnly
-                                                            : TransactionOptions::Durability::Full,
-                                      parent.get_encryption_key().data()))
-, m_thread(std::async(std::launch::async, [=] {
-    m_sg.begin_read();
-    while (m_sg.wait_for_change()) {
-        m_sg.end_read();
-        m_sg.begin_read();
-        m_parent.on_change();
-    }
-}))
-{
-}
-
-ExternalCommitHelper::~ExternalCommitHelper()
-{
-    m_sg.wait_for_change_release();
-    m_thread.wait(); // Wait for the thread to exit
-}

+ 0 - 50
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/generic/external_commit_helper.hpp

@@ -1,50 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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 <realm/group_shared.hpp>
-
-#include <future>
-
-namespace realm {
-class Replication;
-
-namespace _impl {
-class RealmCoordinator;
-
-class ExternalCommitHelper {
-public:
-    ExternalCommitHelper(RealmCoordinator& parent);
-    ~ExternalCommitHelper();
-
-    // A no-op in this version, but needed for the Apple version
-    void notify_others() { }
-
-private:
-    RealmCoordinator& m_parent;
-
-    // A shared group used to listen for changes
-    std::unique_ptr<Replication> m_history;
-    Transaction m_sg;
-
-    // The listener thread
-    std::future<void> m_thread;
-};
-
-} // namespace _impl
-} // namespace realm
-

+ 0 - 104
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/list_notifier.cpp

@@ -1,104 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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 <realm/db.hpp>
-#include <realm/group.hpp>
-
-using namespace realm;
-using namespace realm::_impl;
-
-ListNotifier::ListNotifier(std::shared_ptr<Realm> 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<const LnkLst&>(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 InvalidKey&) {
-    }
-}
-
-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<LnkLst&>(*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);
-        }
-    }
-}

+ 0 - 58
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/list_notifier.hpp

@@ -1,58 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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_NOTIFIER_HPP
-#define REALM_LIST_NOTIFIER_HPP
-
-#include "impl/collection_notifier.hpp"
-
-#include "property.hpp"
-
-#include <realm/list.hpp>
-
-namespace realm {
-namespace _impl {
-class ListNotifier : public CollectionNotifier {
-public:
-    ListNotifier(std::shared_ptr<Realm> realm, LstBase const& list, PropertyType type);
-
-private:
-    PropertyType m_type;
-    std::unique_ptr<LstBase> m_list;
-
-    TableKey m_table;
-    ColKey m_col;
-    ObjKey m_obj;
-
-    // The last-seen size of the LinkView so that we can report row deletions
-    // when the LinkView itself is deleted
-    size_t m_prev_size;
-
-    TransactionChangeInfo* m_info;
-
-    void run() override;
-
-    void do_attach_to(Transaction& sg) override;
-
-    void release_data() noexcept override;
-    bool do_add_required_change_info(TransactionChangeInfo& info) override;
-};
-}
-}
-
-#endif // REALM_LIST_NOTIFIER_HPP

+ 0 - 51
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/notification_wrapper.hpp

@@ -1,51 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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_OS_NOTIFICATION_WRAPPER_HPP
-#define REALM_OS_NOTIFICATION_WRAPPER_HPP
-
-#include "collection_notifications.hpp"
-
-namespace realm {
-namespace _impl {
-
-// A wrapper that stores a value and an associated notification token.
-// The point of this type is to keep the notification token alive
-// until the value can be properly processed or handled.
-template<typename T>
-struct NotificationWrapper : public T {
-    using T::T;
-
-    NotificationWrapper(T&& object)
-    : T(object)
-    { }
-
-    template <typename F>
-    void add_notification_callback(F&& callback)
-    {
-        m_token = T::add_notification_callback(std::forward<F>(callback));
-    }
-
-private:
-    NotificationToken m_token;
-};
-
-} // namespace _impl
-} // namespace realm
-
-#endif // REALM_OS_NOTIFICATION_WRAPPER_HPP

+ 0 - 224
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/object_accessor_impl.hpp

@@ -1,224 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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_OS_OBJECT_ACCESSOR_IMPL_HPP
-#define REALM_OS_OBJECT_ACCESSOR_IMPL_HPP
-
-#include "object_accessor.hpp"
-
-#include <realm/util/any.hpp>
-
-namespace realm {
-using AnyDict = std::map<std::string, util::Any>;
-using AnyVector = std::vector<util::Any>;
-
-// An object accessor context which can be used to create and access objects
-// using util::Any as the type-erased value type. In addition, this serves as
-// the reference implementation of an accessor context that must be implemented
-// by each binding.
-class CppContext {
-public:
-    // This constructor is the only one used by the object accessor code, and is
-    // used when recurring into a link or array property during object creation
-    // (i.e. prop.type will always be Object or Array).
-    CppContext(CppContext& c, Property const& prop)
-    : realm(c.realm)
-    , object_schema(prop.type == PropertyType::Object ? &*realm->schema().find(prop.object_type) : c.object_schema)
-    { }
-
-    CppContext() = default;
-    CppContext(std::shared_ptr<Realm> realm, const ObjectSchema* os=nullptr)
-    : realm(std::move(realm)), object_schema(os) { }
-
-    // The use of util::Optional for the following two functions is not a hard
-    // requirement; only that it be some type which can be evaluated in a
-    // boolean context to determine if it contains a value, and if it does
-    // contain a value it must be dereferencable to obtain that value.
-
-    // Get the value for a property in an input object, or `util::none` if no
-    // value present. The property is identified both by the name of the
-    // property and its index within the ObjectScehma's persisted_properties
-    // array.
-    util::Optional<util::Any> value_for_property(util::Any& dict,
-                                                 const Property& prop,
-                                                 size_t /* property_index */) const
-    {
-        auto const& v = any_cast<AnyDict&>(dict);
-        auto it = v.find(prop.name);
-        return it == v.end() ? util::none : util::make_optional(it->second);
-    }
-
-    // Get the default value for the given property in the given object schema,
-    // or `util::none` if there is none (which is distinct from the default
-    // being `null`).
-    //
-    // This implementation does not support default values; see the default
-    // value tests for an example of one which does.
-    util::Optional<util::Any>
-    default_value_for_property(ObjectSchema const&, Property const&) const
-    {
-        return util::none;
-    }
-
-    // Invoke `fn` with each of the values from an enumerable type
-    template<typename Func>
-    void enumerate_list(util::Any& value, Func&& fn) {
-        for (auto&& v : any_cast<AnyVector&>(value))
-            fn(v);
-    }
-
-    // Determine if `value` boxes the same List as `list`
-    bool is_same_list(List const& list, util::Any const& value)
-    {
-        if (auto list2 = any_cast<List>(&value))
-            return list == *list2;
-        return false;
-    }
-
-    // Convert from core types to the boxed type
-    util::Any box(BinaryData v) const { return std::string(v); }
-    util::Any box(List v) const { return v; }
-    util::Any box(Object v) const { return v; }
-    util::Any box(Results v) const { return v; }
-    util::Any box(StringData v) const { return std::string(v); }
-    util::Any box(Timestamp v) const { return v; }
-    util::Any box(bool v) const { return v; }
-    util::Any box(double v) const { return v; }
-    util::Any box(float v) const { return v; }
-    util::Any box(int64_t v) const { return v; }
-    util::Any box(util::Optional<bool> v) const { return v; }
-    util::Any box(util::Optional<double> v) const { return v; }
-    util::Any box(util::Optional<float> v) const { return v; }
-    util::Any box(util::Optional<int64_t> v) const { return v; }
-    util::Any box(Obj) const;
-
-    // Any properties are only supported by the Cocoa binding to enable reading
-    // old Realm files that may have used them. Other bindings can safely not
-    // implement this.
-    util::Any box(Mixed) const { REALM_TERMINATE("not supported"); }
-
-    // Convert from the boxed type to core types. This needs to be implemented
-    // for all of the types which `box()` can take, plus `Obj` and optional
-    // versions of the numeric types, minus `List` and `Results`.
-    //
-    // `create` and `update` are only applicable to `unbox<Obj>`. If
-    // `create` is false then when given something which is not a managed Realm
-    // object `unbox()` should simply return a detached obj, while if it's
-    // true then `unbox()` should create a new object in the context's Realm
-    // using the provided value. If `update` is true then upsert semantics
-    // should be used for this.
-    // If `update_only_diff` is true, only properties that are different from
-    // already existing properties should be updated. If `create` and `update_only_diff`
-    // is true, `current_row` may hold a reference to the object that should
-    // be compared against.
-    template<typename T>
-    T unbox(util::Any& v, CreatePolicy = CreatePolicy::Skip, ObjKey /*current_row*/ = ObjKey()) const { return any_cast<T>(v); }
-
-    bool is_null(util::Any const& v) const noexcept { return !v.has_value(); }
-    util::Any null_value() const noexcept { return {}; }
-    util::Optional<util::Any> no_value() const noexcept { return {}; }
-
-    // KVO hooks which will be called before and after modying a property from
-    // within Object::create().
-    void will_change(Object const&, Property const&) {}
-    void did_change() {}
-
-    // Get a string representation of the given value for use in error messages.
-    std::string print(util::Any const&) const { return "not implemented"; }
-
-    // Cocoa allows supplying fewer values than there are properties when
-    // creating objects using an array of values. Other bindings should not
-    // mimick this behavior so just return false here.
-    bool allow_missing(util::Any const&) const { return false; }
-
-private:
-    std::shared_ptr<Realm> realm;
-    const ObjectSchema* object_schema = nullptr;
-
-};
-
-inline util::Any CppContext::box(Obj obj) const
-{
-    REALM_ASSERT(object_schema);
-    return Object(realm, *object_schema, obj);
-}
-
-template<>
-inline StringData CppContext::unbox(util::Any& v, CreatePolicy, ObjKey) const
-{
-    if (!v.has_value())
-        return StringData();
-    auto& value = any_cast<std::string&>(v);
-    return StringData(value.c_str(), value.size());
-}
-
-template<>
-inline BinaryData CppContext::unbox(util::Any& v, CreatePolicy, ObjKey) const
-{
-    if (!v.has_value())
-        return BinaryData();
-    auto& value = any_cast<std::string&>(v);
-    return BinaryData(value.c_str(), value.size());
-}
-
-template<>
-inline Obj CppContext::unbox(util::Any& v, CreatePolicy policy, ObjKey current_obj) const
-{
-    if (auto object = any_cast<Object>(&v))
-        return object->obj();
-    if (auto obj = any_cast<Obj>(&v))
-        return *obj;
-    if (policy == CreatePolicy::Skip)
-        return Obj();
-
-    REALM_ASSERT(object_schema);
-    return Object::create(const_cast<CppContext&>(*this), realm, *object_schema, v, policy, current_obj).obj();
-}
-
-template<>
-inline util::Optional<bool> CppContext::unbox(util::Any& v, CreatePolicy, ObjKey) const
-{
-    return v.has_value() ? util::make_optional(unbox<bool>(v)) : util::none;
-}
-
-template<>
-inline util::Optional<int64_t> CppContext::unbox(util::Any& v, CreatePolicy, ObjKey) const
-{
-    return v.has_value() ? util::make_optional(unbox<int64_t>(v)) : util::none;
-}
-
-template<>
-inline util::Optional<double> CppContext::unbox(util::Any& v, CreatePolicy, ObjKey) const
-{
-    return v.has_value() ? util::make_optional(unbox<double>(v)) : util::none;
-}
-
-template<>
-inline util::Optional<float> CppContext::unbox(util::Any& v, CreatePolicy, ObjKey) const
-{
-    return v.has_value() ? util::make_optional(unbox<float>(v)) : util::none;
-}
-
-template<>
-inline Mixed CppContext::unbox(util::Any&, CreatePolicy, ObjKey) const
-{
-    throw std::logic_error("'Any' type is unsupported");
-}
-}
-
-#endif // REALM_OS_OBJECT_ACCESSOR_IMPL_HPP

+ 0 - 64
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/object_notifier.cpp

@@ -1,64 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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> 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);
-    }
-}

+ 0 - 45
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/object_notifier.hpp

@@ -1,45 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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_OS_OBJECT_NOTIFIER_HPP
-#define REALM_OS_OBJECT_NOTIFIER_HPP
-
-#include "impl/collection_notifier.hpp"
-
-#include <realm/keys.hpp>
-
-namespace realm {
-
-namespace _impl {
-class ObjectNotifier : public CollectionNotifier {
-public:
-    ObjectNotifier(std::shared_ptr<Realm> realm, TableKey table, ObjKey obj);
-
-private:
-    TableKey m_table;
-    ObjKey m_obj;
-    TransactionChangeInfo* m_info;
-
-    void run() override;
-
-    bool do_add_required_change_info(TransactionChangeInfo& info) override;
-};
-}
-}
-
-#endif // REALM_OS_OBJECT_NOTIFIER_HPP

+ 0 - 1162
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/realm_coordinator.cpp

@@ -1,1162 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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/work_queue.hpp"
-#include "sync/impl/sync_file.hpp"
-#include "sync/async_open_task.hpp"
-#include "sync/partial_sync.hpp"
-#include "sync/sync_config.hpp"
-#include "sync/sync_manager.hpp"
-#include "sync/sync_session.hpp"
-#endif
-
-#include <realm/db.hpp>
-#include <realm/history.hpp>
-#include <realm/string_data.hpp>
-#include <realm/util/fifo_helper.hpp>
-
-#include <algorithm>
-#include <unordered_map>
-
-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::string, std::weak_ptr<RealmCoordinator>>;
-
-std::shared_ptr<RealmCoordinator> RealmCoordinator::get_coordinator(StringData path)
-{
-    std::lock_guard<std::mutex> 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<RealmCoordinator>();
-    weak_coordinator = coordinator;
-    return coordinator;
-}
-
-std::shared_ptr<RealmCoordinator> 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> RealmCoordinator::get_existing_coordinator(StringData path)
-{
-    std::lock_guard<std::mutex> 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 = SyncManager::shared().get_session(m_config.path, *m_config.sync_config, force_client_resync);
-
-    std::weak_ptr<RealmCoordinator> 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<void>(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->realm_url() != config.sync_config->realm_url()) {
-                throw MismatchedConfigException("Realm at path '%1' already opened with different sync server URL.", 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
-
-        // Realm::update_schema() handles complaining about schema mismatches
-    }
-}
-
-std::shared_ptr<Realm> RealmCoordinator::get_realm(Realm::Config config, util::Optional<VersionID> version)
-{
-    if (!config.scheduler)
-        config.scheduler = version ? util::Scheduler::get_frozen() : 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> realm;
-    util::CheckedUniqueLock lock(m_realm_mutex);
-    set_config(config);
-    do_get_realm(std::move(config), realm, version, lock);
-    return realm;
-}
-
-std::shared_ptr<Realm> RealmCoordinator::get_realm(std::shared_ptr<util::Scheduler> scheduler)
-{
-    std::shared_ptr<Realm> realm;
-    util::CheckedUniqueLock lock(m_realm_mutex);
-    auto config = m_config;
-    config.scheduler = scheduler ? scheduler : util::Scheduler::make_default();
-    do_get_realm(std::move(config), realm, none, lock);
-    return realm;
-}
-
-ThreadSafeReference RealmCoordinator::get_unbound_realm()
-{
-    std::shared_ptr<Realm> 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>& realm,
-                                    util::Optional<VersionID> version,
-                                    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<ExternalCommitHelper>(*this);
-        }
-        catch (std::system_error const& ex) {
-            throw RealmFileException(RealmFileException::Kind::AccessError,
-                                     get_path(), ex.code().message(), "");
-        }
-    }
-    m_weak_realm_notifiers.emplace_back(realm);
-
-    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) {
-#if REALM_ENABLE_SYNC && REALM_PLATFORM_JAVA
-        // Workaround for https://github.com/realm/realm-java/issues/6619
-        // Between Realm Java 5.10.0 and 5.13.0 created_at/updated_at was optional
-        // when created from Java, even though the Object Store code specified them as
-        // required. Due to how the Realm was initialized, this wasn't a problem before
-        // 5.13.0, but after that the Object Store initializer code was changed causing
-        // problems when Java clients upgraded. In order to prevent older clients from
-        // breaking with a schema mismatch when upgrading we thus fix the schema in transit.
-        // This means that schema reported back from Realm will be different than the one
-        // specified in the Java model class, but this seemed like the approach with the
-        // least amount of disadvantages.
-        if (realm->is_partial()) {
-            auto& new_schema = schema.value();
-            auto current_schema = realm->schema();
-            auto current_resultsets_schema_obj = current_schema.find("__ResultSets");
-            if (current_resultsets_schema_obj != current_schema.end()) {
-                Property* p = current_resultsets_schema_obj->property_for_public_name("created_at");
-                if (is_nullable(p->type)) {
-                    auto it = new_schema.find("__ResultSets");
-                    if (it != new_schema.end()) {
-                        auto created_at_property = it->property_for_public_name("created_at");
-                        auto updated_at_property = it->property_for_public_name("updated_at");
-                        if (created_at_property && updated_at_property) {
-                            created_at_property->type = created_at_property->type | PropertyType::Nullable;
-                            updated_at_property->type = updated_at_property->type | PropertyType::Nullable;
-                        }
-                    }
-                }
-            }
-        }
-#endif
-        realm->update_schema(std::move(*schema), config.schema_version, std::move(migration_function),
-                             std::move(initialization_function));
-    }
-#if REALM_ENABLE_SYNC
-    else if (realm->is_partial())
-        _impl::ensure_partial_sync_schema_initialized(*realm);
-#endif
-}
-
-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<AsyncOpenTask> 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);
-    bool exists = File::exists(m_config.path);
-    create_sync_session(!config.sync_config->is_partial && !exists);
-    return std::make_shared<AsyncOpenTask>(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);
-    bool exists = File::exists(m_config.path);
-    create_sync_session(!config.sync_config->is_partial && !exists);
-}
-
-void RealmCoordinator::open_with_config(Realm::Config config)
-{
-    CheckedLockGuard lock(m_realm_mutex);
-    set_config(config);
-    open_db();
-}
-
-#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<Group>(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<Group>(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<Group> 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()
-#if REALM_ENABLE_SYNC
-: m_partial_sync_work_queue(std::make_unique<_impl::partial_sync::WorkQueue>())
-#endif
-{
-}
-
-RealmCoordinator::~RealmCoordinator()
-{
-    {
-        std::lock_guard<std::mutex> 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<std::shared_ptr<Realm>> realms_to_close;
-    std::vector<std::shared_ptr<RealmCoordinator>> coordinators;
-    {
-        std::lock_guard<std::mutex> 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
-            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<std::weak_ptr<RealmCoordinator>> to_clear;
-    {
-        std::lock_guard<std::mutex> 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<std::mutex> 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<Transaction> 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<CollectionNotifier> 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<std::shared_ptr<_impl::CollectionNotifier>>& 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<TransactionChangeInfo> 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();
-    }
-
-    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
-    auto 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<std::shared_ptr<_impl::CollectionNotifier>> RealmCoordinator::notifiers_for_realm(Realm& realm)
-{
-    std::vector<std::shared_ptr<_impl::CollectionNotifier>> 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<void(VersionID, VersionID)> 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();
-}
-
-#if REALM_ENABLE_SYNC
-_impl::partial_sync::WorkQueue& RealmCoordinator::partial_sync_work_queue()
-{
-    return *m_partial_sync_work_queue;
-}
-#endif

+ 0 - 274
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/realm_coordinator.hpp

@@ -1,274 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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_COORDINATOR_HPP
-#define REALM_COORDINATOR_HPP
-
-#include "shared_realm.hpp"
-
-#include "util/checked_mutex.hpp"
-
-#include <realm/version_id.hpp>
-
-#include <condition_variable>
-#include <mutex>
-
-namespace realm {
-class DB;
-class Replication;
-class Schema;
-class StringData;
-class SyncSession;
-class Transaction;
-
-namespace _impl {
-class CollectionNotifier;
-class ExternalCommitHelper;
-class WeakRealmNotifier;
-
-namespace partial_sync {
-class WorkQueue;
-}
-
-// RealmCoordinator manages the weak cache of Realm instances and communication
-// between per-thread Realm instances for a given file
-class RealmCoordinator : public std::enable_shared_from_this<RealmCoordinator> {
-public:
-    // Get the coordinator for the given path, creating it if neccesary
-    static std::shared_ptr<RealmCoordinator> get_coordinator(StringData path);
-    // Get the coordinator for the given config, creating it if neccesary
-    static std::shared_ptr<RealmCoordinator> get_coordinator(const Realm::Config&);
-    // Get the coordinator for the given path, or null if there is none
-    static std::shared_ptr<RealmCoordinator> get_existing_coordinator(StringData path);
-
-    // Get a shared Realm with the given configuration
-    // If the Realm is already opened on another thread, validate that the given
-    // configuration is compatible with the existing one.
-    // If no version is provided a live thread-confined Realm is returned.
-    // Otherwise, a frozen Realm at the given version is returned. This
-    // can be read from any thread.
-    std::shared_ptr<Realm> get_realm(Realm::Config config, util::Optional<VersionID> version) REQUIRES(!m_realm_mutex, !m_schema_cache_mutex);
-    std::shared_ptr<Realm> get_realm(std::shared_ptr<util::Scheduler> = nullptr) REQUIRES(!m_realm_mutex, !m_schema_cache_mutex);
-#if REALM_ENABLE_SYNC
-    // Get a thread-local shared Realm with the given configuration
-    // If the Realm is not already present, it will be fully downloaded before being returned.
-    // If the Realm is already on disk, it will be fully synchronized before being returned.
-    // Timeouts and interruptions are not handled by this method and must be handled by upper layers.
-    std::shared_ptr<AsyncOpenTask> get_synchronized_realm(Realm::Config config)
-        REQUIRES(!m_realm_mutex, !m_schema_cache_mutex);
-    // Used by GlobalNotifier to bypass the normal initialization path
-    void open_with_config(Realm::Config config) REQUIRES(!m_realm_mutex, !m_schema_cache_mutex);
-
-    // Creates the underlying sync session if it doesn't already exists.
-    // This is also created as part of opening a Realm, so only use this
-    // method if the session needs to exist before the Realm does.
-    void create_session(const Realm::Config& config) REQUIRES(!m_realm_mutex, !m_schema_cache_mutex);
-#endif
-
-    // Get a Realm which is not bound to the current execution context
-    ThreadSafeReference get_unbound_realm() REQUIRES(!m_realm_mutex);
-
-    // Bind an unbound Realm to a specific execution context. The Realm must
-    // be managed by this coordinator.
-    void bind_to_context(Realm& realm) REQUIRES(!m_realm_mutex);
-
-    Realm::Config get_config() const { return m_config; }
-
-    uint64_t get_schema_version() const noexcept REQUIRES(!m_schema_cache_mutex);
-    const std::string& get_path() const noexcept { return m_config.path; }
-    const std::vector<char>& get_encryption_key() const noexcept { return m_config.encryption_key; }
-    bool is_in_memory() const noexcept { return m_config.in_memory; }
-    // Returns the number of versions in the Realm file.
-    uint_fast64_t get_number_of_versions() const { return m_db->get_number_of_versions(); };
-
-    // To avoid having to re-read and validate the file's schema every time a
-    // new read transaction is begun, RealmCoordinator maintains a cache of the
-    // most recently seen file schema and the range of transaction versions
-    // which it applies to. Note that this schema may not be identical to that
-    // of any Realm instances managed by this coordinator, as individual Realms
-    // may only be using a subset of it.
-
-    // Get the latest cached schema and the transaction version which it applies
-    // to. Returns false if there is no cached schema.
-    bool get_cached_schema(Schema& schema, uint64_t& schema_version, uint64_t& transaction) const noexcept REQUIRES(!m_schema_cache_mutex);
-
-    // Cache the state of the schema at the given transaction version
-    void cache_schema(Schema const& new_schema, uint64_t new_schema_version,
-                      uint64_t transaction_version) REQUIRES(!m_schema_cache_mutex);
-    // If there is a schema cached for transaction version `previous`, report
-    // that it is still valid at transaction version `next`
-    void advance_schema_cache(uint64_t previous, uint64_t next) REQUIRES(!m_schema_cache_mutex);
-    void clear_schema_cache_and_set_schema_version(uint64_t new_schema_version) REQUIRES(!m_schema_cache_mutex);
-
-
-    // Asynchronously call notify() on every Realm instance for this coordinator's
-    // path, including those in other processes
-    void send_commit_notifications(Realm&);
-    void wake_up_notifier_worker();
-
-    // Clear the weak Realm cache for all paths
-    // Should only be called in test code, as continuing to use the previously
-    // cached instances will have odd results
-    static void clear_cache();
-
-    // Clears all caches on existing coordinators
-    static void clear_all_caches();
-
-    // Verify that there are no Realms open for any paths
-    static void assert_no_open_realms() noexcept;
-
-    // Explicit constructor/destructor needed for the unique_ptrs to forward-declared types
-    RealmCoordinator();
-    ~RealmCoordinator();
-
-    // Called by Realm's destructor to ensure the cache is cleaned up promptly
-    // Do not call directly
-    void unregister_realm(Realm* realm) REQUIRES(!m_realm_mutex, !m_notifier_mutex);
-
-    // Called by m_notifier when there's a new commit to send notifications for
-    void on_change() REQUIRES(!m_realm_mutex, !m_notifier_mutex);
-
-    static void register_notifier(std::shared_ptr<CollectionNotifier> notifier);
-
-    std::shared_ptr<Group> begin_read(VersionID version={}, bool frozen_transaction = false);
-
-    // Check if advance_to_ready() would actually advance the Realm's read version
-    bool can_advance(Realm& realm);
-
-    // Advance the Realm to the most recent transaction version which all async
-    // work is complete for
-    void advance_to_ready(Realm& realm) REQUIRES(!m_notifier_mutex);
-
-    // Advance the Realm to the most recent transaction version, blocking if
-    // async notifiers are not yet ready for that version
-    // returns whether it actually changed the version
-    bool advance_to_latest(Realm& realm) REQUIRES(!m_notifier_mutex);
-
-    // Deliver any notifications which are ready for the Realm's version
-    void process_available_async(Realm& realm) REQUIRES(!m_notifier_mutex);
-
-    // Register a function which is called whenever sync makes a write to the Realm
-    void set_transaction_callback(std::function<void(VersionID, VersionID)>) REQUIRES(!m_transaction_callback_mutex);
-
-    // Deliver notifications for the Realm, blocking if some aren't ready yet
-    // The calling Realm must be in a write transaction
-    void promote_to_write(Realm& realm) REQUIRES(!m_notifier_mutex);
-
-    // Commit a Realm's current write transaction and send notifications to all
-    // other Realm instances for that path, including in other processes
-    void commit_write(Realm& realm) REQUIRES(!m_notifier_mutex);
-
-    void enable_wait_for_change();
-    bool wait_for_change(std::shared_ptr<Transaction> tr);
-    void wait_for_change_release();
-
-    void close();
-    bool compact();
-
-    template<typename Pred>
-    util::CheckedUniqueLock wait_for_notifiers(Pred&& wait_predicate) REQUIRES(!m_notifier_mutex);
-
-#if REALM_ENABLE_SYNC
-    // A work queue that can be used to perform background work related to partial sync.
-    _impl::partial_sync::WorkQueue& partial_sync_work_queue();
-#endif
-
-    AuditInterface* audit_context() const noexcept { return m_audit_context.get(); }
-
-private:
-    friend Realm::Internal;
-    Realm::Config m_config;
-    std::unique_ptr<Replication> m_history;
-    std::shared_ptr<DB> m_db;
-    std::shared_ptr<Group> m_read_only_group;
-
-    mutable util::CheckedMutex m_schema_cache_mutex;
-    util::Optional<Schema> m_cached_schema GUARDED_BY(m_schema_cache_mutex);
-    uint64_t m_schema_version GUARDED_BY(m_schema_cache_mutex) = -1;
-    uint64_t m_schema_transaction_version_min GUARDED_BY(m_schema_cache_mutex) = 0;
-    uint64_t m_schema_transaction_version_max GUARDED_BY(m_schema_cache_mutex) = 0;
-
-    util::CheckedMutex m_realm_mutex;
-    std::vector<WeakRealmNotifier> m_weak_realm_notifiers GUARDED_BY(m_realm_mutex);
-
-    util::CheckedMutex m_notifier_mutex;
-    std::condition_variable m_notifier_cv;
-    std::vector<std::shared_ptr<_impl::CollectionNotifier>> m_new_notifiers GUARDED_BY(m_notifier_mutex);
-    std::vector<std::shared_ptr<_impl::CollectionNotifier>> m_notifiers GUARDED_BY(m_notifier_mutex);
-    VersionID m_notifier_skip_version GUARDED_BY(m_notifier_mutex) = {0, 0};
-
-    // Transaction used for actually running async notifiers
-    // Will have a read transaction iff m_notifiers is non-empty
-    std::shared_ptr<Transaction> m_notifier_sg;
-
-    // Transaction used to advance notifiers in m_new_notifiers to the main shared
-    // group's transaction version
-    // Will have a read transaction iff m_new_notifiers is non-empty
-    std::shared_ptr<Transaction> m_advancer_sg;
-    std::exception_ptr m_async_error;
-
-    std::unique_ptr<_impl::ExternalCommitHelper> m_notifier;
-    util::CheckedMutex m_transaction_callback_mutex;
-    std::function<void(VersionID, VersionID)> m_transaction_callback GUARDED_BY(m_transaction_callback_mutex);
-
-#if REALM_ENABLE_SYNC
-    std::shared_ptr<SyncSession> m_sync_session;
-    std::unique_ptr<partial_sync::WorkQueue> m_partial_sync_work_queue;
-#endif
-
-    std::shared_ptr<AuditInterface> m_audit_context;
-
-    void open_db();
-
-    void pin_version(VersionID version) REQUIRES(m_notifier_mutex);
-
-    void set_config(const Realm::Config&) REQUIRES(m_realm_mutex, !m_schema_cache_mutex);
-    void create_sync_session(bool force_client_resync);
-    void do_get_realm(Realm::Config config, std::shared_ptr<Realm>& realm,
-                      util::Optional<VersionID> version,
-                      util::CheckedUniqueLock& realm_lock) REQUIRES(m_realm_mutex);
-    void run_async_notifiers() REQUIRES(!m_notifier_mutex);
-    void advance_helper_shared_group_to_latest();
-    void clean_up_dead_notifiers() REQUIRES(m_notifier_mutex);
-
-    std::vector<std::shared_ptr<_impl::CollectionNotifier>> notifiers_for_realm(Realm&) REQUIRES(m_notifier_mutex);
-};
-
-void translate_file_exception(StringData path, bool immutable=false);
-
-template<typename Pred>
-util::CheckedUniqueLock RealmCoordinator::wait_for_notifiers(Pred&& wait_predicate)
-{
-    util::CheckedUniqueLock lock(m_notifier_mutex);
-    bool first = true;
-    m_notifier_cv.wait(lock.native_handle(), [&] {
-        if (wait_predicate())
-            return true;
-        if (first) {
-            wake_up_notifier_worker();
-            first = false;
-        }
-        return false;
-    });
-    return lock;
-}
-
-} // namespace _impl
-} // namespace realm
-
-#endif /* REALM_COORDINATOR_HPP */

+ 0 - 362
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/results_notifier.cpp

@@ -1,362 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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 <numeric>
-
-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<Query>(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 (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<int64_t> 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<const SortDescriptor*>(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<size_t>(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<size_t>();
-    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);
-}

+ 0 - 117
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/results_notifier.hpp

@@ -1,117 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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_RESULTS_NOTIFIER_HPP
-#define REALM_RESULTS_NOTIFIER_HPP
-
-#include "collection_notifier.hpp"
-#include "results.hpp"
-
-#include <realm/db.hpp>
-
-namespace realm {
-namespace _impl {
-class ResultsNotifierBase : public CollectionNotifier {
-public:
-    using ListIndices = util::Optional<std::vector<size_t>>;
-    using CollectionNotifier::CollectionNotifier;
-
-    virtual bool get_tableview(TableView&) { return false; }
-    virtual bool get_list_indices(ListIndices&) { return false; }
-};
-
-class ResultsNotifier : public ResultsNotifierBase {
-public:
-    ResultsNotifier(Results& target);
-    bool get_tableview(TableView& out) override;
-
-private:
-    std::unique_ptr<Query> m_query;
-    DescriptorOrdering m_descriptor_ordering;
-    bool m_target_is_in_table_order;
-
-    // The TableView resulting from running the query. Will be detached unless
-    // the query was (re)run since the last time the handover object was created
-    TableView m_run_tv;
-
-    TransactionRef m_handover_transaction;
-    std::unique_ptr<TableView> m_handover_tv;
-    TransactionRef m_delivered_transaction;
-    std::unique_ptr<TableView> m_delivered_tv;
-
-    // The table version from the last time the query was run. Used to avoid
-    // rerunning the query when there's no chance of it changing.
-    TableVersions m_last_seen_version;
-
-    // The rows from the previous run of the query, for calculating diffs
-    std::vector<int64_t> m_previous_rows;
-
-    TransactionChangeInfo* m_info = nullptr;
-    bool m_results_were_used = true;
-
-    bool need_to_run();
-    void calculate_changes();
-
-    void run() override;
-    void do_prepare_handover(Transaction&) override;
-    bool do_add_required_change_info(TransactionChangeInfo& info) override;
-    bool prepare_to_deliver() override;
-
-    void release_data() noexcept override;
-    void do_attach_to(Transaction& sg) override;
-};
-
-class ListResultsNotifier : public ResultsNotifierBase {
-public:
-    ListResultsNotifier(Results& target);
-    bool get_list_indices(ListIndices& out) override;
-
-private:
-    std::shared_ptr<LstBase> m_list;
-    util::Optional<bool> m_sort_order;
-    bool m_distinct = false;
-
-    ListIndices m_run_indices;
-
-    VersionID m_handover_transaction_version;
-    ListIndices m_handover_indices;
-    VersionID m_delivered_transaction_version;
-    ListIndices m_delivered_indices;
-
-    // The rows from the previous run of the query, for calculating diffs
-    std::vector<size_t> m_previous_indices;
-
-    TransactionChangeInfo* m_info = nullptr;
-    bool m_results_were_used = true;
-
-    bool need_to_run();
-    void calculate_changes();
-
-    void run() override;
-    void do_prepare_handover(Transaction&) override;
-    bool do_add_required_change_info(TransactionChangeInfo& info) override;
-    bool prepare_to_deliver() override;
-
-    void release_data() noexcept override;
-    void do_attach_to(Transaction& sg) override;
-};
-
-} // namespace _impl
-} // namespace realm
-
-#endif /* REALM_RESULTS_NOTIFIER_HPP */

+ 0 - 564
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/transact_log_handler.cpp

@@ -1,564 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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 <realm/db.hpp>
-
-#include <algorithm>
-#include <numeric>
-
-using namespace realm;
-
-namespace {
-
-class KVOAdapter : public _impl::TransactionChangeInfo {
-public:
-    KVOAdapter(std::vector<BindingContext::ObserverState>& observers, BindingContext* context);
-
-    void before(Transaction& sg);
-    void after(Transaction& sg);
-
-private:
-    BindingContext* m_context;
-    std::vector<BindingContext::ObserverState>& m_observers;
-    std::vector<void *> m_invalidated;
-
-    struct ListInfo {
-        BindingContext::ObserverState* observer;
-        _impl::CollectionChangeBuilder builder;
-        ColKey col;
-    };
-    std::vector<ListInfo> m_lists;
-    VersionID m_version;
-};
-
-KVOAdapter::KVOAdapter(std::vector<BindingContext::ObserverState>& observers, BindingContext* context)
-: _impl::TransactionChangeInfo{}
-, m_context(context)
-, m_observers(observers)
-{
-    if (m_observers.empty())
-        return;
-
-    std::vector<TableKey> 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<BindingContext::ObserverState>& 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<typename Func>
-void advance_with_notifications(BindingContext* context,
-                                const std::shared_ptr<Transaction>& sg,
-                                Func&& func, _impl::NotifierPackage& notifiers)
-{
-    auto old_version = sg->get_version_of_current_transaction();
-    std::vector<BindingContext::ObserverState> 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<Transaction>& 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<Transaction>& 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<BindingContext::ObserverState> 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

+ 0 - 62
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/transact_log_handler.hpp

@@ -1,62 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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_TRANSACT_LOG_HANDLER_HPP
-#define REALM_TRANSACT_LOG_HANDLER_HPP
-
-#include <cstdint>
-#include <stdexcept>
-#include <memory>
-
-#include <realm/version_id.hpp>
-
-namespace realm {
-class BindingContext;
-class Transaction;
-
-namespace _impl {
-class NotifierPackage;
-struct TransactionChangeInfo;
-
-struct UnsupportedSchemaChange : std::logic_error {
-    UnsupportedSchemaChange();
-};
-
-namespace transaction {
-// Advance the read transaction version, with change notifications sent to delegate
-// Must not be called from within a write transaction.
-void advance(const std::shared_ptr<Transaction>& sg, BindingContext* binding_context, NotifierPackage&);
-void advance(Transaction& sg, BindingContext* binding_context, VersionID);
-
-// Begin a write transaction
-// If the read transaction version is not up to date, will first advance to the
-// most recent read transaction and sent notifications to delegate
-void begin(const std::shared_ptr<Transaction>& sg,
-           BindingContext* binding_context, NotifierPackage&);
-
-// Cancel a write transaction and roll back all changes, with change notifications
-// for reverting to the old values sent to delegate
-void cancel(Transaction& sg, BindingContext* binding_context);
-
-// Advance the read transaction version, with change information gathered in info
-void advance(Transaction& sg, TransactionChangeInfo& info, VersionID version=VersionID{});
-} // namespace transaction
-} // namespace _impl
-} // namespace realm
-
-#endif /* REALM_TRANSACT_LOG_HANDLER_HPP */

+ 0 - 54
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/weak_realm_notifier.cpp

@@ -1,54 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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>& realm)
-: m_realm(realm)
-, m_realm_key(realm.get())
-{
-    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();
-            }
-        });
-    }
-}

+ 0 - 67
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/weak_realm_notifier.hpp

@@ -1,67 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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_WEAK_REALM_NOTIFIER_HPP
-#define REALM_WEAK_REALM_NOTIFIER_HPP
-
-#include <memory>
-#include <thread>
-
-namespace realm {
-class Realm;
-
-namespace util {
-class Scheduler;
-}
-
-namespace _impl {
-// WeakRealmNotifier stores a weak reference to a Realm instance, along with all of
-// the information about a Realm that needs to be accessed from other threads.
-// This is needed to avoid forming strong references to the Realm instances on
-// other threads, which can produce deadlocks when the last strong reference to
-// a Realm instance is released from within a function holding the cache lock.
-class WeakRealmNotifier {
-public:
-    WeakRealmNotifier(const std::shared_ptr<Realm>& realm);
-    ~WeakRealmNotifier();
-
-    // Get a strong reference to the cached realm
-    std::shared_ptr<Realm> realm() const { return m_realm.lock(); }
-
-    // Has the Realm instance been destroyed?
-    bool expired() const { return m_realm.expired(); }
-
-    // Is this a WeakRealmNotifier for the given Realm instance?
-    bool is_for_realm(Realm* realm) const { return realm == m_realm_key; }
-
-    // Invoke m_realm.notify() on the Realm's thread via the scheduler.
-    void notify();
-
-    // Bind this notifier to the Realm's scheduler.
-    void bind_to_scheduler();
-
-private:
-    std::weak_ptr<Realm> m_realm;
-    void* m_realm_key;
-    std::shared_ptr<util::Scheduler> m_scheduler;
-};
-
-} // namespace _impl
-} // namespace realm
-
-#endif // REALM_WEAK_REALM_NOTIFIER_HPP

+ 0 - 69
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/windows/external_commit_helper.cpp

@@ -1,69 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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/external_commit_helper.hpp"
-#include "impl/realm_coordinator.hpp"
-
-#include <algorithm>
-
-using namespace realm;
-using namespace realm::_impl;
-
-static std::wstring create_condvar_sharedmemory_name(std::string realm_path) {
-    std::replace(realm_path.begin(), realm_path.end(), '\\', '/');
-    return L"Local\\Realm_ObjectStore_ExternalCommitHelper_SharedCondVar_" + std::wstring(realm_path.begin(), realm_path.end());
-}
-
-ExternalCommitHelper::ExternalCommitHelper(RealmCoordinator& parent)
-: m_parent(parent)
-, m_condvar_shared(create_condvar_sharedmemory_name(parent.get_path()).c_str())
-{
-    m_mutex.set_shared_part(InterprocessMutex::SharedPart(), parent.get_path(), "ExternalCommitHelper_ControlMutex");
-    m_commit_available.set_shared_part(m_condvar_shared.get(), parent.get_path(),
-                                       "ExternalCommitHelper_CommitCondVar",
-                                       std::filesystem::temp_directory_path().u8string());
-    m_thread = std::async(std::launch::async, [this]() { listen(); });
-}
-
-ExternalCommitHelper::~ExternalCommitHelper()
-{
-    {
-        std::lock_guard<InterprocessMutex> lock(m_mutex);
-        m_keep_listening = false;
-        m_commit_available.notify_all();
-    }
-    m_thread.wait();
-
-    m_commit_available.release_shared_part();
-}
-
-void ExternalCommitHelper::notify_others()
-{
-    m_commit_available.notify_all();
-}
-
-void ExternalCommitHelper::listen()
-{
-    std::lock_guard<InterprocessMutex> lock(m_mutex);
-    while (m_keep_listening) {
-        m_commit_available.wait(m_mutex, nullptr);
-        if (m_keep_listening) {
-			m_parent.on_change();
-        }
-    }
-}

+ 0 - 97
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/windows/external_commit_helper.hpp

@@ -1,97 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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 <realm/db.hpp>
-
-#include <future>
-#include <windows.h>
-
-namespace realm {
-namespace _impl {
-class RealmCoordinator;
-
-namespace win32 {
-    template <class T, void (*Initializer)(T&)>
-    class SharedMemory {
-    public:
-        SharedMemory(LPCWSTR name) {
-#if REALM_WINDOWS
-            HANDLE mapping = CreateFileMappingW(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, sizeof(T), name);
-            auto error = GetLastError();
-            if (mapping != NULL)
-                m_memory = reinterpret_cast<T*>(MapViewOfFile(mapping, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(T)));
-#elif REALM_UWP
-            HANDLE mapping = CreateFileMappingFromApp(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, sizeof(T), name);
-            auto error = GetLastError();
-            if (mapping != NULL)
-                m_memory = reinterpret_cast<T*>(MapViewOfFileFromApp(mapping, FILE_MAP_ALL_ACCESS, 0, sizeof(T)));
-#endif
-
-            if (mapping) {
-                // we can close the handle we own because the view has now referenced it
-                CloseHandle(mapping);
-            }
-
-            try {
-                if (error == 0) {
-                    Initializer(get());
-                }
-                else if (error != ERROR_ALREADY_EXISTS) {
-                    throw std::system_error(error, std::system_category());
-                }
-            }
-            catch (...) {
-                UnmapViewOfFile(m_memory);
-                throw;
-            }
-        }
-
-        T& get() const noexcept { return *m_memory; }
-
-        ~SharedMemory() {
-            UnmapViewOfFile(m_memory);
-        }
-    private:
-        T* m_memory = nullptr;
-    };
-}
-
-class ExternalCommitHelper {
-public:
-    ExternalCommitHelper(RealmCoordinator& parent);
-    ~ExternalCommitHelper();
-
-    void notify_others();
-
-private:
-    void listen();
-
-    RealmCoordinator& m_parent;
-
-    // The listener thread
-    std::future<void> m_thread;
-
-    win32::SharedMemory<InterprocessCondVar::SharedPart, InterprocessCondVar::init_shared_part> m_condvar_shared;
-
-    InterprocessCondVar m_commit_available;
-    InterprocessMutex m_mutex;
-    bool m_keep_listening = true;
-};
-
-} // namespace _impl
-} // namespace realm

+ 0 - 707
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/index_set.cpp

@@ -1,707 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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 <realm/util/assert.hpp>
-
-#include <algorithm>
-
-using namespace realm;
-using namespace realm::_impl;
-
-const size_t IndexSet::npos;
-
-template<typename T>
-void MutableChunkedRangeVectorIterator<T>::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<typename T>
-void MutableChunkedRangeVectorIterator<T>::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<typename T>
-void MutableChunkedRangeVectorIterator<T>::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<size_t, size_t>;
-
-    ChunkedRangeVectorBuilder(ChunkedRangeVector const& expected);
-    void push_back(size_t index);
-    void push_back(std::pair<size_t, size_t> range);
-    std::vector<ChunkedRangeVector::Chunk> finalize();
-private:
-    std::vector<ChunkedRangeVector::Chunk> 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<size_t, size_t> 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<ChunkedRangeVector::Chunk> 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<size_t> values)
-{
-    for (size_t v : values)
-        add(v);
-}
-
-bool IndexSet::contains(size_t index) const noexcept
-{
-    auto it = const_cast<IndexSet*>(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<IndexSet*>(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});
-}

+ 0 - 325
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/index_set.hpp

@@ -1,325 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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_INDEX_SET_HPP
-#define REALM_INDEX_SET_HPP
-
-#include <cstddef>
-#include <initializer_list>
-#include <iterator>
-#include <type_traits>
-#include <utility>
-#include <vector>
-
-namespace realm {
-namespace _impl {
-template<typename OuterIterator>
-class MutableChunkedRangeVectorIterator;
-
-// An iterator for ChunkedRangeVector, templated on the vector iterator/const_iterator
-template<typename OuterIterator>
-class ChunkedRangeVectorIterator {
-public:
-    using iterator_category = std::bidirectional_iterator_tag;
-    using value_type = typename std::remove_reference<decltype(*OuterIterator()->data.begin())>::type;
-    using difference_type = ptrdiff_t;
-    using pointer = const value_type*;
-    using reference = const value_type&;
-
-    ChunkedRangeVectorIterator(OuterIterator outer, OuterIterator end, value_type* inner)
-    : m_outer(outer), m_end(end), m_inner(inner) { }
-
-    reference operator*() const noexcept { return *m_inner; }
-    pointer operator->() const noexcept { return m_inner; }
-
-    template<typename Other> bool operator==(Other const& it) const noexcept;
-    template<typename Other> bool operator!=(Other const& it) const noexcept;
-
-    ChunkedRangeVectorIterator& operator++() noexcept;
-    ChunkedRangeVectorIterator operator++(int) noexcept;
-
-    ChunkedRangeVectorIterator& operator--() noexcept;
-    ChunkedRangeVectorIterator operator--(int) noexcept;
-
-    // Advance directly to the next outer block
-    void next_chunk() noexcept;
-
-    OuterIterator outer() const noexcept { return m_outer; }
-    size_t offset() const noexcept { return m_inner - &m_outer->data[0]; }
-
-private:
-    OuterIterator m_outer;
-    OuterIterator m_end;
-    value_type* m_inner;
-    friend struct ChunkedRangeVector;
-    friend class MutableChunkedRangeVectorIterator<OuterIterator>;
-};
-
-// A mutable iterator that adds some invariant-preserving mutation methods
-template<typename OuterIterator>
-class MutableChunkedRangeVectorIterator : public ChunkedRangeVectorIterator<OuterIterator> {
-public:
-    using ChunkedRangeVectorIterator<OuterIterator>::ChunkedRangeVectorIterator;
-
-    // Set this iterator to the given range and update the parent if needed
-    void set(size_t begin, size_t end);
-    // Adjust the begin and end of this iterator by the given amounts and
-    // update the parent if needed
-    void adjust(ptrdiff_t front, ptrdiff_t back);
-    // Shift this iterator by the given amount and update the parent if needed
-    void shift(ptrdiff_t distance);
-};
-
-// A vector which stores ranges in chunks with a maximum size
-struct ChunkedRangeVector {
-    struct Chunk {
-        std::vector<std::pair<size_t, size_t>> data;
-        size_t begin;
-        size_t end;
-        size_t count;
-    };
-    std::vector<Chunk> m_data;
-
-    using value_type = std::pair<size_t, size_t>;
-    using iterator = MutableChunkedRangeVectorIterator<typename decltype(m_data)::iterator>;
-    using const_iterator = ChunkedRangeVectorIterator<typename decltype(m_data)::const_iterator>;
-
-#ifdef REALM_DEBUG
-    static const size_t max_size = 4;
-#else
-    static const size_t max_size = 4096 / sizeof(std::pair<size_t, size_t>);
-#endif
-
-    iterator begin() noexcept { return empty() ? end() : iterator(m_data.begin(), m_data.end(), &m_data[0].data[0]); }
-    iterator end() noexcept { return iterator(m_data.end(), m_data.end(), nullptr); }
-    const_iterator begin() const noexcept { return cbegin(); }
-    const_iterator end() const noexcept { return cend(); }
-    const_iterator cbegin() const noexcept { return empty() ? cend() : const_iterator(m_data.cbegin(), m_data.end(), &m_data[0].data[0]); }
-    const_iterator cend() const noexcept { return const_iterator(m_data.end(), m_data.end(), nullptr); }
-
-    bool empty() const noexcept { return m_data.empty(); }
-
-    iterator insert(iterator pos, value_type value);
-    iterator erase(iterator pos) noexcept;
-    void push_back(value_type value);
-    iterator ensure_space(iterator pos);
-
-    void verify() const noexcept;
-};
-} // namespace _impl
-
-class IndexSet : private _impl::ChunkedRangeVector {
-public:
-    static const size_t npos = -1;
-
-    using ChunkedRangeVector::value_type;
-    using ChunkedRangeVector::iterator;
-    using ChunkedRangeVector::const_iterator;
-    using ChunkedRangeVector::begin;
-    using ChunkedRangeVector::end;
-    using ChunkedRangeVector::empty;
-    using ChunkedRangeVector::verify;
-
-    IndexSet() = default;
-    IndexSet(std::initializer_list<size_t>);
-
-    // Check if the index set contains the given index
-    bool contains(size_t index) const noexcept;
-
-    // Counts the number of indices in the set in the given range
-    size_t count(size_t start_index=0, size_t end_index=-1) const noexcept;
-
-    // Add an index to the set, doing nothing if it's already present
-    void add(size_t index);
-    void add(IndexSet const& is);
-
-    // Add an index which has had all of the ranges in the set before it removed
-    // Returns the unshifted index
-    size_t add_shifted(size_t index);
-    // Add indexes which have had the ranges in `shifted_by` added and the ranges
-    // in the current set removed
-    void add_shifted_by(IndexSet const& shifted_by, IndexSet const& values);
-
-    // Remove all indexes from the set and then add a single range starting from
-    // zero with the given length
-    void set(size_t len);
-
-    // Insert an index at the given position, shifting existing indexes at or
-    // after that point back by one
-    void insert_at(size_t index, size_t count=1);
-    void insert_at(IndexSet const&);
-
-    // Shift indexes at or after the given point back by one
-    void shift_for_insert_at(size_t index, size_t count=1);
-    void shift_for_insert_at(IndexSet const&);
-
-    // Delete an index at the given position, shifting indexes after that point
-    // forward by one
-    void erase_at(size_t index);
-    void erase_at(IndexSet const&);
-
-    // If the given index is in the set remove it and return npos; otherwise unshift() it
-    size_t erase_or_unshift(size_t index);
-
-    // Remove the indexes at the given index from the set, without shifting
-    void remove(size_t index, size_t count=1);
-    void remove(IndexSet const&);
-
-    // Shift an index by inserting each of the indexes in this set
-    size_t shift(size_t index) const noexcept;
-    // Shift an index by deleting each of the indexes in this set
-    size_t unshift(size_t index) const noexcept;
-
-    // Remove all indexes from the set
-    void clear() noexcept;
-
-    // An iterator over the individual indices in the set rather than the ranges
-    class IndexIterator : public std::iterator<std::forward_iterator_tag, size_t> {
-    public:
-        IndexIterator(IndexSet::const_iterator it) : m_iterator(it) { }
-        size_t operator*() const noexcept { return m_iterator->first + m_offset; }
-        bool operator==(IndexIterator const& it) const noexcept { return m_iterator == it.m_iterator; }
-        bool operator!=(IndexIterator const& it) const noexcept { return m_iterator != it.m_iterator; }
-
-        IndexIterator& operator++() noexcept
-        {
-            ++m_offset;
-            if (m_iterator->first + m_offset == m_iterator->second) {
-                ++m_iterator;
-                m_offset = 0;
-            }
-            return *this;
-        }
-
-        IndexIterator operator++(int) noexcept
-        {
-            auto value = *this;
-            ++*this;
-            return value;
-        }
-
-    private:
-        IndexSet::const_iterator m_iterator;
-        size_t m_offset = 0;
-    };
-
-    class IndexIteratableAdaptor {
-    public:
-        using value_type = size_t;
-        using iterator = IndexIterator;
-        using const_iterator = iterator;
-
-        const_iterator begin() const noexcept { return m_index_set.begin(); }
-        const_iterator end() const noexcept { return m_index_set.end(); }
-
-        IndexIteratableAdaptor(IndexSet const& is) : m_index_set(is) { }
-    private:
-        IndexSet const& m_index_set;
-    };
-
-    IndexIteratableAdaptor as_indexes() const noexcept { return *this; }
-
-private:
-    // Find the range which contains the index, or the first one after it if
-    // none do
-    iterator find(size_t index) noexcept;
-    iterator find(size_t index, iterator it) noexcept;
-    // Insert the index before the given position, combining existing ranges as
-    // applicable
-    // returns inserted position
-    iterator do_add(iterator pos, size_t index);
-    void do_erase(iterator it, size_t index);
-    iterator do_remove(iterator it, size_t index, size_t count);
-
-    void shift_until_end_by(iterator begin, ptrdiff_t shift);
-};
-
-namespace util {
-// This was added in C++14 but is missing from libstdc++ 4.9
-template<typename Iterator>
-std::reverse_iterator<Iterator> make_reverse_iterator(Iterator it) noexcept
-{
-    return std::reverse_iterator<Iterator>(it);
-}
-} // namespace util
-
-
-namespace _impl {
-template<typename T>
-template<typename OtherIterator>
-inline bool ChunkedRangeVectorIterator<T>::operator==(OtherIterator const& it) const noexcept
-{
-    return m_outer == it.outer() && m_inner == it.operator->();
-}
-
-template<typename T>
-template<typename OtherIterator>
-inline bool ChunkedRangeVectorIterator<T>::operator!=(OtherIterator const& it) const noexcept
-{
-    return !(*this == it);
-}
-
-template<typename T>
-inline ChunkedRangeVectorIterator<T>& ChunkedRangeVectorIterator<T>::operator++() noexcept
-{
-    ++m_inner;
-    if (offset() == m_outer->data.size())
-        next_chunk();
-    return *this;
-}
-
-template<typename T>
-inline ChunkedRangeVectorIterator<T> ChunkedRangeVectorIterator<T>::operator++(int) noexcept
-{
-    auto value = *this;
-    ++*this;
-    return value;
-}
-
-template<typename T>
-inline ChunkedRangeVectorIterator<T>& ChunkedRangeVectorIterator<T>::operator--() noexcept
-{
-    if (!m_inner || m_inner == &m_outer->data.front()) {
-        --m_outer;
-        m_inner = &m_outer->data.back();
-    }
-    else {
-        --m_inner;
-    }
-    return *this;
-}
-
-template<typename T>
-inline ChunkedRangeVectorIterator<T> ChunkedRangeVectorIterator<T>::operator--(int) noexcept
-{
-    auto value = *this;
-    --*this;
-    return value;
-}
-
-template<typename T>
-inline void ChunkedRangeVectorIterator<T>::next_chunk() noexcept
-{
-    ++m_outer;
-    m_inner = m_outer != m_end ? &m_outer->data[0] : nullptr;
-}
-} // namespace _impl
-
-} // namespace realm
-
-#endif // REALM_INDEX_SET_HPP

+ 0 - 507
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/list.cpp

@@ -1,507 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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<typename T>
-struct ListType {
-    using type = Lst<T>;
-};
-
-template<>
-struct ListType<Obj> {
-    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<Realm> r, const Obj& parent_obj, ColKey col)
-: m_realm(std::move(r))
-, m_type(ObjectSchema::from_core_type(*parent_obj.get_table(), col) & ~PropertyType::Array)
-, m_list_base(parent_obj.get_listbase_ptr(col))
-{
-}
-
-List::List(std::shared_ptr<Realm> r, const LstBase& list)
-: m_realm(std::move(r))
-, m_type(ObjectSchema::from_core_type(*list.get_table(), list.get_col_key()) & ~PropertyType::Array)
-, m_list_base(list.clone())
-{
-}
-
-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<LnkLst&>(*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<LnkLst&>(*m_list_base).get_target_table()->where(as<Obj>());
-    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<LnkLst&>(*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<typename T>
-T List::get(size_t row_ndx) const
-{
-    verify_valid_row(row_ndx);
-    return as<T>().get(row_ndx);
-}
-
-template<>
-Obj List::get(size_t row_ndx) const
-{
-    verify_valid_row(row_ndx);
-    auto& list = as<Obj>();
-    return list.get_target_table()->get_object(list.get(row_ndx));
-}
-
-template<typename T>
-size_t List::find(T const& value) const
-{
-    verify_attached();
-    return as<T>().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<Obj>().ConstLstIf<ObjKey>::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<Obj>().ConstLstIf<ObjKey>::find_first(key) : not_found;
-    }
-    throw std::runtime_error("not implemented");
-}
-
-template<typename T>
-void List::add(T value)
-{
-    verify_in_transaction();
-    as<T>().add(value);
-}
-
-template<>
-void List::add(Obj o)
-{
-    verify_in_transaction();
-    validate(o);
-    as<Obj>().add(o.get_key());
-}
-
-template<typename T>
-void List::insert(size_t row_ndx, T value)
-{
-    verify_in_transaction();
-    verify_valid_row(row_ndx, true);
-    as<T>().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);
-    as<Obj>().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<typename T>
-void List::set(size_t row_ndx, T value)
-{
-    verify_in_transaction();
-    verify_valid_row(row_ndx);
-//    validate(row);
-    as<T>().set(row_ndx, value);
-}
-
-template<>
-void List::set(size_t row_ndx, Obj o)
-{
-    verify_in_transaction();
-    verify_valid_row(row_ndx);
-    validate(o);
-    as<Obj>().set(row_ndx, o.get_key());
-}
-
-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<Obj>().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<Obj>().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<LnkLst>(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<std::pair<std::string, bool>> const& keypaths) const
-{
-    return as_results().sort(keypaths);
-}
-
-Results List::filter(Query q) const
-{
-    verify_attached();
-    return Results(m_realm, std::dynamic_pointer_cast<LnkLst>(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<LnkLst>(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<class...> using VoidT = void;
-namespace _impl {
-    template<class... > struct MakeVoid { using type = void; };
-}
-template<class... T> using VoidT = typename _impl::MakeVoid<T...>::type;
-
-template<class, class = VoidT<>>
-struct HasMinmaxType : std::false_type { };
-template<class T>
-struct HasMinmaxType<T, VoidT<typename ColumnTypeTraits<T>::minmax_type>> : std::true_type { };
-
-template<class, class = VoidT<>>
-struct HasSumType : std::false_type { };
-template<class T>
-struct HasSumType<T, VoidT<typename ColumnTypeTraits<T>::sum_type>> : std::true_type { };
-
-template<bool cond>
-struct If;
-
-template<>
-struct If<true> {
-    template<typename T, typename Then, typename Else>
-    static auto call(T self, Then&& fn, Else&&) { return fn(self); }
-};
-template<>
-struct If<false> {
-    template<typename T, typename Then, typename Else>
-    static auto call(T, Then&&, Else&& fn) { return fn(); }
-};
-
-util::Optional<Mixed> 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 : make_optional(result);
-}
-
-util::Optional<Mixed> 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 : 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<double> 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 : make_optional(result.get_double());
-}
-
-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<ListNotifier>(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<Realm> 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<T>(size_t) const; \
-    template size_t List::find<T>(T const&) const; \
-    template void List::add<T>(T); \
-    template void List::insert<T>(size_t, T); \
-    template void List::set<T>(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(util::Optional<bool>)
-REALM_PRIMITIVE_LIST_TYPE(util::Optional<int64_t>)
-REALM_PRIMITIVE_LIST_TYPE(util::Optional<float>)
-REALM_PRIMITIVE_LIST_TYPE(util::Optional<double>)
-
-#undef REALM_PRIMITIVE_LIST_TYPE
-} // namespace realm
-
-namespace {
-size_t hash_combine() { return 0; }
-template<typename T, typename... Rest>
-size_t hash_combine(const T& v, Rest... rest)
-{
-    size_t h = hash_combine(rest...);
-    h ^= std::hash<T>()(v) + 0x9e3779b9 + (h<<6) + (h>>2);
-    return h;
-}
-}
-
-namespace std {
-size_t hash<List>::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);
-}
-}

+ 0 - 319
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/list.hpp

@@ -1,319 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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_OS_LIST_HPP
-#define REALM_OS_LIST_HPP
-
-#include "collection_notifications.hpp"
-#include "impl/collection_notifier.hpp"
-#include "object.hpp"
-#include "property.hpp"
-#include "util/copyable_atomic.hpp"
-
-#include <realm/mixed.hpp>
-#include <realm/list.hpp>
-
-#include <functional>
-#include <memory>
-
-namespace realm {
-class Obj;
-class ObjectSchema;
-class Query;
-class Realm;
-class Results;
-class SortDescriptor;
-class ThreadSafeReference;
-struct ColKey;
-struct ObjKey;
-
-namespace _impl {
-class ListNotifier;
-}
-
-class List {
-public:
-    List() noexcept;
-    List(std::shared_ptr<Realm> r, const Obj& parent_obj, ColKey col);
-    List(std::shared_ptr<Realm> r, const LstBase& list);
-    ~List();
-
-    List(const List&);
-    List& operator=(const List&);
-    List(List&&);
-    List& operator=(List&&);
-
-    const std::shared_ptr<Realm>& get_realm() const { return m_realm; }
-    Query get_query() const;
-
-    ColKey get_parent_column_key() const;
-    ObjKey get_parent_object_key() const;
-    TableKey get_parent_table_key() const;
-
-    // Get the type of the values contained in this List
-    PropertyType get_type() const { return m_type; }
-
-    // Get the ObjectSchema of the values in this List
-    // Only valid if get_type() returns PropertyType::Object
-    ObjectSchema const& get_object_schema() const;
-
-    bool is_valid() const;
-    void verify_attached() const;
-    void verify_in_transaction() const;
-
-    size_t size() const;
-
-    void move(size_t source_ndx, size_t dest_ndx);
-    void remove(size_t list_ndx);
-    void remove_all();
-    void swap(size_t ndx1, size_t ndx2);
-    void delete_at(size_t list_ndx);
-    void delete_all();
-
-    template<typename T = Obj>
-    T get(size_t row_ndx) const;
-    template<typename T>
-    size_t find(T const& value) const;
-
-    // Find the index in the List of the first row matching the query
-    size_t find(Query&& query) const;
-
-    template<typename T>
-    void add(T value);
-    template<typename T>
-    void insert(size_t list_ndx, T value);
-    template<typename T>
-    void set(size_t row_ndx, T value);
-
-    Results sort(SortDescriptor order) const;
-    Results sort(std::vector<std::pair<std::string, bool>> const& keypaths) const;
-    Results filter(Query q) const;
-
-    // Return a Results representing a live view of this List.
-    Results as_results() const;
-
-    // Return a Results representing a snapshot of this List.
-    Results snapshot() const;
-
-    // Returns a frozen copy of this result
-    List freeze(std::shared_ptr<Realm> const& realm) const;
-
-    // Returns whether or not this List is frozen.
-    bool is_frozen() const noexcept;
-
-    // Get the min/max/average/sum of the given column
-    // All but sum() returns none when there are zero matching rows
-    // sum() returns 0,
-    // Throws UnsupportedColumnTypeException for sum/average on timestamp or non-numeric column
-    // Throws OutOfBoundsIndexException for an out-of-bounds column
-    util::Optional<Mixed> max(ColKey column={}) const;
-    util::Optional<Mixed> min(ColKey column={}) const;
-    util::Optional<double> average(ColKey column={}) const;
-    Mixed sum(ColKey column={}) const;
-
-    bool operator==(List const& rgt) const noexcept;
-
-    NotificationToken add_notification_callback(CollectionChangeCallback cb) &;
-
-    template<typename Context>
-    auto get(Context&, size_t row_ndx) const;
-    template<typename T, typename Context>
-    size_t find(Context&, T&& value) const;
-
-    template<typename T, typename Context>
-    void add(Context&, T&& value, CreatePolicy=CreatePolicy::ForceCreate);
-    template<typename T, typename Context>
-    void insert(Context&, size_t list_ndx, T&& value, CreatePolicy=CreatePolicy::ForceCreate);
-    template<typename T, typename Context>
-    void set(Context&, size_t row_ndx, T&& value, CreatePolicy=CreatePolicy::ForceCreate);
-
-    // Replace the values in this list with the values from an enumerable object
-    template<typename T, typename Context>
-    void assign(Context&, T&& value, CreatePolicy=CreatePolicy::ForceCreate);
-
-    // The List object has been invalidated (due to the Realm being invalidated,
-    // or the containing object being deleted)
-    // All non-noexcept functions can throw this
-    struct InvalidatedException : public std::logic_error {
-        InvalidatedException() : std::logic_error("Access to invalidated List object") {}
-    };
-
-    // The input index parameter was out of bounds
-    struct OutOfBoundsIndexException : public std::out_of_range {
-        OutOfBoundsIndexException(size_t r, size_t c);
-        size_t requested;
-        size_t valid_count;
-    };
-
-private:
-    std::shared_ptr<Realm> m_realm;
-    PropertyType m_type;
-    mutable util::CopyableAtomic<const ObjectSchema*> m_object_schema = nullptr;
-    _impl::CollectionNotifier::Handle<_impl::ListNotifier> m_notifier;
-    std::shared_ptr<LstBase> m_list_base;
-
-    void verify_valid_row(size_t row_ndx, bool insertion = false) const;
-    void validate(const Obj&) const;
-
-    template<typename Fn>
-    auto dispatch(Fn&&) const;
-    template<typename T>
-    auto& as() const;
-
-    template<typename T, typename Context>
-    void set_if_different(Context&, size_t row_ndx, T&& value, CreatePolicy);
-
-    friend struct std::hash<List>;
-};
-
-template<typename T>
-auto& List::as() const
-{
-    return static_cast<Lst<T>&>(*m_list_base);
-}
-
-template<>
-inline auto& List::as<Obj>() const
-{
-    return static_cast<LnkLst&>(*m_list_base);
-}
-
-template<typename Fn>
-auto List::dispatch(Fn&& fn) const
-{
-    verify_attached();
-    return switch_on_type(get_type(), std::forward<Fn>(fn));
-}
-
-template<typename Context>
-auto List::get(Context& ctx, size_t row_ndx) const
-{
-    return dispatch([&](auto t) { return ctx.box(this->get<std::decay_t<decltype(*t)>>(row_ndx)); });
-}
-
-template<typename T, typename Context>
-size_t List::find(Context& ctx, T&& value) const
-{
-    return dispatch([&](auto t) { return this->find(ctx.template unbox<std::decay_t<decltype(*t)>>(value, CreatePolicy::Skip)); });
-}
-
-template<typename T, typename Context>
-void List::add(Context& ctx, T&& value, CreatePolicy policy)
-{
-    dispatch([&](auto t) { this->add(ctx.template unbox<std::decay_t<decltype(*t)>>(value, policy)); });
-}
-
-template<typename T, typename Context>
-void List::insert(Context& ctx, size_t list_ndx, T&& value, CreatePolicy policy)
-{
-    dispatch([&](auto t) { this->insert(list_ndx, ctx.template unbox<std::decay_t<decltype(*t)>>(value, policy)); });
-}
-
-template<typename T, typename Context>
-void List::set(Context& ctx, size_t row_ndx, T&& value, CreatePolicy policy)
-{
-    dispatch([&](auto t) { this->set(row_ndx, ctx.template unbox<std::decay_t<decltype(*t)>>(value, policy)); });
-}
-
-namespace _impl {
-template <class T>
-inline ObjKey help_get_current_row(const T&)
-{
-    return ObjKey();
-}
-
-template <>
-inline ObjKey help_get_current_row(const ConstObj& v)
-{
-    return v.get_key();
-}
-
-template <>
-inline ObjKey help_get_current_row(const Obj& v)
-{
-    return v.get_key();
-}
-
-template <class T>
-inline bool help_compare_values(const T& v1, const T& v2)
-{
-    return v1 != v2;
-}
-template <>
-inline bool help_compare_values(const Obj& v1, const Obj& v2)
-{
-    return v1.get_table() != v2.get_table() || v1.get_key() != v2.get_key();
-}
-}
-
-template<typename T, typename Context>
-void List::set_if_different(Context& ctx, size_t row_ndx, T&& value, CreatePolicy policy)
-{
-    dispatch([&](auto t) {
-        using U = std::decay_t<decltype(*t)>;
-        auto old_value =  this->get<U>(row_ndx);
-        auto new_value = ctx.template unbox<U>(value, policy, _impl::help_get_current_row(old_value));
-        if (_impl::help_compare_values(old_value, new_value))
-            this->set(row_ndx, new_value);
-    });
-}
-
-
-template<typename T, typename Context>
-void List::assign(Context& ctx, T&& values, CreatePolicy policy)
-{
-    if (ctx.is_same_list(*this, values))
-        return;
-
-    if (ctx.is_null(values)) {
-        remove_all();
-        return;
-    }
-
-    if (policy == CreatePolicy::UpdateModified) {
-        size_t sz = size();
-        size_t index = 0;
-        ctx.enumerate_list(values, [&](auto&& element) {
-            if (index < sz) {
-                this->set_if_different(ctx, index, element, policy);
-            }
-            else {
-                this->add(ctx, element, policy);
-            }
-            index++;
-        });
-        while (index < sz) {
-            remove(--sz);
-        }
-    }
-    else {
-        remove_all();
-        ctx.enumerate_list(values, [&](auto&& element) {
-            this->add(ctx, element, policy);
-        });
-    }
-}
-} // namespace realm
-
-namespace std {
-template<> struct hash<realm::List> {
-    size_t operator()(realm::List const&) const;
-};
-}
-
-#endif // REALM_OS_LIST_HPP

+ 0 - 163
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/object.cpp

@@ -1,163 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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 <realm/table.hpp>
-
-using namespace realm;
-
-Object Object::freeze(std::shared_ptr<Realm> 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)
-{
-}
-
-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))
-{
-}
-
-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))
-{
-}
-
-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({});
-    }
-}
-
-#if REALM_ENABLE_SYNC
-void Object::ensure_user_in_everyone_role()
-{
-    if (auto role_table = m_realm->read_group().get_table("class___Role")) {
-        if (ObjKey ndx = role_table->find_first_string(role_table->get_column_key("name"), "everyone")) {
-            auto role = role_table->get_object(ndx);
-            auto users = role.get_linklist(role_table->get_column_key("members"));
-            if (users.find_first(m_obj.get_key()) == realm::npos) {
-                users.add(m_obj.get_key());
-            }
-        }
-    }
-}
-
-void Object::ensure_private_role_exists_for_user()
-{
-    auto user_id = m_obj.get<StringData>("id");
-    ObjectStore::ensure_private_role_exists_for_user(static_cast<Transaction&>(m_realm->read_group()), user_id);
-}
-#endif

+ 0 - 188
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/object.hpp

@@ -1,188 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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_OS_OBJECT_HPP
-#define REALM_OS_OBJECT_HPP
-
-#include "impl/collection_notifier.hpp"
-
-#include <realm/obj.hpp>
-
-namespace realm {
-class ObjectSchema;
-struct Property;
-
-namespace _impl {
-    class ObjectNotifier;
-}
-
-enum class CreatePolicy : int8_t {
-    // Do not create objects if given something that could be converted to a
-    // Realm object but isn't. Used for things like find().
-    Skip,
-    // Throw an exception if an object with the same PK already exists.
-    ForceCreate,
-    // If an object with the same PK already exists, set all fields in the input.
-    UpdateAll,
-    // If an object with the same PK already exists, only set fields which have changed.
-    UpdateModified
-};
-
-class Object {
-public:
-    Object();
-    Object(std::shared_ptr<Realm> r, Obj const& o);
-    Object(std::shared_ptr<Realm> r, ObjectSchema const& s, Obj const& o);
-    Object(std::shared_ptr<Realm> r, StringData object_type, ObjKey key);
-    Object(std::shared_ptr<Realm> r, StringData object_type, size_t index);
-
-    Object(Object const&);
-    Object(Object&&);
-    Object& operator=(Object const&);
-    Object& operator=(Object&&);
-
-    ~Object();
-
-    std::shared_ptr<Realm> const& realm() const { return m_realm; }
-    std::shared_ptr<Realm> const& get_realm() const { return m_realm; }
-    ObjectSchema const& get_object_schema() const { return *m_object_schema; }
-    Obj obj() const { return m_obj; }
-
-    bool is_valid() const { return m_obj.is_valid(); }
-
-    // Returns a frozen copy of this object.
-    Object freeze(std::shared_ptr<Realm> frozen_realm) const;
-
-    // Returns whether or not this Object is frozen.
-    bool is_frozen() const noexcept;
-
-    NotificationToken add_notification_callback(CollectionChangeCallback callback) &;
-
-    void ensure_user_in_everyone_role();
-    void ensure_private_role_exists_for_user();
-
-    template<typename ValueType>
-    void set_column_value(StringData prop_name, ValueType&& value) { m_obj.set(prop_name, value); }
-
-    template<typename ValueType>
-    ValueType get_column_value(StringData prop_name) const { return m_obj.get<ValueType>(prop_name); }
-
-    // The following functions require an accessor context which converts from
-    // the binding's native data types to the core data types. See CppContext
-    // for a reference implementation of such a context.
-    //
-    // The actual definitions of these templated functions is in object_accessor.hpp
-
-    // property getter/setter
-    template<typename ValueType, typename ContextType>
-    void set_property_value(ContextType& ctx, StringData prop_name,
-                            ValueType value, CreatePolicy policy = CreatePolicy::ForceCreate);
-
-    template<typename ValueType, typename ContextType>
-    ValueType get_property_value(ContextType& ctx, StringData prop_name) const;
-
-    template<typename ValueType, typename ContextType>
-    ValueType get_property_value(ContextType& ctx, const Property& property) const;
-
-    // create an Object from a native representation
-    template<typename ValueType, typename ContextType>
-    static Object create(ContextType& ctx, std::shared_ptr<Realm> const& realm,
-                         const ObjectSchema &object_schema, ValueType value,
-                         CreatePolicy policy = CreatePolicy::ForceCreate,
-                         ObjKey current_obj = ObjKey(), Obj* = nullptr);
-
-    template<typename ValueType, typename ContextType>
-    static Object create(ContextType& ctx, std::shared_ptr<Realm> const& realm,
-                         StringData object_type, ValueType value,
-                         CreatePolicy policy = CreatePolicy::ForceCreate,
-                         ObjKey current_obj = ObjKey(), Obj* = nullptr);
-
-    template<typename ValueType, typename ContextType>
-    static Object get_for_primary_key(ContextType& ctx,
-                                      std::shared_ptr<Realm> const& realm,
-                                      const ObjectSchema &object_schema,
-                                      ValueType primary_value);
-
-    template<typename ValueType, typename ContextType>
-    static Object get_for_primary_key(ContextType& ctx,
-                                      std::shared_ptr<Realm> const& realm,
-                                      StringData object_type,
-                                      ValueType primary_value);
-
-private:
-    friend class Results;
-
-    std::shared_ptr<Realm> m_realm;
-    const ObjectSchema *m_object_schema;
-    Obj m_obj;
-    _impl::CollectionNotifier::Handle<_impl::ObjectNotifier> m_notifier;
-
-
-    template<typename ValueType, typename ContextType>
-    void set_property_value_impl(ContextType& ctx, const Property &property,
-                                 ValueType value, CreatePolicy policy, bool is_default);
-    template<typename ValueType, typename ContextType>
-    ValueType get_property_value_impl(ContextType& ctx, const Property &property) const;
-
-    template<typename ValueType, typename ContextType>
-    static ObjKey get_for_primary_key_impl(ContextType& ctx, Table const& table,
-                                           const Property &primary_prop,
-                                           ValueType primary_value);
-
-    void verify_attached() const;
-    Property const& property_for_name(StringData prop_name) const;
-    void validate_property_for_setter(Property const&) const;
-};
-
-struct InvalidatedObjectException : public std::logic_error {
-    InvalidatedObjectException(const std::string& object_type);
-    const std::string object_type;
-};
-
-struct InvalidPropertyException : public std::logic_error {
-    InvalidPropertyException(const std::string& object_type, const std::string& property_name);
-    const std::string object_type;
-    const std::string property_name;
-};
-
-struct MissingPropertyValueException : public std::logic_error {
-    MissingPropertyValueException(const std::string& object_type, const std::string& property_name);
-    const std::string object_type;
-    const std::string property_name;
-};
-
-struct MissingPrimaryKeyException : public std::logic_error {
-    MissingPrimaryKeyException(const std::string& object_type);
-    const std::string object_type;
-};
-
-struct ReadOnlyPropertyException : public std::logic_error {
-    ReadOnlyPropertyException(const std::string& object_type, const std::string& property_name);
-    const std::string object_type;
-    const std::string property_name;
-};
-
-struct ModifyPrimaryKeyException : public std::logic_error {
-    ModifyPrimaryKeyException(const std::string& object_type, const std::string& property_name);
-    const std::string object_type;
-    const std::string property_name;
-};
-
-} // namespace realm
-
-#endif // REALM_OS_OBJECT_HPP

+ 0 - 349
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/object_accessor.hpp

@@ -1,349 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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_OS_OBJECT_ACCESSOR_HPP
-#define REALM_OS_OBJECT_ACCESSOR_HPP
-
-#include "object.hpp"
-
-#include "feature_checks.hpp"
-#include "list.hpp"
-#include "object_schema.hpp"
-#include "object_store.hpp"
-#include "results.hpp"
-#include "schema.hpp"
-#include "shared_realm.hpp"
-
-#include <realm/util/assert.hpp>
-#include <realm/table_view.hpp>
-
-#if REALM_ENABLE_SYNC
-#include <realm/sync/object.hpp>
-#endif // REALM_ENABLE_SYNC
-
-#include <string>
-
-namespace realm {
-template <typename ValueType, typename ContextType>
-void Object::set_property_value(ContextType& ctx, StringData prop_name,
-                                ValueType value, CreatePolicy policy)
-{
-    auto& property = property_for_name(prop_name);
-    validate_property_for_setter(property);
-    set_property_value_impl(ctx, property, value, policy, false);
-}
-
-template <typename ValueType, typename ContextType>
-ValueType Object::get_property_value(ContextType& ctx, const Property& property) const
-{
-    return get_property_value_impl<ValueType>(ctx, property);
-}
-
-template <typename ValueType, typename ContextType>
-ValueType Object::get_property_value(ContextType& ctx, StringData prop_name) const
-{
-    return get_property_value_impl<ValueType>(ctx, property_for_name(prop_name));
-}
-
-namespace {
-template <typename ValueType, typename ContextType>
-struct ValueUpdater {
-    ContextType& ctx;
-    Property const& property;
-    ValueType& value;
-    Obj& obj;
-    ColKey col;
-    CreatePolicy policy;
-    bool is_default;
-
-    void operator()(Obj*)
-    {
-        ContextType child_ctx(ctx, property);
-        auto curr_link = obj.get<ObjKey>(col);
-        auto link = child_ctx.template unbox<Obj>(value, policy, curr_link);
-        if (policy != CreatePolicy::UpdateModified || curr_link != link.get_key()) {
-            obj.set(col, link.get_key());
-        }
-    }
-
-    template<typename T>
-    void operator()(T*)
-    {
-        auto new_val = ctx.template unbox<T>(value);
-        if (policy != CreatePolicy::UpdateModified || obj.get<T>(col) != new_val) {
-            obj.set(col, new_val, is_default);
-        }
-    }
-};
-}
-
-template <typename ValueType, typename ContextType>
-void Object::set_property_value_impl(ContextType& ctx, const Property &property,
-                                     ValueType value, CreatePolicy policy, bool is_default)
-{
-    ctx.will_change(*this, property);
-
-    ColKey col{property.column_key};
-    if (is_nullable(property.type) && ctx.is_null(value)) {
-        if (policy != CreatePolicy::UpdateModified || !m_obj.is_null(col)) {
-            if (property.type == PropertyType::Object) {
-                if (!is_default)
-                    m_obj.set_null(col);
-            }
-            else {
-                m_obj.set_null(col, is_default);
-            }
-        }
-
-        ctx.did_change();
-        return;
-    }
-
-    if (is_array(property.type)) {
-        if (property.type == PropertyType::LinkingObjects)
-            throw ReadOnlyPropertyException(m_object_schema->name, property.name);
-
-        ContextType child_ctx(ctx, property);
-        List list(m_realm, m_obj, col);
-        list.assign(child_ctx, value, policy);
-        ctx.did_change();
-        return;
-    }
-
-    ValueUpdater<ValueType, ContextType> updater{ctx, property, value,
-        m_obj, col, policy, is_default};
-    switch_on_type(property.type, updater);
-    ctx.did_change();
-}
-
-template <typename ValueType, typename ContextType>
-ValueType Object::get_property_value_impl(ContextType& ctx, const Property &property) const
-{
-    verify_attached();
-
-    ColKey column{property.column_key};
-    if (is_nullable(property.type) && m_obj.is_null(column))
-        return ctx.null_value();
-    if (is_array(property.type) && property.type != PropertyType::LinkingObjects)
-        return ctx.box(List(m_realm, m_obj, column));
-
-    switch (property.type & ~PropertyType::Flags) {
-        case PropertyType::Bool:   return ctx.box(m_obj.get<bool>(column));
-        case PropertyType::Int:    return is_nullable(property.type) ? ctx.box(*m_obj.get<util::Optional<int64_t>>(column)) : ctx.box(m_obj.get<int64_t>(column));
-        case PropertyType::Float:  return ctx.box(m_obj.get<float>(column));
-        case PropertyType::Double: return ctx.box(m_obj.get<double>(column));
-        case PropertyType::String: return ctx.box(m_obj.get<StringData>(column));
-        case PropertyType::Data:   return ctx.box(m_obj.get<BinaryData>(column));
-        case PropertyType::Date:   return ctx.box(m_obj.get<Timestamp>(column));
-//        case PropertyType::Any:    return ctx.box(m_obj.get<Mixed>(column));
-        case PropertyType::Object: {
-            auto linkObjectSchema = m_realm->schema().find(property.object_type);
-            return ctx.box(Object(m_realm, *linkObjectSchema,
-                                  const_cast<Obj&>(m_obj).get_linked_object(column)));
-        }
-        case PropertyType::LinkingObjects: {
-            auto target_object_schema = m_realm->schema().find(property.object_type);
-            auto link_property = target_object_schema->property_for_name(property.link_origin_property_name);
-            auto table = m_realm->read_group().get_table(target_object_schema->table_key);
-            auto tv = const_cast<Obj&>(m_obj).get_backlink_view(table, ColKey(link_property->column_key));
-            return ctx.box(Results(m_realm, std::move(tv)));
-        }
-        default: REALM_UNREACHABLE();
-    }
-}
-
-template<typename ValueType, typename ContextType>
-Object Object::create(ContextType& ctx, std::shared_ptr<Realm> const& realm,
-                      StringData object_type, ValueType value,
-                      CreatePolicy policy, ObjKey current_obj, Obj* out_row)
-{
-    auto object_schema = realm->schema().find(object_type);
-    REALM_ASSERT(object_schema != realm->schema().end());
-    return create(ctx, realm, *object_schema, value, policy, current_obj, out_row);
-}
-
-template<typename ValueType, typename ContextType>
-Mixed as_mixed(ContextType& ctx, ValueType& value, PropertyType type)
-{
-    if (!value)
-        return {};
-    return switch_on_type(type, [&](auto* t) {
-        return Mixed(ctx.template unbox<NonObjTypeT<decltype(*t)>>(*value));
-    });
-}
-
-template<typename ValueType, typename ContextType>
-Object Object::create(ContextType& ctx, std::shared_ptr<Realm> const& realm,
-                      ObjectSchema const& object_schema, ValueType value,
-                      CreatePolicy policy, ObjKey current_obj, Obj* out_row)
-{
-    realm->verify_in_write();
-
-    // When setting each property, we normally want to skip over the primary key
-    // as that's set as part of object creation. However, during migrations the
-    // property marked as the primary key in the schema may not currently be
-    // considered a primary key by core, and so will need to be set.
-    bool skip_primary = true;
-    // If the input value is missing values for any of the properties we want to
-    // set the propery to the default value for new objects, but leave it
-    // untouched for existing objects.
-    bool created = false;
-
-    Obj obj;
-    auto table = realm->read_group().get_table(object_schema.table_key);
-
-    // If there's a primary key, we need to first check if an object with the
-    // same primary key already exists. If it does, we either update that object
-    // or throw an exception if updating is disabled.
-    if (auto primary_prop = object_schema.primary_key_property()) {
-        auto primary_value = ctx.value_for_property(value, *primary_prop,
-                                                    primary_prop - &object_schema.persisted_properties[0]);
-        if (!primary_value)
-            primary_value = ctx.default_value_for_property(object_schema, *primary_prop);
-        if (!primary_value && !is_nullable(primary_prop->type))
-            throw MissingPropertyValueException(object_schema.name, primary_prop->name);
-
-        // When changing the primary key of a table, we remove the existing pk (if any), call
-        // the migration function, then add the new pk (if any). This means that we can't call
-        // create_object_with_primary_key(), and creating duplicate primary keys is allowed as
-        // long as they're unique by the end of the migration.
-        if (table->get_primary_key_column() == ColKey{}) {
-            REALM_ASSERT(realm->is_in_migration());
-            if (policy != CreatePolicy::ForceCreate) {
-                if (auto key = get_for_primary_key_impl(ctx, *table, *primary_prop, *primary_value))
-                    obj = table->get_object(key);
-            }
-            if (!obj)
-                skip_primary = false;
-        }
-        else {
-            obj = table->create_object_with_primary_key(as_mixed(ctx, primary_value, primary_prop->type), &created);
-            if (!created && policy == CreatePolicy::ForceCreate) {
-                if (!realm->is_in_migration()) {
-                    throw std::logic_error(util::format("Attempting to create an object of type '%1' with an existing primary key value '%2'.",
-                                                        object_schema.name, ctx.print(*primary_value)));
-                }
-                table->set_primary_key_column(ColKey{});
-                skip_primary = false;
-                obj = {};
-            }
-        }
-    }
-
-    // No primary key (possibly temporarily due to migrations). If we're
-    // currently performing a recursive update on an existing object tree then
-    // an object key was passed in that we need to look up, and otherwise we
-    // need to create the new object.
-    if (!obj) {
-        if (policy == CreatePolicy::UpdateModified && current_obj) {
-            obj = table->get_object(current_obj);
-        }
-        else {
-            obj = table->create_object();
-            created = true;
-        }
-    }
-
-    Object object(realm, object_schema, obj);
-    // KVO in Cocoa requires that the obj ivar on the wrapper object be set
-    // *before* we start setting the properties, so it passes in a pointer to
-    // that.
-    if (out_row)
-        *out_row = obj;
-    for (size_t i = 0; i < object_schema.persisted_properties.size(); ++i) {
-        auto& prop = object_schema.persisted_properties[i];
-        if (skip_primary && prop.is_primary)
-            continue;
-
-        auto v = ctx.value_for_property(value, prop, i);
-        if (!created && !v)
-            continue;
-
-        bool is_default = false;
-        if (!v) {
-            v = ctx.default_value_for_property(object_schema, prop);
-            is_default = true;
-        }
-        // We consider null or a missing value to be equivalent to an empty
-        // array for historical reasons; the original implementation did this
-        // accidentally and it's not worth changing.
-        if ((!v || ctx.is_null(*v)) && !is_nullable(prop.type) && !is_array(prop.type)) {
-            if (prop.is_primary || !ctx.allow_missing(value))
-                throw MissingPropertyValueException(object_schema.name, prop.name);
-        }
-        if (v)
-            object.set_property_value_impl(ctx, prop, *v, policy, is_default);
-    }
-#if REALM_ENABLE_SYNC
-    if (realm->is_partial() && object_schema.name == "__User") {
-        object.ensure_user_in_everyone_role();
-        object.ensure_private_role_exists_for_user();
-    }
-#endif
-    return object;
-}
-
-template<typename ValueType, typename ContextType>
-Object Object::get_for_primary_key(ContextType& ctx, std::shared_ptr<Realm> const& realm,
-                      StringData object_type, ValueType primary_value)
-{
-    auto object_schema = realm->schema().find(object_type);
-    REALM_ASSERT(object_schema != realm->schema().end());
-    return get_for_primary_key(ctx, realm, *object_schema, primary_value);
-}
-
-template<typename ValueType, typename ContextType>
-Object Object::get_for_primary_key(ContextType& ctx, std::shared_ptr<Realm> const& realm,
-                                   const ObjectSchema &object_schema,
-                                   ValueType primary_value)
-{
-    auto primary_prop = object_schema.primary_key_property();
-    if (!primary_prop) {
-        throw MissingPrimaryKeyException(object_schema.name);
-    }
-
-    TableRef table;
-    if (object_schema.table_key)
-        table = realm->read_group().get_table(object_schema.table_key);
-    if (!table)
-        return Object(realm, object_schema, Obj());
-    auto key = get_for_primary_key_impl(ctx, *table, *primary_prop, primary_value);
-    return Object(realm, object_schema, key ? table->get_object(key) : Obj{});
-}
-
-template<typename ValueType, typename ContextType>
-ObjKey Object::get_for_primary_key_impl(ContextType& ctx, Table const& table,
-                                        const Property &primary_prop,
-                                        ValueType primary_value) {
-    bool is_null = ctx.is_null(primary_value);
-    if (is_null && !is_nullable(primary_prop.type))
-        throw std::logic_error("Invalid null value for non-nullable primary key.");
-    if (primary_prop.type == PropertyType::String) {
-        return table.find_first(primary_prop.column_key,
-                                ctx.template unbox<StringData>(primary_value));
-    }
-    if (is_nullable(primary_prop.type))
-        return table.find_first(primary_prop.column_key,
-                                ctx.template unbox<util::Optional<int64_t>>(primary_value));
-    return table.find_first(primary_prop.column_key,
-                            ctx.template unbox<int64_t>(primary_value));
-}
-
-} // namespace realm
-
-#endif // REALM_OS_OBJECT_ACCESSOR_HPP

+ 0 - 343
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/object_schema.cpp

@@ -1,343 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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 <realm/data_type.hpp>
-#include <realm/group.hpp>
-#include <realm/table.hpp>
-
-using namespace realm;
-
-ObjectSchema::ObjectSchema() = default;
-ObjectSchema::~ObjectSchema() = default;
-
-ObjectSchema::ObjectSchema(std::string name, std::initializer_list<Property> persisted_properties)
-: ObjectSchema(std::move(name), persisted_properties, {})
-{
-}
-
-ObjectSchema::ObjectSchema(std::string name, std::initializer_list<Property> persisted_properties,
-                           std::initializer_list<Property> computed_properties)
-: name(std::move(name))
-, persisted_properties(persisted_properties)
-, computed_properties(computed_properties)
-{
-    for (auto const& prop : persisted_properties) {
-        if (prop.is_primary) {
-            primary_key = prop.name;
-            break;
-        }
-    }
-}
-
-PropertyType ObjectSchema::from_core_type(Table const& table, ColKey col)
-{
-    auto flags = PropertyType::Required;
-    auto attr = table.get_column_attr(col);
-    if (attr.test(col_attr_Nullable))
-        flags |= PropertyType::Nullable;
-    if (attr.test(col_attr_List))
-        flags |= PropertyType::Array;
-    switch (table.get_column_type(col)) {
-        case type_Int:       return PropertyType::Int | flags;
-        case type_Float:     return PropertyType::Float | flags;
-        case type_Double:    return PropertyType::Double | flags;
-        case type_Bool:      return PropertyType::Bool | flags;
-        case type_String:    return PropertyType::String | flags;
-        case type_Binary:    return PropertyType::Data | flags;
-        case type_Timestamp: return PropertyType::Date | flags;
-        case type_OldMixed:  return PropertyType::Any | flags;
-        case type_Link:      return PropertyType::Object | PropertyType::Nullable;
-        case 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();
-
-    size_t count = table->get_column_count();
-    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(*table, col_key);
-        property.is_indexed = table->has_search_index(col_key) || table->get_primary_key_column() == 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));
-    }
-
-    primary_key = ObjectStore::get_primary_key_for_object(group, name);
-    set_primary_key_property();
-}
-
-Property *ObjectSchema::property_for_name(StringData name) noexcept
-{
-    for (auto& prop : persisted_properties) {
-        if (StringData(prop.name) == name) {
-            return &prop;
-        }
-    }
-    for (auto& prop : computed_properties) {
-        if (StringData(prop.name) == name) {
-            return &prop;
-        }
-    }
-    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 &prop;
-    }
-
-    // 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 &prop;
-    }
-    return nullptr;
-}
-
-const Property *ObjectSchema::property_for_public_name(StringData public_name) const noexcept
-{
-    return const_cast<ObjectSchema *>(this)->property_for_public_name(public_name);
-}
-
-const Property *ObjectSchema::property_for_name(StringData name) const noexcept
-{
-    return const_cast<ObjectSchema *>(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,
-                              std::string const& object_name,
-                              Property const& prop,
-                              Property const** primary,
-                              std::vector<ObjectSchemaValidationException>& exceptions)
-{
-    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) {
-            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 = &prop;
-    }
-
-    // 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<ObjectSchemaValidationException>& exceptions) const
-{
-    std::vector<StringData> public_property_names;
-    std::vector<StringData> 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<ObjectSchemaValidationException> &exceptions;
-
-        struct Proxy {
-            ObjectSchema const &os;
-            std::vector<ObjectSchemaValidationException> &exceptions;
-
-            Proxy &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;
-            }
-        };
-
-        Proxy operator*() { return Proxy{os, exceptions}; }
-        ErrorWriter &operator=(const ErrorWriter &) { 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, name, prop, &primary, exceptions);
-    }
-    for (auto const& prop : computed_properties) {
-        validate_property(schema, name, prop, &primary, exceptions);
-    }
-
-    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.primary_key, a.persisted_properties, a.computed_properties)
-        == std::tie(b.name, b.primary_key, b.persisted_properties, b.computed_properties);
-
-}
-}

+ 0 - 82
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/object_schema.hpp

@@ -1,82 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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_OBJECT_SCHEMA_HPP
-#define REALM_OBJECT_SCHEMA_HPP
-
-#include <realm/keys.hpp>
-#include <realm/string_data.hpp>
-
-#include <string>
-#include <vector>
-
-namespace realm {
-class Group;
-class Schema;
-class Table;
-enum class PropertyType: unsigned char;
-struct ObjectSchemaValidationException;
-struct Property;
-
-class ObjectSchema {
-public:
-    ObjectSchema();
-    ObjectSchema(std::string name, std::initializer_list<Property> persisted_properties);
-    ObjectSchema(std::string name, std::initializer_list<Property> persisted_properties,
-                 std::initializer_list<Property> computed_properties);
-    ~ObjectSchema();
-
-    ObjectSchema(ObjectSchema const&) = default;
-    ObjectSchema(ObjectSchema&&) noexcept = default;
-    ObjectSchema& operator=(ObjectSchema const&) = default;
-    ObjectSchema& operator=(ObjectSchema&&) noexcept = default;
-
-    // create object schema from existing table
-    // if no table key is provided it is looked up in the group
-    ObjectSchema(Group const& group, StringData name, TableKey key);
-
-    std::string name;
-    std::vector<Property> persisted_properties;
-    std::vector<Property> computed_properties;
-    std::string primary_key;
-    TableKey table_key;
-
-    Property *property_for_public_name(StringData public_name) noexcept;
-    const Property *property_for_public_name(StringData public_name) const noexcept;
-    Property *property_for_name(StringData name) noexcept;
-    const Property *property_for_name(StringData name) const noexcept;
-    Property *primary_key_property() noexcept {
-        return property_for_name(primary_key);
-    }
-    const Property *primary_key_property() const noexcept {
-        return property_for_name(primary_key);
-    }
-    bool property_is_computed(Property const& property) const noexcept;
-
-    void validate(Schema const& schema, std::vector<ObjectSchemaValidationException>& exceptions) const;
-
-    friend bool operator==(ObjectSchema const& a, ObjectSchema const& b) noexcept;
-
-    static PropertyType from_core_type(Table const& table, ColKey col);
-
-private:
-    void set_primary_key_property() noexcept;
-};
-}
-
-#endif /* defined(REALM_OBJECT_SCHEMA_HPP) */

+ 0 - 926
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/object_store.cpp

@@ -1,926 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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 "sync/partial_sync.hpp"
-
-#include <realm/group.hpp>
-#include <realm/table.hpp>
-#include <realm/table_view.hpp>
-#include <realm/util/assert.hpp>
-
-#if REALM_ENABLE_SYNC
-#include <realm/sync/object.hpp>
-#include <realm/sync/permissions.hpp>
-#include <realm/sync/instruction_replication.hpp>
-#endif // REALM_ENABLE_SYNC
-
-#include <string.h>
-
-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<int64_t>(c_versionColumnName, version);
-}
-
-template<typename Group>
-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;
-        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;
-    if (auto* pk_property = object_schema.primary_key_property()) {
-        table = group.get_table(name);
-        if (!table) {
-            table = group.add_table_with_primary_key(name, to_core_type(pk_property->type), pk_property->name,
-                                                     is_nullable(pk_property->type));
-        }
-    }
-    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;
-}
-
-} // 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<int64_t>(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<ObjectSchemaValidationException> 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::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<typename ErrorType, typename Verifier>
-void verify_no_errors(Verifier&& verifier, std::vector<SchemaChange> 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<SchemaChange> 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()(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<SchemaChange> const& changes)
-{
-    verify_no_errors<SchemaMismatchException>(SchemaDifferenceExplainer(), changes);
-}
-
-void ObjectStore::verify_no_migration_required(std::vector<SchemaChange> 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<SchemaMismatchException>(verifier, changes);
-}
-
-bool ObjectStore::verify_valid_additive_changes(std::vector<SchemaChange> 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<InvalidSchemaChangeException>(verifier, changes);
-    return verifier.other_changes || (verifier.index_changes && update_indexes);
-}
-
-void ObjectStore::verify_valid_external_changes(std::vector<SchemaChange> 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<InvalidExternalSchemaChangeException>(verifier, changes);
-}
-
-void ObjectStore::verify_compatible_for_immutable_and_readonly(std::vector<SchemaChange> const& changes)
-{
-    using namespace schema_change;
-    struct Verifier : SchemaDifferenceExplainer {
-        using SchemaDifferenceExplainer::operator();
-
-        void operator()(AddTable) { }
-        void operator()(AddInitialProperties) { }
-        void operator()(RemoveProperty) { }
-        void operator()(AddIndex) { }
-        void operator()(RemoveIndex) { }
-    } verifier;
-    verify_no_errors<InvalidSchemaChangeException>(verifier, changes);
-}
-
-static void apply_non_migration_changes(Group& group, std::vector<SchemaChange> 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<SchemaMismatchException>(applier, changes);
-}
-
-static void create_initial_tables(Group& group, std::vector<SchemaChange> 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()(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) { 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()(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<SchemaChange> 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()(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<SchemaChange> 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); }
-        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) { 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};
-
-    for (auto& change : changes) {
-        change.visit(applier);
-    }
-}
-
-enum class DidRereadSchema { Yes, No };
-
-static void apply_post_migration_changes(Group& group,
-                                         std::vector<SchemaChange> 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()(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);
-    }
-}
-
-static void create_default_permissions(Transaction& group, std::vector<SchemaChange> const& changes,
-                                       std::string const& sync_user_id)
-{
-#if !REALM_ENABLE_SYNC
-    static_cast<void>(group);
-    static_cast<void>(changes);
-    static_cast<void>(sync_user_id);
-#else
-    _impl::initialize_schema(group);
-    sync::set_up_basic_permissions(group, true);
-
-    // Ensure that this user exists so that local privileges checks work immediately
-    sync::add_user_to_role(group, sync_user_id, "everyone");
-
-    // Ensure that the user's private role exists so that local privilege checks work immediately.
-    ObjectStore::ensure_private_role_exists_for_user(group, sync_user_id);
-
-    // Mark all tables we just created as fully world-accessible
-    // This has to be done after the first pass of schema init is done so that we can be
-    // sure that the permissions tables actually exist.
-    using namespace schema_change;
-    struct Applier {
-        Transaction& group;
-        void operator()(AddTable op)
-        {
-            sync::set_class_permissions_for_role(group, op.object->name, "everyone",
-                                                 static_cast<int>(ComputedPrivileges::All));
-        }
-
-        void operator()(RemoveTable) { }
-        void operator()(AddInitialProperties) { }
-        void operator()(AddProperty) { }
-        void operator()(RemoveProperty) { }
-        void operator()(MakePropertyNullable) { }
-        void operator()(MakePropertyRequired) { }
-        void operator()(ChangePrimaryKey) { }
-        void operator()(AddIndex) { }
-        void operator()(RemoveIndex) { }
-        void operator()(ChangePropertyType) { }
-    } applier{group};
-
-    for (auto& change : changes) {
-        change.visit(applier);
-    }
-#endif
-}
-
-#if REALM_ENABLE_SYNC
-void ObjectStore::ensure_private_role_exists_for_user(Transaction& group, StringData sync_user_id)
-{
-    std::string private_role_name = util::format("__User:%1", sync_user_id);
-
-    TableRef roles = ObjectStore::table_for_object_type(group, "__Role");
-    ObjKey private_role_ndx = roles->find_first_string(roles->get_column_key("name"), private_role_name);
-    if (private_role_ndx) {
-        // The private role already exists, so there's nothing for us to do.
-        return;
-    }
-
-    // Add the user to the private role, creating the private role in the process.
-    sync::add_user_to_role(group, sync_user_id, private_role_name);
-
-    // Set the private role on the user.
-    private_role_ndx = roles->find_first_string(roles->get_column_key("name"), private_role_name);
-    TableRef users = ObjectStore::table_for_object_type(group, "__User");
-    ObjKey user_ndx = users->find_first_string(users->get_column_key("id"), sync_user_id);
-    users->get_object(user_ndx).set("role", private_role_ndx);
-}
-#endif
-
-void ObjectStore::apply_schema_changes(Transaction& group, uint64_t schema_version,
-                                       Schema& target_schema, uint64_t target_schema_version,
-                                       SchemaMode mode, std::vector<SchemaChange> const& changes,
-                                       util::Optional<std::string> sync_user_id,
-                                       std::function<void()> 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);
-
-        if (sync_user_id)
-            create_default_permissions(group, changes, *sync_user_id);
-
-        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<ObjectSchema> 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<Property> ObjectStore::property_for_column_index(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(*table, 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)) {
-        ObjectStore::set_primary_key_for_object(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)
-{
-}
-
-SchemaValidationException::SchemaValidationException(std::vector<ObjectSchemaValidationException> const& errors)
-: std::logic_error([&] {
-    std::string message = "Schema validation failed due to the following errors:";
-    for (auto const& error : errors) {
-        message += std::string("\n- ") + error.what();
-    }
-    return message;
-}())
-{
-}
-
-SchemaMismatchException::SchemaMismatchException(std::vector<ObjectSchemaValidationException> const& errors)
-: std::logic_error([&] {
-    std::string message = "Migration is required due to the following errors:";
-    for (auto const& error : errors) {
-        message += std::string("\n- ") + error.what();
-    }
-    return message;
-}())
-{
-}
-
-InvalidSchemaChangeException::InvalidSchemaChangeException(std::vector<ObjectSchemaValidationException> const& errors)
-: std::logic_error([&] {
-    std::string message = "The following changes cannot be made in additive-only schema mode:";
-    for (auto const& error : errors) {
-        message += std::string("\n- ") + error.what();
-    }
-    return message;
-}())
-{
-}
-
-InvalidExternalSchemaChangeException::InvalidExternalSchemaChangeException(std::vector<ObjectSchemaValidationException> 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.";
-    for (auto const& error : errors) {
-        message += std::string("\n- ") + error.what();
-    }
-    return message;
-}())
-{
-}

+ 0 - 170
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/object_store.hpp

@@ -1,170 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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_OBJECT_STORE_HPP
-#define REALM_OBJECT_STORE_HPP
-
-#include "property.hpp"
-
-#include <realm/table_ref.hpp>
-#include <realm/util/optional.hpp>
-
-#include <functional>
-#include <string>
-#include <vector>
-#include <limits>
-
-namespace realm {
-class Group;
-class Transaction;
-class Schema;
-class SchemaChange;
-class StringData;
-enum class SchemaMode : uint8_t;
-
-namespace util {
-template<typename... Args>
-std::string format(const char* fmt, Args&&... args);
-}
-
-class ObjectStore {
-public:
-    // Schema version used for uninitialized Realms
-    static constexpr uint64_t NotVersioned = std::numeric_limits<uint64_t>::max();
-
-    // Column name used for subtables which store an array
-    static constexpr const char* const ArrayColumnName = "!ARRAY_VALUE";
-
-    // get the last set schema version
-    static uint64_t get_schema_version(Group const& group);
-
-    // set the schema version without any checks
-    // and the tables for the schema version and the primary key are created if they don't exist
-    // NOTE: must be performed within a write transaction
-    static void set_schema_version(Group& group, uint64_t version);
-
-    // check if all of the changes in the list can be applied automatically, or
-    // throw if any of them require a schema version bump and migration function
-    static void verify_no_migration_required(std::vector<SchemaChange> const& changes);
-
-    // Similar to above, but returns a bool rather than throwing/not throwing
-    static bool needs_migration(std::vector<SchemaChange> const& changes);
-
-    // check if any of the schema changes in the list are forbidden in
-    // additive-only mode, and if any are throw an exception
-    // returns true if any of the changes are not no-ops
-    static bool verify_valid_additive_changes(std::vector<SchemaChange> const& changes,
-                                              bool update_indexes=false);
-
-    // check if the schema changes made by a different process made any changes
-    // which will prevent us from being able to continue (such as removing a
-    // property we were relying on)
-    static void verify_valid_external_changes(std::vector<SchemaChange> const& changes);
-
-    static void verify_compatible_for_immutable_and_readonly(std::vector<SchemaChange> const& changes);
-
-    // check if changes is empty, and throw an exception if not
-    static void verify_no_changes_required(std::vector<SchemaChange> const& changes);
-
-    // updates a Realm from old_schema to the given target schema, creating and updating tables as needed
-    // passed in target schema is updated with the correct column mapping
-    // optionally runs migration function if schema is out of date
-    // NOTE: must be performed within a write transaction
-    static void apply_schema_changes(Transaction& group, uint64_t schema_version,
-                                     Schema& target_schema, uint64_t target_schema_version,
-                                     SchemaMode mode, std::vector<SchemaChange> const& changes,
-                                     util::Optional<std::string> sync_user_id,
-                                     std::function<void()> migration_function={});
-
-    static void apply_additive_changes(Group&, std::vector<SchemaChange> const&, bool update_indexes);
-
-    // get a table for an object type
-    static realm::TableRef table_for_object_type(Group& group, StringData object_type);
-    static realm::ConstTableRef table_for_object_type(Group const& group, StringData object_type);
-
-    // get existing Schema from a group
-    static Schema schema_from_group(Group const& group);
-
-    // get the property for a existing column in the given table. return none if the column is reserved internally.
-    // NOTE: is_primary won't be set for the returned property.
-    static util::Optional<Property> property_for_column_index(ConstTableRef& table, ColKey column_key);
-
-    static void set_schema_keys(Group const& group, Schema& schema);
-
-    // deletes the table for the given type
-    static void delete_data_for_object(Group& group, StringData object_type);
-
-    // indicates if this group contains any objects
-    static bool is_empty(Group const& group);
-
-    // renames the object_type's column of the old_name to the new name
-    static void rename_property(Group& group, Schema& schema, StringData object_type, StringData old_name, StringData new_name);
-
-    // get primary key property name for object type
-    static StringData get_primary_key_for_object(Group const& group, StringData object_type);
-
-    // sets primary key property for object type
-    // must be in write transaction to set
-    static void set_primary_key_for_object(Group& group, StringData object_type, StringData primary_key);
-
-    static std::string table_name_for_object_type(StringData class_name);
-    static StringData object_type_for_table_name(StringData table_name);
-
-    // creates the private role for the given user if it does not exist
-    static void ensure_private_role_exists_for_user(Transaction& group, StringData sync_user_id);
-
-private:
-    friend class ObjectSchema;
-};
-
-class InvalidSchemaVersionException : public std::logic_error {
-public:
-    InvalidSchemaVersionException(uint64_t old_version, uint64_t new_version);
-    uint64_t old_version() const { return m_old_version; }
-    uint64_t new_version() const { return m_new_version; }
-private:
-    uint64_t m_old_version, m_new_version;
-};
-
-// Schema validation exceptions
-struct ObjectSchemaValidationException : public std::logic_error {
-    ObjectSchemaValidationException(std::string message) : logic_error(std::move(message)) {}
-
-    template<typename... Args>
-    ObjectSchemaValidationException(const char* fmt, Args&&... args)
-    : std::logic_error(util::format(fmt, std::forward<Args>(args)...)) { }
-};
-
-struct SchemaValidationException : public std::logic_error {
-    SchemaValidationException(std::vector<ObjectSchemaValidationException> const& errors);
-};
-
-struct SchemaMismatchException : public std::logic_error {
-    SchemaMismatchException(std::vector<ObjectSchemaValidationException> const& errors);
-};
-
-struct InvalidSchemaChangeException : public std::logic_error {
-    InvalidSchemaChangeException(std::vector<ObjectSchemaValidationException> const& errors);
-};
-
-struct InvalidExternalSchemaChangeException : public std::logic_error {
-    InvalidExternalSchemaChangeException(std::vector<ObjectSchemaValidationException> const& errors);
-};
-} // namespace realm
-
-#endif /* defined(REALM_OBJECT_STORE_HPP) */

+ 0 - 1
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/placeholder.cpp

@@ -1 +0,0 @@
-// This file is intentionally left blank.

+ 0 - 297
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/property.hpp

@@ -1,297 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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_HPP
-#define REALM_PROPERTY_HPP
-
-#include "util/tagged_bool.hpp"
-
-#include <realm/util/features.h>
-// FIXME: keys.hpp is currently pretty heavyweight
-#include <realm/keys.hpp>
-
-#include <string>
-
-namespace realm {
-namespace util {
-    template<typename> class Optional;
-}
-class BinaryData;
-class Obj;
-class StringData;
-class Table;
-class Timestamp;
-
-enum class PropertyType : unsigned char {
-    Int    = 0,
-    Bool   = 1,
-    String = 2,
-    Data   = 3,
-    Date   = 4,
-    Float  = 5,
-    Double = 6,
-    Object = 7, // currently must be either Array xor Nullable
-    LinkingObjects = 8, // currently must be Array and not Nullable
-
-    // deprecated and remains only for reading old files
-    Any    = 9,
-
-    // Flags which can be combined with any of the above types except as noted
-    Required  = 0,
-    Nullable  = 64,
-    Array     = 128,
-    Flags     = Nullable | Array
-};
-
-struct Property {
-    using IsPrimary = util::TaggedBool<class IsPrimaryTag>;
-    using IsIndexed = util::TaggedBool<class IsIndexedTag>;
-
-    // The internal column name used in the Realm file.
-    std::string name;
-
-    // The public name used by the binding to represent the internal column name in the Realm file. Bindings can use
-    // this to expose a different name in the binding API, e.g. to map between different naming conventions.
-    //
-    // Public names are only ever user defined, they are not persisted on disk, so reading the schema from the file
-    // will leave this field empty. If `public_name` is empty, the internal and public name are considered to be the same.
-    //
-    // ObjectStore will ensure that no conflicts occur between persisted properties and the public name, so
-    // the public name is just as unique an identifier as the internal name in the file.
-    //
-    // In order to respect public names bindings should use `ObjectSchema::property_for_public_name()` in the schema
-    // and `Object::value_for_property()` in the Object accessor for reading fields defined by the public name.
-    //
-    // For queries, bindings should provide an appropriate `KeyPathMapping` definition. Bindings are responsible
-    // for creating this.
-    std::string public_name;
-    PropertyType type = PropertyType::Int;
-    std::string object_type;
-    std::string link_origin_property_name;
-    IsPrimary is_primary = false;
-    IsIndexed is_indexed = false;
-
-    ColKey column_key;
-
-    Property() = default;
-
-    Property(std::string name, PropertyType type, IsPrimary primary = false,
-             IsIndexed indexed = false, std::string public_name = "");
-
-    Property(std::string name, PropertyType type, std::string object_type,
-             std::string link_origin_property_name = "", std::string public_name = "");
-
-    Property(Property const&) = default;
-    Property(Property&&) noexcept = default;
-    Property& operator=(Property const&) = default;
-    Property& operator=(Property&&) noexcept = default;
-
-    bool requires_index() const { return is_primary || is_indexed; }
-
-    bool type_is_indexable() const noexcept;
-    bool type_is_nullable() const noexcept;
-
-    std::string type_string() const;
-};
-
-template<typename E>
-constexpr auto to_underlying(E e)
-{
-    return static_cast<typename std::underlying_type<E>::type>(e);
-}
-
-inline constexpr PropertyType operator&(PropertyType a, PropertyType b)
-{
-    return static_cast<PropertyType>(to_underlying(a) & to_underlying(b));
-}
-
-inline constexpr PropertyType operator|(PropertyType a, PropertyType b)
-{
-    return static_cast<PropertyType>(to_underlying(a) | to_underlying(b));
-}
-
-inline constexpr PropertyType operator^(PropertyType a, PropertyType b)
-{
-    return static_cast<PropertyType>(to_underlying(a) ^ to_underlying(b));
-}
-
-inline constexpr PropertyType operator~(PropertyType a)
-{
-    return static_cast<PropertyType>(~to_underlying(a));
-}
-
-inline constexpr bool operator==(PropertyType a, PropertyType b)
-{
-    return to_underlying(a & ~PropertyType::Flags) == to_underlying(b & ~PropertyType::Flags);
-}
-
-inline constexpr bool operator!=(PropertyType a, PropertyType b)
-{
-    return !(a == b);
-}
-
-inline PropertyType& operator&=(PropertyType & a, PropertyType b)
-{
-    a = a & b;
-    return a;
-}
-
-inline PropertyType& operator|=(PropertyType & a, PropertyType b)
-{
-    a = a | b;
-    return a;
-}
-
-inline PropertyType& operator^=(PropertyType & a, PropertyType b)
-{
-    a = a ^ b;
-    return a;
-}
-
-inline constexpr bool is_array(PropertyType a)
-{
-    return to_underlying(a & PropertyType::Array) == to_underlying(PropertyType::Array);
-}
-
-inline constexpr bool is_nullable(PropertyType a)
-{
-    return to_underlying(a & PropertyType::Nullable) == to_underlying(PropertyType::Nullable);
-}
-
-// Some of the places we use switch_on_type() the Obj version isn't instantiatable
-// or reachable, so we want to map it to a valid type to let the unreachable code compile
-template<typename T>
-struct NonObjType {
-    using type = std::remove_reference_t<T>;
-};
-template<>
-struct NonObjType<Obj&> {
-    using type = int64_t;
-};
-template<typename T>
-using NonObjTypeT = typename NonObjType<T>::type;
-
-template<typename ObjType=Obj, typename Fn>
-static auto switch_on_type(PropertyType type, Fn&& fn)
-{
-    using PT = PropertyType;
-    bool is_optional = is_nullable(type);
-    switch (type & ~PropertyType::Flags) {
-        case PT::Int:    return is_optional ? fn((util::Optional<int64_t>*)0) : fn((int64_t*)0);
-        case PT::Bool:   return is_optional ? fn((util::Optional<bool>*)0)    : fn((bool*)0);
-        case PT::Float:  return is_optional ? fn((util::Optional<float>*)0)   : fn((float*)0);
-        case PT::Double: return is_optional ? fn((util::Optional<double>*)0)  : fn((double*)0);
-        case PT::String: return fn((StringData*)0);
-        case PT::Data:   return fn((BinaryData*)0);
-        case PT::Date:   return fn((Timestamp*)0);
-        case PT::Object: return fn((ObjType*)0);
-        default: REALM_COMPILER_HINT_UNREACHABLE();
-    }
-}
-
-static const char *string_for_property_type(PropertyType type)
-{
-    if (is_array(type)) {
-        if (type == PropertyType::LinkingObjects)
-            return "linking objects";
-        return "array";
-    }
-    switch (type & ~PropertyType::Flags) {
-        case PropertyType::String: return "string";
-        case PropertyType::Int: return "int";
-        case PropertyType::Bool: return "bool";
-        case PropertyType::Date: return "date";
-        case PropertyType::Data: return "data";
-        case PropertyType::Double: return "double";
-        case PropertyType::Float: return "float";
-        case PropertyType::Object: return "object";
-        case PropertyType::Any: return "any";
-        case PropertyType::LinkingObjects: return "linking objects";
-        default: REALM_COMPILER_HINT_UNREACHABLE();
-    }
-}
-
-inline Property::Property(std::string name, PropertyType type,
-                          IsPrimary primary, IsIndexed indexed,
-                          std::string public_name)
-: name(std::move(name))
-, public_name(std::move(public_name))
-, type(type)
-, is_primary(primary)
-, is_indexed(indexed)
-{
-}
-
-inline Property::Property(std::string name, PropertyType type,
-                          std::string object_type,
-                          std::string link_origin_property_name,
-                          std::string public_name)
-: name(std::move(name))
-, public_name(std::move(public_name))
-, type(type)
-, object_type(std::move(object_type))
-, link_origin_property_name(std::move(link_origin_property_name))
-{
-}
-
-inline bool Property::type_is_indexable() const noexcept
-{
-    return type == PropertyType::Int
-        || type == PropertyType::Bool
-        || type == PropertyType::Date
-        || type == PropertyType::String;
-}
-
-inline bool Property::type_is_nullable() const noexcept
-{
-    return !(is_array(type) && type == PropertyType::Object) && type != PropertyType::LinkingObjects;
-}
-
-inline std::string Property::type_string() const
-{
-    if (is_array(type)) {
-        if (type == PropertyType::Object)
-            return "array<" + object_type + ">";
-        if (type == PropertyType::LinkingObjects)
-            return "linking objects<" + object_type + ">";
-        return std::string("array<") + string_for_property_type(type & ~PropertyType::Flags) + ">";
-    }
-    switch (auto base_type = (type & ~PropertyType::Flags)) {
-        case PropertyType::Object:
-            return "<" + object_type + ">";
-        case PropertyType::LinkingObjects:
-            return "linking objects<" + object_type + ">";
-        default:
-            return string_for_property_type(base_type);
-    }
-}
-
-inline bool operator==(Property const& lft, Property const& rgt)
-{
-    // note: not checking column_key
-    // ordered roughly by the cost of the check
-    return to_underlying(lft.type) == to_underlying(rgt.type)
-        && lft.is_primary == rgt.is_primary
-        && lft.requires_index() == rgt.requires_index()
-        && lft.name == rgt.name
-        && lft.object_type == rgt.object_type
-        && lft.link_origin_property_name == rgt.link_origin_property_name;
-}
-} // namespace realm
-
-#endif // REALM_PROPERTY_HPP

+ 0 - 1114
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/results.cpp

@@ -1,1114 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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 <stdexcept>
-
-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<Realm> r, std::shared_ptr<LstBase> 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<Realm> r, std::shared_ptr<LstBase> 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<Realm> 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<Realm> r, std::shared_ptr<LnkLst> lv, util::Optional<Query> 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
-{
-    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<typename T>
-auto& Results::list_as() const
-{
-    return static_cast<Lst<T>&>(*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<size_t>{};
-        needs_update = true;
-    }
-    if (!needs_update)
-        return;
-    if (m_list->is_empty()) {
-        m_list_indices->clear();
-        return;
-    }
-
-    util::Optional<bool> 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<const SortDescriptor*>(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<typename T>
-util::Optional<T> 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<T>().get((*m_list_indices)[ndx]);
-        }
-        else {
-            if (ndx < m_list->size())
-                return list_as<T>().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<Table::ConstIterator>(*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::ConstIterator>(table.begin());
-    }
-    if (!m_it) {
-        return const_cast<Table&>(table).get_object(ndx);
-    }
-    try {
-        return (*m_it)[ndx];
-    }
-    catch (...) {
-        // Iterator might be outdated
-        m_it = std::make_unique<Table::ConstIterator>(table.begin());
-        return (*m_it)[ndx];
-    }
-}
-
-template<>
-util::Optional<Obj> 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<typename T>
-T Results::get(size_t row_ndx)
-{
-    util::CheckedUniqueLock lock(m_mutex);
-    if (auto row = try_get<T>(row_ndx)) {
-        return *row;
-    }
-    throw OutOfBoundsIndexException{row_ndx, do_size()};
-}
-
-template<typename T>
-util::Optional<T> Results::first()
-{
-    util::CheckedUniqueLock lock(m_mutex);
-    return try_get<T>(0);
-}
-
-template<typename T>
-util::Optional<T> 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<T>(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()),
-            "Attempting to get the index of a Row of the wrong type"
-        );
-    }
-
-    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<ObjKey>::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<typename T>
-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<T>().get((*m_list_indices)[i]) == value)
-                return i;
-        }
-        return not_found;
-    }
-    return list_as<T>().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<Table&>(*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: break;
-        default: throw UnsupportedColumnTypeException{column, *m_table, name};
-    }
-    return type;
-}
-
-namespace {
-template<typename T, typename Table>
-struct AggregateHelper;
-
-template<typename Table>
-struct AggregateHelper<int64_t, Table> {
-    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<typename Table>
-struct AggregateHelper<double, Table> {
-    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<typename Table>
-struct AggregateHelper<float, Table> {
-    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<typename Table>
-struct AggregateHelper<Timestamp, Table> {
-    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"}; }
-};
-
-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<int64_t, LstBase&> : ListAggregateHelper
-{ AggregateHelper(LstBase& l) : ListAggregateHelper{l} {} };
-template<> struct AggregateHelper<double,  LstBase&> : ListAggregateHelper
-{ AggregateHelper(LstBase& l) : ListAggregateHelper{l} {} };
-template<> struct AggregateHelper<float,   LstBase&> : ListAggregateHelper
-{ AggregateHelper(LstBase& l) : ListAggregateHelper{l} {} };
-
-template<>
-struct AggregateHelper<Timestamp, LstBase&> : 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<typename Table, typename Func>
-Mixed call_with_helper(Func&& func, Table&& table, DataType type)
-{
-    switch (type) {
-        case type_Timestamp: return func(AggregateHelper<Timestamp, Table>{table});
-        case type_Double:    return func(AggregateHelper<double, Table>{table});
-        case type_Float:     return func(AggregateHelper<Float, Table>{table});
-        case type_Int:       return func(AggregateHelper<Int, Table>{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<typename AggregateFunction>
-util::Optional<Mixed> 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<Mixed> 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<Mixed> 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<Mixed> Results::sum(ColKey column)
-{
-    return aggregate(column, "sum", [&](auto&& helper) { return helper.sum(column); });
-}
-
-util::Optional<double> 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 : util::make_optional(results->get_double());
-}
-
-void Results::clear()
-{
-    util::CheckedUniqueLock lock(m_mutex);
-    switch (m_mode) {
-        case Mode::Empty:
-            return;
-        case Mode::Table:
-            validate_write();
-            if (m_realm->is_partial())
-                m_table->where().find_all().clear();
-            else
-                const_cast<Table&>(*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_table(), 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<Query&>(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<ConstTableView>(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<ColKey> 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<ColKey> 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<std::pair<std::string, bool>> 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<std::vector<ColKey>> column_keys;
-    std::vector<bool> 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<const SortDescriptor*>(ordering[i]);
-                new_order.append_sort(std::move(*sort));
-                break;
-            }
-            case DescriptorType::Distinct: {
-                auto distinct = dynamic_cast<const DistinctDescriptor*>(ordering[i]);
-                new_order.append_distinct(std::move(*distinct));
-                break;
-            }
-            case DescriptorType::Limit: {
-                auto limit = dynamic_cast<const LimitDescriptor*>(ordering[i]);
-                new_order.append_limit(std::move(*limit));
-                break;
-            }
-            case DescriptorType::Include: {
-                auto include = dynamic_cast<const IncludeDescriptor*>(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<std::string> 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<std::vector<ColKey>> 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<Results&&>(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<T>(size_t); \
-    template util::Optional<T> Results::first<T>(); \
-    template util::Optional<T> Results::last<T>(); \
-    template size_t Results::index_of<T>(T const&);
-
-template Obj Results::get<Obj>(size_t);
-template util::Optional<Obj> Results::first<Obj>();
-template util::Optional<Obj> Results::last<Obj>();
-
-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(util::Optional<bool>)
-REALM_RESULTS_TYPE(util::Optional<int64_t>)
-REALM_RESULTS_TYPE(util::Optional<float>)
-REALM_RESULTS_TYPE(util::Optional<double>)
-
-#undef REALM_RESULTS_TYPE
-
-Results Results::freeze(std::shared_ptr<Realm> 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<LnkLst> frozen_ll(frozen_realm->import_copy_of(std::make_unique<LnkLst>(*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(util::format("Requested index %1 greater than max %2", r, c - 1))
-, requested(r), valid_count(c) {}
-
-static std::string unsupported_operation_msg(ColKey column, Table const& table, const char* operation)
-{
-    auto type = ObjectSchema::from_core_type(table, 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(table, ColKey(column)) & ~PropertyType::Array)
-{
-}
-
-Results::UnsupportedColumnTypeException::UnsupportedColumnTypeException(ColKey column, TableView const& tv,
-                                                                        const char* operation)
-: UnsupportedColumnTypeException(column, tv.ObjList::get_parent(), 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

+ 0 - 393
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/results.hpp

@@ -1,393 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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_RESULTS_HPP
-#define REALM_RESULTS_HPP
-
-#include "collection_notifications.hpp"
-#include "impl/collection_notifier.hpp"
-#include "list.hpp"
-#include "object.hpp"
-#include "object_schema.hpp"
-#include "property.hpp"
-#include "shared_realm.hpp"
-#include "util/checked_mutex.hpp"
-#include "util/copyable_atomic.hpp"
-
-#include <realm/table_view.hpp>
-#include <realm/util/optional.hpp>
-
-namespace realm {
-class Mixed;
-class ObjectSchema;
-
-namespace _impl {
-    class ResultsNotifierBase;
-}
-
-class Results {
-public:
-    // Results can be either be backed by nothing, a thin wrapper around a table,
-    // or a wrapper around a query and a sort order which creates and updates
-    // the tableview as needed
-    Results();
-    Results(std::shared_ptr<Realm> r, ConstTableRef table);
-    Results(std::shared_ptr<Realm> r, std::shared_ptr<LstBase> list);
-    Results(std::shared_ptr<Realm> r, std::shared_ptr<LstBase> list, DescriptorOrdering o);
-    Results(std::shared_ptr<Realm> r, Query q, DescriptorOrdering o = {});
-    Results(std::shared_ptr<Realm> r, TableView tv, DescriptorOrdering o = {});
-    Results(std::shared_ptr<Realm> r, std::shared_ptr<LnkLst> list, util::Optional<Query> q = {}, SortDescriptor s = {});
-    ~Results();
-
-    // Results is copyable and moveable
-    Results(Results&&);
-    Results& operator=(Results&&);
-    Results(const Results&);
-    Results& operator=(const Results&);
-
-    // Get the Realm
-    std::shared_ptr<Realm> get_realm() const { return m_realm; }
-
-    // Object schema describing the vendored object type
-    const ObjectSchema &get_object_schema() const REQUIRES(!m_mutex);
-
-    // Get a query which will match the same rows as is contained in this Results
-    // Returned query will not be valid if the current mode is Empty
-    Query get_query() const REQUIRES(!m_mutex);
-
-    // Get the Lst this Results is derived from, if any
-    std::shared_ptr<LstBase> const& get_list() const { return m_list; }
-
-    // Get the list of sort and distinct operations applied for this Results.
-    DescriptorOrdering const& get_descriptor_ordering() const noexcept { return m_descriptor_ordering; }
-
-    // Get a tableview containing the same rows as this Results
-    TableView get_tableview() REQUIRES(!m_mutex);
-
-    // Get the object type which will be returned by get()
-    StringData get_object_type() const noexcept;
-
-    PropertyType get_type() const REQUIRES(!m_mutex);
-
-    // Get the size of this results
-    // Can be either O(1) or O(N) depending on the state of things
-    size_t size() REQUIRES(!m_mutex);
-
-    // Get the row accessor for the given index
-    // Throws OutOfBoundsIndexException if index >= size()
-    template<typename T = Obj>
-    T get(size_t index) REQUIRES(!m_mutex);
-
-    // Get the boxed row accessor for the given index
-    // Throws OutOfBoundsIndexException if index >= size()
-    template<typename Context>
-    auto get(Context&, size_t index) REQUIRES(!m_mutex);
-
-    // Get a row accessor for the first/last row, or none if the results are empty
-    // More efficient than calling size()+get()
-    template<typename T = Obj>
-    util::Optional<T> first() REQUIRES(!m_mutex);
-    template<typename T = Obj>
-    util::Optional<T> last() REQUIRES(!m_mutex);
-
-    // Get the index of the first row matching the query in this table
-    size_t index_of(Query&& q) REQUIRES(!m_mutex);
-
-    // Get the first index of the given value in this results, or not_found
-    // Throws DetachedAccessorException if row is not attached
-    // Throws IncorrectTableException if row belongs to a different table
-    template<typename T>
-    size_t index_of(T const& value) REQUIRES(!m_mutex);
-
-    // Delete all of the rows in this Results from the Realm
-    // size() will always be zero afterwards
-    // Throws InvalidTransactionException if not in a write transaction
-    void clear() REQUIRES(!m_mutex);
-
-    // Create a new Results by further filtering or sorting this Results
-    Results filter(Query&& q) const REQUIRES(!m_mutex);
-    Results sort(SortDescriptor&& sort) const REQUIRES(!m_mutex);
-    Results sort(std::vector<std::pair<std::string, bool>> const& keypaths) const REQUIRES(!m_mutex);
-
-    // Create a new Results by removing duplicates
-    Results distinct(DistinctDescriptor&& uniqueness) const REQUIRES(!m_mutex);
-    Results distinct(std::vector<std::string> const& keypaths) const REQUIRES(!m_mutex);
-
-    // Create a new Results with only the first `max_count` entries
-    Results limit(size_t max_count) const REQUIRES(!m_mutex);
-
-    // Create a new Results by adding sort and distinct combinations
-    Results apply_ordering(DescriptorOrdering&& ordering) REQUIRES(!m_mutex);
-
-    // Return a snapshot of this Results that never updates to reflect changes in the underlying data.
-    Results snapshot() const& REQUIRES(!m_mutex);
-    Results snapshot() && REQUIRES(!m_mutex);
-
-    // Returns a frozen copy of this result
-    Results freeze(std::shared_ptr<Realm> const& realm) REQUIRES(!m_mutex);
-
-    // Returns whether or not this Results is frozen.
-    bool is_frozen() REQUIRES(!m_mutex);
-
-    // Get the min/max/average/sum of the given column
-    // All but sum() returns none when there are zero matching rows
-    // sum() returns 0, except for when it returns none
-    // Throws UnsupportedColumnTypeException for sum/average on timestamp or non-numeric column
-    // Throws OutOfBoundsIndexException for an out-of-bounds column
-    util::Optional<Mixed> max(ColKey column={}) REQUIRES(!m_mutex);
-    util::Optional<Mixed> min(ColKey column={}) REQUIRES(!m_mutex);
-    util::Optional<double> average(ColKey column={}) REQUIRES(!m_mutex);
-    util::Optional<Mixed> sum(ColKey column={}) REQUIRES(!m_mutex);
-
-    util::Optional<Mixed> max(StringData column_name) REQUIRES(!m_mutex) { return max(key(column_name)); }
-    util::Optional<Mixed> min(StringData column_name) REQUIRES(!m_mutex) { return min(key(column_name)); }
-    util::Optional<double> average(StringData column_name) REQUIRES(!m_mutex) { return average(key(column_name)); }
-    util::Optional<Mixed> sum(StringData column_name) REQUIRES(!m_mutex) { return sum(key(column_name)); }
-
-    enum class Mode {
-        Empty, // Backed by nothing (for missing tables)
-        Table, // Backed directly by a Table
-        List,  // Backed by a list-of-primitives that is not a link list.
-        Query, // Backed by a query that has not yet been turned into a TableView
-        LinkList,  // Backed directly by a LinkList
-        TableView, // Backed by a TableView created from a Query
-    };
-    // Get the currrent mode of the Results
-    // Ideally this would not be public but it's needed for some KVO stuff
-    Mode get_mode() const noexcept REQUIRES(!m_mutex);
-
-    // Is this Results associated with a Realm that has not been invalidated?
-    bool is_valid() const;
-
-    // The Results object has been invalidated (due to the Realm being invalidated)
-    // All non-noexcept functions can throw this
-    struct InvalidatedException : public std::logic_error {
-        InvalidatedException() : std::logic_error("Access to invalidated Results objects") {}
-    };
-
-    // The input index parameter was out of bounds
-    struct OutOfBoundsIndexException : public std::out_of_range {
-        OutOfBoundsIndexException(size_t r, size_t c);
-        const size_t requested;
-        const size_t valid_count;
-    };
-
-    // The input Row object is not attached
-    struct DetatchedAccessorException : public std::logic_error {
-        DetatchedAccessorException() : std::logic_error("Atempting to access an invalid object") {}
-    };
-
-    // The input Row object belongs to a different table
-    struct IncorrectTableException : public std::logic_error {
-        IncorrectTableException(StringData e, StringData a, const std::string &error) :
-            std::logic_error(error), expected(e), actual(a) {}
-        const StringData expected;
-        const StringData actual;
-    };
-
-    // The requested aggregate operation is not supported for the column type
-    struct UnsupportedColumnTypeException : public std::logic_error {
-        ColKey column_key;
-        StringData column_name;
-        PropertyType property_type;
-
-        UnsupportedColumnTypeException(ColKey column, Table const& table, const char* operation);
-        UnsupportedColumnTypeException(ColKey column, TableView const& tv, const char* operation);
-    };
-
-    // The property request does not exist in the schema
-    struct InvalidPropertyException : public std::logic_error {
-        InvalidPropertyException(StringData object_type, StringData property_name);
-        const std::string object_type;
-        const std::string property_name;
-	};
-
-    // The requested operation is valid, but has not yet been implemented
-    struct UnimplementedOperationException : public std::logic_error {
-        UnimplementedOperationException(const char *message);
-    };
-
-    // Create an async query from this Results
-    // The query will be run on a background thread and delivered to the callback,
-    // and then rerun after each commit (if needed) and redelivered if it changed
-    NotificationToken add_notification_callback(CollectionChangeCallback cb) &;
-
-    // Returns whether the rows are guaranteed to be in table order.
-    bool is_in_table_order() const;
-
-    template<typename Context> auto first(Context&) REQUIRES(!m_mutex);
-    template<typename Context> auto last(Context&) REQUIRES(!m_mutex);
-
-    template<typename Context, typename T>
-    size_t index_of(Context&, T value) REQUIRES(!m_mutex);
-
-    // Batch updates all items in this collection with the provided value
-    // Must be called inside a transaction
-    // Throws an exception if the value does not match the type for given prop_name
-    template<typename ValueType, typename ContextType>
-    void set_property_value(ContextType& ctx, StringData prop_name, ValueType value) REQUIRES(!m_mutex);
-
-    // Execute the query immediately if needed. When the relevant query is slow, size()
-    // may cost similar time compared with creating the tableview. Use this function to
-    // avoid running the query twice for size() and other accessors.
-    void evaluate_query_if_needed(bool wants_notifications = true) REQUIRES(!m_mutex);
-
-    enum class UpdatePolicy {
-        Auto,      // Update automatically to reflect changes in the underlying data.
-        AsyncOnly, // Only update via ResultsNotifier and never run queries synchronously
-        Never,     // Never update.
-    };
-    // For tests only. Use snapshot() for normal uses.
-    void set_update_policy(UpdatePolicy policy) { m_update_policy = policy; }
-
-private:
-    std::shared_ptr<Realm> m_realm;
-    mutable util::CopyableAtomic<const ObjectSchema*> m_object_schema = nullptr;
-    Query m_query GUARDED_BY(m_mutex);
-    TableView m_table_view GUARDED_BY(m_mutex);
-    ConstTableRef m_table;
-    DescriptorOrdering m_descriptor_ordering;
-    std::shared_ptr<LnkLst> m_link_list;
-    std::shared_ptr<LstBase> m_list;
-    util::Optional<std::vector<size_t>> m_list_indices GUARDED_BY(m_mutex);
-
-    _impl::CollectionNotifier::Handle<_impl::ResultsNotifierBase> m_notifier;
-
-    Mode m_mode GUARDED_BY(m_mutex) = Mode::Empty;
-    UpdatePolicy m_update_policy = UpdatePolicy::Auto;
-
-    bool update_linklist() REQUIRES(m_mutex);
-
-    void validate_read() const;
-    void validate_write() const;
-
-    size_t do_size() REQUIRES(m_mutex);
-    Query do_get_query() const REQUIRES(m_mutex);
-    PropertyType do_get_type() const REQUIRES(m_mutex);
-
-    using ForCallback = util::TaggedBool<class ForCallback>;
-    void prepare_async(ForCallback);
-
-    ColKey key(StringData) const;
-
-    template<typename T>
-    util::Optional<T> try_get(size_t) REQUIRES(m_mutex);
-
-    template<typename AggregateFunction>
-    util::Optional<Mixed> aggregate(ColKey column, const char* name,
-                                    AggregateFunction&& func) REQUIRES(!m_mutex);
-    DataType prepare_for_aggregate(ColKey column, const char* name) REQUIRES(m_mutex);
-
-    template<typename Fn>
-    auto dispatch(Fn&&) const REQUIRES(!m_mutex);
-
-    template<typename T>
-    auto& list_as() const;
-
-    void evaluate_sort_and_distinct_on_list() REQUIRES(m_mutex);
-    void do_evaluate_query_if_needed(bool wants_notifications = true) REQUIRES(m_mutex);
-
-    class IteratorWrapper {
-    public:
-        IteratorWrapper() = default;
-        IteratorWrapper(IteratorWrapper const&);
-        IteratorWrapper& operator=(IteratorWrapper const&);
-        IteratorWrapper(IteratorWrapper&&) = default;
-        IteratorWrapper& operator=(IteratorWrapper&&) = default;
-
-        Obj get(Table const& table, size_t ndx);
-    private:
-        std::unique_ptr<Table::ConstIterator> m_it;
-    } m_table_iterator;
-
-    util::CheckedOptionalMutex m_mutex;
-
-    // A work around for what appears to be a false positive in clang's thread
-    // analysis when constructing a different object of the same type within a
-    // member function. Putting the ACQUIRE on the constructor seems like it
-    // should work, but doesn't.
-    void assert_unlocked() ACQUIRE(!m_mutex) {}
-};
-
-template<typename Fn>
-auto Results::dispatch(Fn&& fn) const
-{
-    return switch_on_type(get_type(), std::forward<Fn>(fn));
-}
-
-template<typename Context>
-auto Results::get(Context& ctx, size_t row_ndx)
-{
-    return dispatch([&](auto t) { return ctx.box(this->get<std::decay_t<decltype(*t)>>(row_ndx)); });
-}
-
-template<typename Context>
-auto Results::first(Context& ctx)
-{
-    // GCC 4.9 complains about `ctx` not being defined within the lambda without this goofy capture
-    return dispatch([this, ctx = &ctx](auto t) {
-        auto value = this->first<std::decay_t<decltype(*t)>>();
-        return value ? static_cast<decltype(ctx->no_value())>(ctx->box(std::move(*value))) : ctx->no_value();
-    });
-}
-
-template<typename Context>
-auto Results::last(Context& ctx)
-{
-    return dispatch([&](auto t) {
-        auto value = this->last<std::decay_t<decltype(*t)>>();
-        return value ? static_cast<decltype(ctx.no_value())>(ctx.box(std::move(*value))) : ctx.no_value();
-    });
-}
-
-template<typename Context, typename T>
-size_t Results::index_of(Context& ctx, T value)
-{
-    return dispatch([&](auto t) {
-        return this->index_of(ctx.template unbox<std::decay_t<decltype(*t)>>(value, CreatePolicy::Skip));
-    });
-}
-
-template <typename ValueType, typename ContextType>
-void Results::set_property_value(ContextType& ctx, StringData prop_name, ValueType value) NO_THREAD_SAFETY_ANALYSIS
-{
-    // Check invariants for calling this method
-    validate_write();
-    const ObjectSchema& object_schema = get_object_schema();
-    const Property* prop = object_schema.property_for_name(prop_name);
-    if (!prop) {
-        throw InvalidPropertyException(object_schema.name, prop_name);
-    }
-    if (prop->is_primary && !m_realm->is_in_migration()) {
-        throw ModifyPrimaryKeyException(object_schema.name, prop->name);
-    }
-
-    // Update all objects in this ResultSets. Use snapshot to avoid correctness problems if the
-    // object is removed from the TableView after the property update as well as avoiding to
-    // re-evaluating the query too many times.
-    auto snapshot = this->snapshot();
-    size_t size = snapshot.size();
-    for (size_t i = 0; i < size; ++i) {
-        Object obj(m_realm, *m_object_schema, snapshot.get(i));
-        obj.set_property_value_impl(ctx, *prop, value, CreatePolicy::ForceCreate, false);
-    }
-}
-
-} // namespace realm
-
-#endif // REALM_RESULTS_HPP

+ 0 - 258
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/schema.cpp

@@ -1,258 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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 <algorithm>
-
-using namespace realm;
-
-namespace realm {
-bool operator==(Schema const& a, Schema const& b) noexcept
-{
-    return static_cast<Schema::base const&>(a) == static_cast<Schema::base const&>(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<ObjectSchema> 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<Schema *>(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<Schema *>(this)->find(object);
-}
-
-void Schema::validate() const
-{
-    std::vector<ObjectSchemaValidationException> 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);
-    }
-
-    if (exceptions.size()) {
-        throw SchemaValidationException(exceptions);
-    }
-}
-
-static void compare(ObjectSchema const& existing_schema,
-                    ObjectSchema const& target_schema,
-                    std::vector<SchemaChange>& 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, &current_prop});
-            continue;
-        }
-        if (target_schema.property_is_computed(*target_prop)) {
-            changes.emplace_back(schema_change::RemoveProperty{&existing_schema, &current_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, &current_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, &current_prop});
-            else
-                changes.emplace_back(schema_change::MakePropertyNullable{&existing_schema, &current_prop});
-        }
-        if (target_prop->requires_index()) {
-            if (!current_prop.is_indexed)
-                changes.emplace_back(schema_change::AddIndex{&existing_schema, &current_prop});
-        }
-        else if (current_prop.requires_index()) {
-            changes.emplace_back(schema_change::RemoveIndex{&existing_schema, &current_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<typename T, typename U, typename Func>
-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<SchemaChange> Schema::compare(Schema const& target_schema, bool include_table_removals) const
-{
-    std::vector<SchemaChange> 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 (include_table_removals && existing && !target) {
-            changes.emplace_back(schema_change::RemoveTable{existing});
-        }
-    });
-
-    // 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(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

+ 0 - 183
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/schema.hpp

@@ -1,183 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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_SCHEMA_HPP
-#define REALM_SCHEMA_HPP
-
-#include <string>
-#include <vector>
-
-#include <realm/util/features.h>
-
-namespace realm {
-class ObjectSchema;
-class SchemaChange;
-class StringData;
-struct Property;
-
-class Schema : private std::vector<ObjectSchema> {
-private:
-    using base = std::vector<ObjectSchema>;
-public:
-    Schema() noexcept;
-    ~Schema();
-    // Create a schema from a vector of ObjectSchema
-    Schema(base types) noexcept;
-    Schema(std::initializer_list<ObjectSchema> types);
-
-    Schema(Schema const&);
-    Schema(Schema&&) noexcept;
-    Schema& operator=(Schema const&);
-    Schema& operator=(Schema&&) noexcept;
-
-    // find an ObjectSchema by name
-    iterator find(StringData name) noexcept;
-    const_iterator find(StringData name) const noexcept;
-
-    // find an ObjectSchema with the same name as the passed in one
-    iterator find(ObjectSchema const& object) noexcept;
-    const_iterator find(ObjectSchema const& object) const noexcept;
-
-    // Verify that this schema is internally consistent (i.e. all properties are
-    // valid, links link to types that actually exist, etc.)
-    void validate() const;
-
-    // Get the changes which must be applied to this schema to produce the passed-in schema
-    std::vector<SchemaChange> compare(Schema const&, bool include_removals=false) const;
-
-    void copy_keys_from(Schema const&) noexcept;
-
-    friend bool operator==(Schema const&, Schema const&) noexcept;
-    friend bool operator!=(Schema const& a, Schema const& b) noexcept { return !(a == b); }
-
-    using base::iterator;
-    using base::const_iterator;
-    using base::begin;
-    using base::end;
-    using base::empty;
-    using base::size;
-
-private:
-    template<typename T, typename U, typename Func>
-    static void zip_matching(T&& a, U&& b, Func&& func) noexcept;
-};
-
-namespace schema_change {
-struct AddTable {
-    const ObjectSchema* object;
-};
-
-struct RemoveTable {
-    const ObjectSchema* object;
-};
-
-struct AddInitialProperties {
-    const ObjectSchema* object;
-};
-
-struct AddProperty {
-    const ObjectSchema* object;
-    const Property* property;
-};
-
-struct RemoveProperty {
-    const ObjectSchema* object;
-    const Property* property;
-};
-
-struct ChangePropertyType {
-    const ObjectSchema* object;
-    const Property* old_property;
-    const Property* new_property;
-};
-
-struct MakePropertyNullable {
-    const ObjectSchema* object;
-    const Property* property;
-};
-
-struct MakePropertyRequired {
-    const ObjectSchema* object;
-    const Property* property;
-};
-
-struct AddIndex {
-    const ObjectSchema* object;
-    const Property* property;
-};
-
-struct RemoveIndex {
-    const ObjectSchema* object;
-    const Property* property;
-};
-
-struct ChangePrimaryKey {
-    const ObjectSchema* object;
-    const Property* property;
-};
-}
-
-#define REALM_FOR_EACH_SCHEMA_CHANGE_TYPE(macro) \
-    macro(AddTable) \
-    macro(RemoveTable) \
-    macro(AddInitialProperties) \
-    macro(AddProperty) \
-    macro(RemoveProperty) \
-    macro(ChangePropertyType) \
-    macro(MakePropertyNullable) \
-    macro(MakePropertyRequired) \
-    macro(AddIndex) \
-    macro(RemoveIndex) \
-    macro(ChangePrimaryKey) \
-
-class SchemaChange {
-public:
-#define REALM_SCHEMA_CHANGE_CONSTRUCTOR(name) \
-    SchemaChange(schema_change::name value) : m_kind(Kind::name) { name = value; }
-        REALM_FOR_EACH_SCHEMA_CHANGE_TYPE(REALM_SCHEMA_CHANGE_CONSTRUCTOR)
-#undef REALM_SCHEMA_CHANGE_CONSTRUCTOR
-
-    template<typename Visitor>
-    auto visit(Visitor&& visitor) const {
-        switch (m_kind) {
-#define REALM_SWITCH_CASE(name) case Kind::name: return visitor(name);
-        REALM_FOR_EACH_SCHEMA_CHANGE_TYPE(REALM_SWITCH_CASE)
-#undef REALM_SWITCH_CASE
-        }
-        REALM_COMPILER_HINT_UNREACHABLE();
-    }
-
-    friend bool operator==(SchemaChange const& lft, SchemaChange const& rgt) noexcept;
-private:
-    enum class Kind {
-#define REALM_SCHEMA_CHANGE_TYPE(name) name,
-        REALM_FOR_EACH_SCHEMA_CHANGE_TYPE(REALM_SCHEMA_CHANGE_TYPE)
-#undef REALM_SCHEMA_CHANGE_TYPE
-
-    } m_kind;
-    union {
-#define REALM_DEFINE_FIELD(name) schema_change::name name;
-        REALM_FOR_EACH_SCHEMA_CHANGE_TYPE(REALM_DEFINE_FIELD)
-#undef REALM_DEFINE_FIELD
-    };
-};
-
-#undef REALM_FOR_EACH_SCHEMA_CHANGE_TYPE
-}
-
-#endif /* defined(REALM_SCHEMA_HPP) */

+ 0 - 1029
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/shared_realm.cpp

@@ -1,1029 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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 <realm/db.hpp>
-#include <realm/util/scope_exit.hpp>
-#include <realm/util/fifo_helper.hpp>
-
-#if REALM_ENABLE_SYNC
-#include "sync/impl/sync_file.hpp"
-#include "sync/sync_config.hpp"
-#include "sync/sync_manager.hpp"
-
-#include <realm/sync/history.hpp>
-#include <realm/sync/permissions.hpp>
-#include <realm/sync/version.hpp>
-#else
-namespace realm {
-namespace sync {
-    struct PermissionsCache {};
-    struct TableInfoCache {};
-}
-}
-#endif
-
-using namespace realm;
-using namespace realm::_impl;
-
-Realm::Realm(Config config, util::Optional<VersionID> 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);
-    }
-}
-
-bool Realm::is_partial() const noexcept
-{
-#if REALM_ENABLE_SYNC
-    return m_config.sync_config && m_config.sync_config->is_partial;
-#else
-    return false;
-#endif
-}
-
-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<Transaction&>(read_group());
-}
-
-Transaction& Realm::transaction() const
-{
-    REALM_ASSERT(!m_config.immutable());
-    // FIXME: read_group() is not even remotly const
-    return static_cast<Transaction&>(const_cast<Realm*>(this)->read_group());
-}
-
-std::shared_ptr<Transaction> Realm::transaction_ref()
-{
-    return std::static_pointer_cast<Transaction>(m_group);
-}
-
-std::shared_ptr<Transaction> Realm::duplicate() const
-{
-    return std::static_pointer_cast<Transaction>(m_coordinator->begin_read(read_transaction_version(), is_frozen()));
-}
-
-std::shared_ptr<DB>& 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<VersionID>(version));
-    realm->set_auto_refresh(false);
-    return realm;
-}
-
-SharedRealm Realm::get_shared_realm(ThreadSafeReference ref, std::shared_ptr<util::Scheduler> scheduler)
-{
-    if (!scheduler)
-        scheduler = util::Scheduler::make_default();
-    SharedRealm realm = ref.resolve<std::shared_ptr<Realm>>(nullptr);
-    REALM_ASSERT(realm);
-    auto& config = realm->config();
-    auto coordinator = RealmCoordinator::get_coordinator(config.path);
-    realm->m_scheduler = scheduler;
-    coordinator->bind_to_context(*realm);
-    return realm;
-}
-
-#if REALM_ENABLE_SYNC
-std::shared_ptr<AsyncOpenTask> 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<SchemaChange>& 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<SchemaChange>& 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<SchemaChange> 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<SchemaChange> 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<Realm>(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, util::none, wrapper);
-    }
-    else {
-        util::Optional<std::string> sync_user_id;
-#if REALM_ENABLE_SYNC
-        if (m_config.sync_config && m_config.sync_config->is_partial)
-            sync_user_id = m_config.sync_config->user->identity();
-#endif
-        ObjectStore::apply_schema_changes(transaction(), m_schema_version, schema, version,
-                                          m_config.schema_mode, required_changes, std::move(sync_user_id));
-        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);
-        invalidate_permission_cache();
-        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<Transaction&>(*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<VersionID> Realm::current_transaction_version() const
-{
-    util::Optional<VersionID> ret;
-    if (m_group) {
-        ret = static_cast<Transaction&>(*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();
-    invalidate_permission_cache();
-}
-
-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());
-    invalidate_permission_cache();
-}
-
-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_permissions_cache = nullptr;
-    m_table_info_cache = nullptr;
-    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[]>((char*)buffer.data()), buffer.size());
-}
-
-void Realm::notify()
-{
-    if (is_closed() || is_in_transaction() || is_frozen()) {
-        return;
-    }
-
-    verify_thread();
-    invalidate_permission_cache();
-
-    // 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;
-    }
-    invalidate_permission_cache();
-
-    // 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;
-    config.scheduler = util::Scheduler::get_frozen();
-    return Realm::get_frozen_realm(std::move(config), read_transaction_version());
-}
-
-void Realm::close()
-{
-    if (m_coordinator) {
-        m_coordinator->unregister_realm(this);
-    }
-    if (!m_config.immutable() && m_group) {
-        transaction().close();
-    }
-
-    m_permissions_cache = nullptr;
-    m_table_info_cache = nullptr;
-    m_group = nullptr;
-    m_binding_context = nullptr;
-    m_coordinator = nullptr;
-}
-
-AuditInterface* Realm::audit_context() const noexcept
-{
-    return m_coordinator ? m_coordinator->audit_context() : nullptr;
-}
-
-#if REALM_ENABLE_SYNC
-static_assert(static_cast<int>(ComputedPrivileges::Read) == static_cast<int>(sync::Privilege::Read), "");
-static_assert(static_cast<int>(ComputedPrivileges::Update) == static_cast<int>(sync::Privilege::Update), "");
-static_assert(static_cast<int>(ComputedPrivileges::Delete) == static_cast<int>(sync::Privilege::Delete), "");
-static_assert(static_cast<int>(ComputedPrivileges::SetPermissions) == static_cast<int>(sync::Privilege::SetPermissions), "");
-static_assert(static_cast<int>(ComputedPrivileges::Query) == static_cast<int>(sync::Privilege::Query), "");
-static_assert(static_cast<int>(ComputedPrivileges::Create) == static_cast<int>(sync::Privilege::Create), "");
-static_assert(static_cast<int>(ComputedPrivileges::ModifySchema) == static_cast<int>(sync::Privilege::ModifySchema), "");
-
-static constexpr const uint8_t s_allRealmPrivileges = sync::Privilege::Read
-                                                    | sync::Privilege::Update
-                                                    | sync::Privilege::SetPermissions
-                                                    | sync::Privilege::ModifySchema;
-static constexpr const uint8_t s_allClassPrivileges = sync::Privilege::Read
-                                                    | sync::Privilege::Update
-                                                    | sync::Privilege::Create
-                                                    | sync::Privilege::Query
-                                                    | sync::Privilege::SetPermissions;
-static constexpr const uint8_t s_allObjectPrivileges = sync::Privilege::Read
-                                                     | sync::Privilege::Update
-                                                     | sync::Privilege::Delete
-                                                     | sync::Privilege::SetPermissions;
-
-bool Realm::init_permission_cache()
-{
-    verify_thread();
-
-    if (m_permissions_cache) {
-        // Rather than trying to track changes to permissions tables, just skip the caching
-        // entirely within write transactions for now
-        if (is_in_transaction())
-            m_permissions_cache->clear();
-        return true;
-    }
-
-    // Admin users bypass permissions checks outside of the logic in PermissionsCache
-    if (m_config.sync_config && m_config.sync_config->is_partial && !m_config.sync_config->user->is_admin()) {
-        m_table_info_cache = std::make_unique<sync::TableInfoCache>(transaction());
-        m_permissions_cache = std::make_unique<sync::PermissionsCache>(transaction(), *m_table_info_cache,
-                                                                       m_config.sync_config->user->identity());
-        return true;
-    }
-    return false;
-}
-
-void Realm::invalidate_permission_cache()
-{
-    if (m_permissions_cache)
-        m_permissions_cache->clear();
-}
-
-ComputedPrivileges Realm::get_privileges()
-{
-    if (!init_permission_cache())
-        return static_cast<ComputedPrivileges>(s_allRealmPrivileges);
-    return static_cast<ComputedPrivileges>(m_permissions_cache->get_realm_privileges() & s_allRealmPrivileges);
-}
-
-static uint8_t inherited_mask(uint32_t privileges)
-{
-    uint8_t mask = ~0;
-    if (!(privileges & sync::Privilege::Read))
-        mask = 0;
-    else if (!(privileges & sync::Privilege::Update))
-        mask = static_cast<uint8_t>(sync::Privilege::Read | sync::Privilege::Query);
-    return mask;
-}
-
-ComputedPrivileges Realm::get_privileges(StringData object_type)
-{
-    if (!init_permission_cache())
-        return static_cast<ComputedPrivileges>(s_allClassPrivileges);
-    auto privileges = inherited_mask(m_permissions_cache->get_realm_privileges())
-                    & m_permissions_cache->get_class_privileges(object_type);
-    return static_cast<ComputedPrivileges>(privileges & s_allClassPrivileges);
-}
-
-ComputedPrivileges Realm::get_privileges(ConstObj const& obj)
-{
-    if (!init_permission_cache())
-        return static_cast<ComputedPrivileges>(s_allObjectPrivileges);
-
-    auto table = obj.get_table();
-    auto object_type = ObjectStore::object_type_for_table_name(table->get_name());
-    sync::GlobalID global_id{object_type, table->get_object_id(obj.get_key())};
-    auto privileges = inherited_mask(m_permissions_cache->get_realm_privileges())
-                    & inherited_mask(m_permissions_cache->get_class_privileges(object_type))
-                    & m_permissions_cache->get_object_privileges(global_id);
-    return static_cast<ComputedPrivileges>(privileges & s_allObjectPrivileges);
-}
-#else
-void Realm::invalidate_permission_cache() { }
-#endif
-
-MismatchedConfigException::MismatchedConfigException(StringData message, StringData path)
-: std::logic_error(util::format(message.data(), path)) { }
-
-MismatchedRealmException::MismatchedRealmException(StringData message)
-: std::logic_error(message.data()) { }
-

+ 0 - 540
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/shared_realm.hpp

@@ -1,540 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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_REALM_HPP
-#define REALM_REALM_HPP
-
-#include "schema.hpp"
-
-#include <realm/util/optional.hpp>
-#include <realm/binary_data.hpp>
-#include <realm/db.hpp>
-#include <realm/version_id.hpp>
-
-#if REALM_ENABLE_SYNC
-#include <realm/sync/client.hpp>
-#endif
-
-#include <memory>
-
-namespace realm {
-class AsyncOpenTask;
-class AuditInterface;
-class BindingContext;
-class DB;
-class Group;
-class Obj;
-class Realm;
-class Replication;
-class StringData;
-class Table;
-class ThreadSafeReference;
-class Transaction;
-struct SyncConfig;
-typedef std::shared_ptr<Realm> SharedRealm;
-typedef std::weak_ptr<Realm> WeakRealm;
-
-namespace util {
-class Scheduler;
-}
-
-namespace _impl {
-    class AnyHandover;
-    class CollectionNotifier;
-    class PartialSyncHelper;
-    class RealmCoordinator;
-    class RealmFriend;
-}
-namespace sync {
-    struct PermissionsCache;
-    struct TableInfoCache;
-}
-
-// How to handle update_schema() being called on a file which has
-// already been initialized with a different schema
-enum class SchemaMode : uint8_t {
-    // If the schema version has increased, automatically apply all
-    // changes, then call the migration function.
-    //
-    // If the schema version has not changed, verify that the only
-    // changes are to add new tables and add or remove indexes, and then
-    // apply them if so. Does not call the migration function.
-    //
-    // This mode does not automatically remove tables which are not
-    // present in the schema that must be manually done in the migration
-    // function, to support sharing a Realm file between processes using
-    // different class subsets.
-    //
-    // This mode allows using schemata with different subsets of tables
-    // on different threads, but the tables which are shared must be
-    // identical.
-    Automatic,
-
-    // Open the file in immutable mode. Schema version must match the
-    // version in the file, and all tables present in the file must
-    // exactly match the specified schema, except for indexes. Tables
-    // are allowed to be missing from the file.
-    // WARNING: This is the original ReadOnly mode.
-    Immutable,
-
-    // Open the Realm in read-only mode, transactions are not allowed to
-    // be performed on the Realm instance. The schema of the existing Realm
-    // file won't be changed through this Realm instance. Extra tables and
-    // extra properties are allowed in the existing Realm schema. The
-    // difference of indexes is allowed as well. Other schema differences
-    // than those will cause an exception. This is different from Immutable
-    // mode, sync Realm can be opened with ReadOnly mode. Changes
-    // can be made to the Realm file through another writable Realm instance.
-    // Thus, notifications are also allowed in this mode.
-    // FIXME: Rename this to ReadOnly
-    // WARNING: This is not the original ReadOnly mode. The original ReadOnly
-    // has been renamed to Immutable.
-    ReadOnlyAlternative,
-
-    // If the schema version matches and the only schema changes are new
-    // tables and indexes being added or removed, apply the changes to
-    // the existing file.
-    // Otherwise delete the file and recreate it from scratch.
-    // The migration function is not used.
-    //
-    // This mode allows using schemata with different subsets of tables
-    // on different threads, but the tables which are shared must be
-    // identical.
-    ResetFile,
-
-    // The only changes allowed are to add new tables, add columns to
-    // existing tables, and to add or remove indexes from existing
-    // columns. Extra tables not present in the schema are ignored.
-    // Indexes are only added to or removed from existing columns if the
-    // schema version is greater than the existing one (and unlike other
-    // modes, the schema version is allowed to be less than the existing
-    // one).
-    // The migration function is not used.
-    //
-    // This mode allows updating the schema with additive changes even
-    // if the Realm is already open on another thread.
-    Additive,
-
-    // Verify that the schema version has increased, call the migraiton
-    // function, and then verify that the schema now matches.
-    // The migration function is mandatory for this mode.
-    //
-    // This mode requires that all threads and processes which open a
-    // file use identical schemata.
-    Manual
-};
-
-enum class ComputedPrivileges : uint8_t {
-    None = 0,
-
-    Read = (1 << 0),
-    Update = (1 << 1),
-    Delete = (1 << 2),
-    SetPermissions = (1 << 3),
-    Query = (1 << 4),
-    Create = (1 << 5),
-    ModifySchema = (1 << 6),
-
-    AllRealm = Read | Update | SetPermissions | ModifySchema,
-    AllClass = Read | Update | Create | Query | SetPermissions,
-    AllObject = Read | Update | Delete | SetPermissions,
-    All = (1 << 7) - 1
-};
-
-class Realm : public std::enable_shared_from_this<Realm> {
-public:
-    // A callback function to be called during a migration for Automatic and
-    // Manual schema modes. It is passed a SharedRealm at the version before
-    // the migration, the SharedRealm in the migration, and a mutable reference
-    // to the realm's Schema. Updating the schema with changes made within the
-    // migration function is only required if you wish to use the ObjectStore
-    // functions which take a Schema from within the migration function.
-    using MigrationFunction = std::function<void (SharedRealm old_realm, SharedRealm realm, Schema&)>;
-
-    // A callback function to be called the first time when a schema is created.
-    // It is passed a SharedRealm which is in a write transaction with the schema
-    // initialized. So it is possible to create some initial objects inside the callback
-    // with the given SharedRealm. Those changes will be committed together with the
-    // schema creation in a single transaction.
-    using DataInitializationFunction = std::function<void (SharedRealm realm)>;
-
-    // A callback function called when opening a SharedRealm when no cached
-    // version of this Realm exists. It is passed the total bytes allocated for
-    // the file (file size) and the total bytes used by data in the file.
-    // Return `true` to indicate that an attempt to compact the file should be made
-    // if it is possible to do so.
-    // Won't compact the file if another process is accessing it.
-    //
-    // WARNING / FIXME: compact() should NOT be exposed publicly on Windows
-    // because it's not crash safe! It may corrupt your database if something fails
-    using ShouldCompactOnLaunchFunction = std::function<bool (uint64_t total_bytes, uint64_t used_bytes)>;
-
-    struct Config {
-        // Path and binary data are mutually exclusive
-        std::string path;
-        BinaryData realm_data;
-        // User-supplied encryption key. Must be either empty or 64 bytes.
-        std::vector<char> encryption_key;
-
-        // Core and Object Store will in some cases need to create named pipes alongside the Realm file.
-        // But on some filesystems this can be a problem (e.g. external storage on Android that uses FAT32).
-        // In order to work around this, a separate path can be specified for these files.
-        std::string fifo_files_fallback_path;
-
-        bool in_memory = false;
-        SchemaMode schema_mode = SchemaMode::Automatic;
-
-        // Optional schema for the file.
-        // If the schema and schema version are supplied, update_schema() is
-        // called with the supplied schema, version and migration function when
-        // the Realm is actually opened and not just retrieved from the cache
-        util::Optional<Schema> schema;
-        uint64_t schema_version = -1;
-        MigrationFunction migration_function;
-
-        DataInitializationFunction initialization_function;
-
-        // A callback function called when opening a SharedRealm when no cached
-        // version of this Realm exists. It is passed the total bytes allocated for
-        // the file (file size) and the total bytes used by data in the file.
-        // Return `true` to indicate that an attempt to compact the file should be made
-        // if it is possible to do so.
-        // Won't compact the file if another process is accessing it.
-        //
-        // WARNING / FIXME: compact() should NOT be exposed publicly on Windows
-        // because it's not crash safe! It may corrupt your database if something fails
-        ShouldCompactOnLaunchFunction should_compact_on_launch_function;
-
-        // WARNING: The original read_only() has been renamed to immutable().
-        bool immutable() const { return schema_mode == SchemaMode::Immutable; }
-        // FIXME: Rename this to read_only().
-        bool read_only_alternative() const { return schema_mode == SchemaMode::ReadOnlyAlternative; }
-
-        // The following are intended for internal/testing purposes and
-        // should not be publicly exposed in binding APIs
-
-        // Throw an exception rather than automatically upgrading the file
-        // format. Used by the browser to warn the user that it'll modify
-        // the file.
-        bool disable_format_upgrade = false;
-        // Disable the background worker thread for producing change
-        // notifications. Useful for tests for those notifications so that
-        // everything can be done deterministically on one thread, and
-        // speeds up tests that don't need notifications.
-        bool automatic_change_notifications = true;
-
-        // The Scheduler which this Realm should be bound to. If not supplied,
-        // a default one for the current thread will be used.
-        std::shared_ptr<util::Scheduler> scheduler;
-
-        /// A data structure storing data used to configure the Realm for sync support.
-        std::shared_ptr<SyncConfig> sync_config;
-
-        // Open the Realm using the sync history mode even if a sync
-        // configuration is not supplied.
-        bool force_sync_history = false;
-
-        // A factory function which produces an audit implementation.
-        std::function<std::shared_ptr<AuditInterface>()> audit_factory;
-
-        // Maximum number of active versions in the Realm file allowed before an exception
-        // is thrown.
-        uint_fast64_t max_number_of_active_versions = std::numeric_limits<uint_fast64_t>::max();
-    };
-
-    // Returns a thread-confined live Realm for the given configuration
-    static SharedRealm get_shared_realm(Config config);
-
-    // Get a Realm for the given scheduler (or current thread if `none`)
-    // from the thread safe reference.
-    static SharedRealm get_shared_realm(ThreadSafeReference, std::shared_ptr<util::Scheduler> = nullptr);
-
-#if REALM_ENABLE_SYNC
-    // Open a synchronized Realm and make sure it is fully up to date before
-    // returning it.
-    //
-    // It is possible to both cancel the download and listen to download progress
-    // using the `AsyncOpenTask` returned. Note that the download doesn't actually
-    // start until you call `AsyncOpenTask::start(callback)`
-    static std::shared_ptr<AsyncOpenTask> get_synchronized_realm(Config config);
-#endif
-    // Returns a frozen Realm for the given Realm. This Realm can be accessed from any thread.
-    static SharedRealm get_frozen_realm(Config config, VersionID version);
-
-    // Updates a Realm to a given schema, using the Realm's pre-set schema mode.
-    void update_schema(Schema schema, uint64_t version=0,
-                       MigrationFunction migration_function=nullptr,
-                       DataInitializationFunction initialization_function=nullptr,
-                       bool in_transaction=false);
-
-    // Set the schema used for this Realm, but do not update the file's schema
-    // if it is not compatible (and instead throw an error).
-    // Cannot be called multiple times on a single Realm instance or an instance
-    // which has already had update_schema() called on it.
-    void set_schema_subset(Schema schema);
-
-    // Read the schema version from the file specified by the given config, or
-    // ObjectStore::NotVersioned if it does not exist
-    static uint64_t get_schema_version(Config const& config);
-
-    Config const& config() const { return m_config; }
-    Schema const& schema() const { return m_schema; }
-    uint64_t schema_version() const { return m_schema_version; }
-
-    // Returns `true` if this Realm is a Partially synchronized Realm.
-    bool is_partial() const noexcept;
-
-    void begin_transaction();
-    void commit_transaction();
-    void cancel_transaction();
-    bool is_in_transaction() const noexcept;
-
-    // Returns a frozen copy for the current version of this Realm
-    SharedRealm freeze();
-
-    // Returns `true` if the Realm is frozen, `false` otherwise.
-    bool is_frozen() const;
-
-    // Returns true if the Realm is either in a read or frozen transaction
-    bool is_in_read_transaction() const { return m_group != nullptr; }
-    uint64_t last_seen_transaction_version() { return m_schema_transaction_version; }
-
-    // Returns the number of versions in the Realm file.
-    uint_fast64_t get_number_of_versions() const;
-
-    VersionID read_transaction_version() const;
-    Group& read_group();
-
-    // Get the version of the current read or frozen transaction, or `none` if the Realm
-    // is not in a read transaction
-    util::Optional<VersionID> current_transaction_version() const;
-
-    TransactionRef duplicate() const;
-
-    void enable_wait_for_change();
-    bool wait_for_change();
-    void wait_for_change_release();
-
-    bool is_in_migration() const noexcept { return m_in_migration; }
-
-    bool refresh();
-    void set_auto_refresh(bool auto_refresh);
-    bool auto_refresh() const { return m_auto_refresh; }
-    void notify();
-
-    void invalidate();
-
-    // WARNING / FIXME: compact() should NOT be exposed publicly on Windows
-    // because it's not crash safe! It may corrupt your database if something fails
-    bool compact();
-    void write_copy(StringData path, BinaryData encryption_key);
-    OwnedBinaryData write_copy();
-
-    void verify_thread() const;
-    void verify_in_write() const;
-    void verify_open() const;
-    bool verify_notifications_available(bool throw_on_error = true) const;
-
-    bool can_deliver_notifications() const noexcept;
-    std::shared_ptr<util::Scheduler> scheduler() const noexcept { return m_scheduler; }
-
-    // Close this Realm. Continuing to use a Realm after closing it will throw ClosedRealmException
-    void close();
-    bool is_closed() const { return !m_group && !m_coordinator; }
-
-    // returns the file format version upgraded from if an upgrade took place
-    util::Optional<int> file_format_upgraded_from_version() const;
-
-    Realm(const Realm&) = delete;
-    Realm& operator=(const Realm&) = delete;
-    Realm(Realm&&) = delete;
-    Realm& operator=(Realm&&) = delete;
-    ~Realm();
-
-    ComputedPrivileges get_privileges();
-    ComputedPrivileges get_privileges(StringData object_type);
-    ComputedPrivileges get_privileges(ConstObj const& obj);
-
-    AuditInterface* audit_context() const noexcept;
-
-    template<typename... Args>
-    auto import_copy_of(Args&&... args)
-    {
-        return transaction().import_copy_of(std::forward<Args>(args)...);
-    }
-
-    static SharedRealm make_shared_realm(Config config, util::Optional<VersionID> version, std::shared_ptr<_impl::RealmCoordinator> coordinator)
-    {
-        return std::make_shared<Realm>(std::move(config), std::move(version), std::move(coordinator), MakeSharedTag{});
-    }
-
-    // Expose some internal functionality to other parts of the ObjectStore
-    // without making it public to everyone
-    class Internal {
-        friend class _impl::CollectionNotifier;
-        friend class _impl::PartialSyncHelper;
-        friend class _impl::RealmCoordinator;
-        friend class GlobalNotifier;
-        friend class TestHelper;
-        friend class ThreadSafeReference;
-
-        static Transaction& get_transaction(Realm& realm) { return realm.transaction(); }
-        static std::shared_ptr<Transaction> get_transaction_ref(Realm& realm) { return realm.transaction_ref(); }
-
-        // CollectionNotifier needs to be able to access the owning
-        // coordinator to wake up the worker thread when a callback is
-        // added, and coordinators need to be able to get themselves from a Realm
-        static _impl::RealmCoordinator& get_coordinator(Realm& realm) { return *realm.m_coordinator; }
-
-        static std::shared_ptr<DB>& get_db(Realm& realm);
-        static void begin_read(Realm&, VersionID);
-    };
-
-private:
-    struct MakeSharedTag {};
-
-    std::shared_ptr<_impl::RealmCoordinator> m_coordinator;
-    std::unique_ptr<sync::TableInfoCache> m_table_info_cache;
-    std::unique_ptr<sync::PermissionsCache> m_permissions_cache;
-
-    Config m_config;
-    util::Optional<VersionID> m_frozen_version;
-    std::shared_ptr<util::Scheduler> m_scheduler;
-    bool m_auto_refresh = true;
-
-    std::shared_ptr<Group> m_group;
-
-    uint64_t m_schema_version;
-    Schema m_schema;
-    util::Optional<Schema> m_new_schema;
-    uint64_t m_schema_transaction_version = -1;
-
-    // FIXME: this should be a Dynamic schema mode instead, but only once
-    // that's actually fully working
-    bool m_dynamic_schema = true;
-
-    // True while sending the notifications caused by advancing the read
-    // transaction version, to avoid recursive notifications where possible
-    bool m_is_sending_notifications = false;
-
-    // True while we're performing a schema migration via this Realm instance
-    // to allow for different behavior (such as allowing modifications to
-    // primary key values)
-    bool m_in_migration = false;
-
-    void begin_read(VersionID);
-    bool do_refresh();
-
-    void set_schema(Schema const& reference, Schema schema);
-    bool reset_file(Schema& schema, std::vector<SchemaChange>& changes_required);
-    bool schema_change_needs_write_transaction(Schema& schema, std::vector<SchemaChange>& changes, uint64_t version);
-    Schema get_full_schema();
-
-    // Ensure that m_schema and m_schema_version match that of the current
-    // version of the file
-    void read_schema_from_group_if_needed();
-
-    void add_schema_change_handler();
-    void cache_new_schema();
-    void translate_schema_error();
-    void notify_schema_changed();
-
-    bool init_permission_cache();
-    void invalidate_permission_cache();
-
-    Transaction& transaction();
-    Transaction& transaction() const;
-    std::shared_ptr<Transaction> transaction_ref();
-
-public:
-    std::unique_ptr<BindingContext> m_binding_context;
-
-    // `enable_shared_from_this` is unsafe with public constructors; use `make_shared_realm` instead
-    Realm(Config config, util::Optional<VersionID> version, std::shared_ptr<_impl::RealmCoordinator> coordinator, MakeSharedTag);
-};
-
-class RealmFileException : public std::runtime_error {
-public:
-    enum class Kind {
-        /** Thrown for any I/O related exception scenarios when a realm is opened. */
-        AccessError,
-        /** Thrown if the history type of the on-disk Realm is unexpected or incompatible. */
-        BadHistoryError,
-        /** Thrown if the user does not have permission to open or create
-         the specified file in the specified access mode when the realm is opened. */
-        PermissionDenied,
-        /** Thrown if create_Always was specified and the file did already exist when the realm is opened. */
-        Exists,
-        /** Thrown if no_create was specified and the file was not found when the realm is opened. */
-        NotFound,
-        /** Thrown if the database file is currently open in another
-         process which cannot share with the current process due to an
-         architecture mismatch. */
-        IncompatibleLockFile,
-        /** Thrown if the file needs to be upgraded to a new format, but upgrades have been explicitly disabled. */
-        FormatUpgradeRequired,
-    };
-    RealmFileException(Kind kind, std::string path, std::string message, std::string underlying)
-    : std::runtime_error(std::move(message)), m_kind(kind), m_path(std::move(path)), m_underlying(std::move(underlying)) {}
-    Kind kind() const { return m_kind; }
-    const std::string& path() const { return m_path; }
-    const std::string& underlying() const { return m_underlying; }
-
-private:
-    Kind m_kind;
-    std::string m_path;
-    std::string m_underlying;
-};
-
-class MismatchedConfigException : public std::logic_error {
-public:
-    MismatchedConfigException(StringData message, StringData path);
-};
-
-class MismatchedRealmException : public std::logic_error {
-public:
-    MismatchedRealmException(StringData message);
-};
-
-class InvalidTransactionException : public std::logic_error {
-public:
-    InvalidTransactionException(std::string message) : std::logic_error(message) {}
-};
-
-class IncorrectThreadException : public std::logic_error {
-public:
-    IncorrectThreadException() : std::logic_error("Realm accessed from incorrect thread.") {}
-};
-
-class ClosedRealmException : public std::logic_error {
-public:
-    ClosedRealmException() : std::logic_error("Cannot access realm that has been closed.") {}
-};
-
-class UninitializedRealmException : public std::runtime_error {
-public:
-    UninitializedRealmException(std::string message) : std::runtime_error(message) {}
-};
-
-class InvalidEncryptionKeyException : public std::logic_error {
-public:
-    InvalidEncryptionKeyException() : std::logic_error("Encryption key must be 64 bytes.") {}
-};
-} // namespace realm
-
-#endif /* defined(REALM_REALM_HPP) */

+ 0 - 243
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/thread_safe_reference.cpp

@@ -1,243 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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 <realm/db.hpp>
-#include <realm/keys.hpp>
-
-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<List> : 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<Realm> 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<Object> : 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<Realm> 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<Results> : 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<Realm> 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 (InvalidKey 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(*table, m_col_key), [&](auto* t) -> void {
-                    list = std::make_unique<Lst<NonObjTypeT<decltype(*t)>>>();
-                });
-            }
-            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<Query> m_query;
-    ObjKey m_key;
-    TableKey m_table_key;
-    ColKey m_col_key;
-};
-
-template<>
-class ThreadSafeReference::PayloadImpl<std::shared_ptr<Realm>> : public ThreadSafeReference::Payload {
-public:
-    PayloadImpl(std::shared_ptr<Realm> const& realm)
-    : Payload(*realm)
-    , m_realm(realm)
-    {
-    }
-
-    std::shared_ptr<Realm> get_realm()
-    {
-        return std::move(m_realm);
-    }
-
-private:
-    std::shared_ptr<Realm> m_realm;
-};
-
-ThreadSafeReference::ThreadSafeReference() noexcept = default;
-ThreadSafeReference::~ThreadSafeReference() = default;
-ThreadSafeReference::ThreadSafeReference(ThreadSafeReference&&) noexcept = default;
-ThreadSafeReference& ThreadSafeReference::operator=(ThreadSafeReference&&) noexcept = default;
-
-template<typename T>
-ThreadSafeReference::ThreadSafeReference(T const& value)
-{
-    auto realm = value.get_realm();
-    realm->verify_thread();
-    m_payload.reset(new PayloadImpl<T>(value));
-}
-
-template<>
-ThreadSafeReference::ThreadSafeReference(std::shared_ptr<Realm> const& value)
-{
-    m_payload.reset(new PayloadImpl<std::shared_ptr<Realm>>(value));
-}
-
-template ThreadSafeReference::ThreadSafeReference(List const&);
-template ThreadSafeReference::ThreadSafeReference(Results const&);
-template ThreadSafeReference::ThreadSafeReference(Object const&);
-
-template<typename T>
-T ThreadSafeReference::resolve(std::shared_ptr<Realm> const& realm)
-{
-    REALM_ASSERT(realm);
-    realm->verify_thread();
-
-    REALM_ASSERT(m_payload);
-    auto& payload = static_cast<PayloadImpl<T>&>(*m_payload);
-    REALM_ASSERT(typeid(payload) == typeid(PayloadImpl<T>));
-
-    m_payload->refresh_target_realm(*realm);
-    try {
-        return payload.import_into(realm);
-    }
-    catch (InvalidKey const&) {
-        // Object was deleted in a version after when the TSR was created
-        return {};
-    }
-}
-
-template<>
-std::shared_ptr<Realm> ThreadSafeReference::resolve<std::shared_ptr<Realm>>(std::shared_ptr<Realm> const&)
-{
-    REALM_ASSERT(m_payload);
-    auto& payload = static_cast<PayloadImpl<std::shared_ptr<Realm>>&>(*m_payload);
-    REALM_ASSERT(typeid(payload) == typeid(PayloadImpl<std::shared_ptr<Realm>>));
-
-    return payload.get_realm();
-}
-
-template Results ThreadSafeReference::resolve<Results>(std::shared_ptr<Realm> const&);
-template List ThreadSafeReference::resolve<List>(std::shared_ptr<Realm> const&);
-template Object ThreadSafeReference::resolve<Object>(std::shared_ptr<Realm> const&);
-
-} // namespace realm

+ 0 - 59
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/thread_safe_reference.hpp

@@ -1,59 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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_OS_THREAD_SAFE_REFERENCE_HPP
-#define REALM_OS_THREAD_SAFE_REFERENCE_HPP
-
-#include <memory>
-
-namespace realm {
-class List;
-class Object;
-class Realm;
-class Results;
-
-// Opaque type-ereased wrapper for a Realm object which can be imported into another Realm
-class ThreadSafeReference {
-public:
-    ThreadSafeReference() noexcept;
-    ~ThreadSafeReference();
-    ThreadSafeReference(const ThreadSafeReference&) = delete;
-    ThreadSafeReference& operator=(const ThreadSafeReference&) = delete;
-    ThreadSafeReference(ThreadSafeReference&&) noexcept;
-    ThreadSafeReference& operator=(ThreadSafeReference&&) noexcept;
-
-    template<typename T>
-    ThreadSafeReference(T const& value);
-
-    // Import the object into the destination Realm
-    template<typename T>
-    T resolve(std::shared_ptr<Realm> const&);
-
-    explicit operator bool() const noexcept { return !!m_payload; }
-
-private:
-    class Payload;
-    template<typename> class PayloadImpl;
-    std::unique_ptr<Payload> m_payload;
-};
-
-template<> ThreadSafeReference::ThreadSafeReference(std::shared_ptr<Realm> const&);
-template<> std::shared_ptr<Realm> ThreadSafeReference::resolve(std::shared_ptr<Realm> const&);
-}
-
-#endif /* REALM_OS_THREAD_SAFE_REFERENCE_HPP */

+ 0 - 65
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/util/aligned_union.hpp

@@ -1,65 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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 utilied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////
-
-#ifndef REALM_OS_ALIGNED_UNION_HPP
-#define REALM_OS_ALIGNED_UNION_HPP
-
-#include <cstddef>
-#include <initializer_list>
-#include <type_traits>
-
-namespace realm {
-
-// Provide our own implementation of max as GCC 4.9's is not marked as constexpr.
-namespace _impl {
-
-template <typename T>
-static constexpr const T& constexpr_max(const T& a, const T& b)
-{
-    return a > b ? a : b;
-}
-
-template <typename T>
-static constexpr const T& constexpr_max(const T* begin, const T *end)
-{
-    return begin + 1 == end ? *begin : constexpr_max(*begin, constexpr_max(begin + 1, end));
-}
-
-template <typename T>
-static constexpr const T& constexpr_max(std::initializer_list<T> list)
-{
-    return constexpr_max(list.begin(), list.end());
-}
-
-} // namespace _impl
-
-namespace util {
-
-// Provide our own implementation of `std::aligned_union` as it is missing from GCC 4.9.
-template <size_t Len, typename... Types>
-struct AlignedUnion
-{
-    static constexpr size_t alignment_value = _impl::constexpr_max({alignof(Types)...});
-    static constexpr size_t storage_size = _impl::constexpr_max({Len, sizeof(Types)...});
-    using type = typename std::aligned_storage<storage_size, alignment_value>::type;
-};
-
-} // namespace util
-} // namespace realm
-
-#endif // REALM_OS_ALIGNED_UNION_HPP

+ 0 - 148
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/util/atomic_shared_ptr.hpp

@@ -1,148 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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_ATOMIC_SHARED_PTR_HPP
-#define REALM_ATOMIC_SHARED_PTR_HPP
-
-#include <atomic>
-#include <memory>
-#include <mutex>
-
-namespace realm {
-namespace _impl {
-
-// Check if std::atomic_load has an overload taking a std::shared_ptr, and set
-// HasAtomicPtrOps to either true_type or false_type
-
-template<typename... Ts> struct make_void { typedef void type; };
-template<typename... Ts> using void_t = typename make_void<Ts...>::type;
-
-template<typename, typename = void_t<>>
-struct HasAtomicPtrOps : std::false_type { };
-
-template<class T>
-struct HasAtomicPtrOps<T, void_t<decltype(std::atomic_load(std::declval<T*>()))>> : std::true_type { };
-} // namespace _impl
-
-namespace util {
-// A wrapper for std::shared_ptr that enables sharing a shared_ptr instance
-// (and not just a thing *pointed to* by a shared_ptr) between threads. Is
-// lock-free iff the underlying shared_ptr implementation supports atomic
-// operations. Currently the only implemented operation other than copy/move
-// construction/assignment is exchange().
-template<typename T, bool = _impl::HasAtomicPtrOps<std::shared_ptr<T>>::value>
-class AtomicSharedPtr;
-
-template<typename T>
-class AtomicSharedPtr<T, true> {
-public:
-    AtomicSharedPtr() = default;
-    AtomicSharedPtr(std::shared_ptr<T> ptr) : m_ptr(std::move(ptr)) { }
-
-    AtomicSharedPtr(AtomicSharedPtr const& ptr) : m_ptr(std::atomic_load(&ptr.m_ptr)) { }
-    AtomicSharedPtr(AtomicSharedPtr&& ptr) : m_ptr(std::atomic_exchange(&ptr.m_ptr, {})) { }
-
-    AtomicSharedPtr& operator=(AtomicSharedPtr const& ptr)
-    {
-        if (&ptr != this) {
-            std::atomic_store(&m_ptr, std::atomic_load(&ptr.m_ptr));
-        }
-        return *this;
-    }
-
-    AtomicSharedPtr& operator=(AtomicSharedPtr&& ptr)
-    {
-        std::atomic_store(&m_ptr, std::atomic_exchange(&ptr.m_ptr, {}));
-        return *this;
-    }
-
-    std::shared_ptr<T> exchange(std::shared_ptr<T> ptr)
-    {
-        return std::atomic_exchange(&m_ptr, std::move(ptr));
-    }
-
-    std::shared_ptr<T> load() const noexcept
-    {
-        return std::atomic_load(&m_ptr);
-    }
-
-private:
-    std::shared_ptr<T> m_ptr = nullptr;
-};
-
-template<typename T>
-class AtomicSharedPtr<T, false> {
-public:
-    AtomicSharedPtr() = default;
-    AtomicSharedPtr(std::shared_ptr<T> ptr) : m_ptr(std::move(ptr)) { }
-
-    AtomicSharedPtr(AtomicSharedPtr const& ptr)
-    {
-        std::lock_guard<std::mutex> lock(ptr.m_mutex);
-        m_ptr = ptr.m_ptr;
-    }
-    AtomicSharedPtr(AtomicSharedPtr&& ptr)
-    {
-        std::lock_guard<std::mutex> lock(ptr.m_mutex);
-        m_ptr = std::move(ptr.m_ptr);
-    }
-
-    AtomicSharedPtr& operator=(AtomicSharedPtr const& ptr)
-    {
-        if (&ptr != this) {
-            // std::lock() ensures that these are locked in a consistent order
-            // to avoid deadlock
-            std::lock(m_mutex, ptr.m_mutex);
-            m_ptr = ptr.m_ptr;
-            m_mutex.unlock();
-            ptr.m_mutex.unlock();
-        }
-        return *this;
-    }
-
-    AtomicSharedPtr& operator=(AtomicSharedPtr&& ptr)
-    {
-        std::lock(m_mutex, ptr.m_mutex);
-        m_ptr = std::move(ptr.m_ptr);
-        m_mutex.unlock();
-        ptr.m_mutex.unlock();
-        return *this;
-    }
-
-    std::shared_ptr<T> exchange(std::shared_ptr<T> ptr)
-    {
-        std::lock_guard<std::mutex> lock(m_mutex);
-        m_ptr.swap(ptr);
-        return ptr;
-    }
-
-    std::shared_ptr<T> load() const noexcept
-    {
-        std::lock_guard<std::mutex> lock(m_mutex);
-        return m_ptr;
-    }
-
-private:
-    mutable std::mutex m_mutex;
-    std::shared_ptr<T> m_ptr = nullptr;
-};
-
-}
-}
-
-#endif // REALM_ATOMIC_SHARED_PTR_HPP

+ 0 - 60
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/util/tagged_bool.hpp

@@ -1,60 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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_OS_UTIL_TAGGED_BOOL_HPP
-#define REALM_OS_UTIL_TAGGED_BOOL_HPP
-
-#include <type_traits>
-
-namespace realm {
-namespace util {
-// A type factory which defines a type which is implicitly convertable to and
-// from `bool`, but not to other TaggedBool types
-//
-// Usage:
-// using IsIndexed = util::TaggedBool<class IsIndexedTag>;
-// using IsPrimary = util::TaggedBool<class IsPrimaryTag>;
-// void foo(IsIndexed is_indexed, IsPrimary is_primary);
-//
-// foo(IsIndexed{true}, IsPrimary{false}); // compiles
-// foo(IsPrimary{true}, IsIndexed{false}); // doesn't compile
-template <typename Tag>
-struct TaggedBool {
-    // Allow explicit construction from anything convertible to bool
-    constexpr explicit TaggedBool(bool v) noexcept : m_value(v) { }
-
-    // Allow implicit construction from *just* bool and not things convertible
-    // to bool (such as other types of tagged bools)
-    template <typename Bool, typename = typename std::enable_if<std::is_same<Bool, bool>::value>::type>
-    constexpr TaggedBool(Bool v) noexcept : m_value(v) {}
-
-    constexpr TaggedBool(TaggedBool const& v) noexcept : m_value(v.m_value) {}
-
-    constexpr operator bool() const noexcept { return m_value; }
-    constexpr TaggedBool operator!() const noexcept { return TaggedBool{!m_value}; }
-
-    friend constexpr bool operator==(TaggedBool l, TaggedBool r) noexcept { return l.m_value == r.m_value; }
-    friend constexpr bool operator!=(TaggedBool l, TaggedBool r) noexcept { return l.m_value != r.m_value; }
-
-private:
-    bool m_value;
-};
-
-}
-}
-#endif // REALM_OS_UTIL_TAGGED_BOOL_HPP

+ 0 - 80
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/util/uuid.cpp

@@ -1,80 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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 <algorithm>
-#include <array>
-#include <functional>
-#include <random>
-#include <stdio.h>
-
-namespace {
-
-// Seed `engine` with as much random state as it requires, based on the approach outlined in P0205R0.
-// <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0205r0.html>
-template <typename T>
-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<std::random_device::result_type, numbers_needed> 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::mt19937>();
-
-    std::array<uint8_t, 16> uuid_bytes;
-    std::uniform_int_distribution<unsigned int> distribution(0, std::numeric_limits<uint8_t>::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<char, 37> 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

+ 0 - 33
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/util/uuid.hpp

@@ -1,33 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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_OS_UTIL_UUID_HPP
-#define REALM_OS_UTIL_UUID_HPP
-
-#include <string>
-
-namespace realm {
-namespace util {
-
-// Generate a random UUID and return its formatted string representation.
-std::string uuid_string();
-
-} // namespace util
-} // namespace realm
-
-#endif // REALM_OS_UTIL_UUID_HPP

+ 0 - 83
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/CMakeLists.txt

@@ -1,83 +0,0 @@
-include_directories(../external/catch/single_include .)
-
-set(HEADERS
-    util/event_loop.hpp
-    util/index_helpers.hpp
-    util/test_file.hpp
-    util/test_utils.hpp
-)
-
-set(SOURCES
-    collection_change_indices.cpp
-    frozen_objects.cpp
-    index_set.cpp
-    list.cpp
-    main.cpp
-    migrations.cpp
-    object.cpp
-    object_store.cpp
-    primitive_list.cpp
-    realm.cpp
-    results.cpp
-    schema.cpp
-    thread_safe_reference.cpp
-    transaction_log_parsing.cpp
-    uuid.cpp
-
-    util/event_loop.cpp
-    util/test_file.cpp
-    util/test_utils.cpp
-)
-
-
-if(REALM_ENABLE_SYNC)
-    list(APPEND HEADERS
-        sync/sync_test_utils.hpp
-        sync/session/session_util.hpp
-    )
-    list(APPEND SOURCES
-        sync/file.cpp
-        sync/metadata.cpp
-        sync/partial_sync.cpp
-        sync/permission.cpp
-        sync/session/connection_change_notifications.cpp
-        sync/session/progress_notifications.cpp
-        sync/session/session.cpp
-        sync/session/wait_for_completion.cpp
-        sync/sync_manager.cpp
-        sync/sync_test_utils.cpp
-        sync/user.cpp
-    )
-endif()
-
-if(REALM_ENABLE_SERVER)
-    list(APPEND SOURCES
-        sync/global_notifier.cpp
-    )
-endif()
-
-add_executable(tests ${SOURCES} ${HEADERS})
-target_compile_definitions(tests PRIVATE ${PLATFORM_DEFINES})
-
-if(VSCODE_TEST_RUNNER)
-    # Increase the Catch2 virtual console width so that the Visual Studio Code
-    # Test Explorer extension can parse long test names
-    target_compile_definitions(tests PRIVATE -DCATCH_CONFIG_CONSOLE_WIDTH=300)
-endif()
-
-if(REALM_ENABLE_SYNC)
-    # It's necessary to explicitly link to realm-sync here to control the order in which libraries are
-    # linked to avoid link errors when using GNU ld.
-    target_link_libraries(tests realm-sync realm-sync-server realm-parser)
-endif()
-
-target_link_libraries(tests realm-object-store ${PLATFORM_LIBRARIES})
-add_custom_command(TARGET tests POST_BUILD
-                   COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/sync-1.x.realm $<TARGET_FILE_DIR:tests>)
-
-create_coverage_target(generate-coverage tests)
-
-add_custom_target(run-tests USES_TERMINAL DEPENDS tests COMMAND ./tests)
-
-add_subdirectory(notifications-fuzzer)
-add_subdirectory(benchmarks)

+ 0 - 965
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/collection_change_indices.cpp

@@ -1,965 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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 "catch2/catch.hpp"
-
-#include "impl/collection_notifier.hpp"
-
-#include "util/index_helpers.hpp"
-
-#include <limits>
-
-using namespace realm;
-
-TEST_CASE("collection_change: insert()") {
-    _impl::CollectionChangeBuilder c;
-
-    SECTION("adds the row to the insertions set") {
-        c.insert(5);
-        c.insert(8);
-        REQUIRE_INDICES(c.insertions, 5, 8);
-    }
-
-    SECTION("shifts previous insertions and modifications") {
-        c.insert(5);
-        c.modify(8, 1);
-
-        c.insert(1);
-        REQUIRE_INDICES(c.insertions, 1, 6);
-        REQUIRE_INDICES(c.modifications, 9);
-        REQUIRE_COLUMN_INDICES(c.columns, 1, 9);
-    }
-
-    SECTION("does not shift previous deletions") {
-        c.erase(8);
-        c.erase(3);
-        c.insert(5);
-
-        REQUIRE_INDICES(c.insertions, 5);
-        REQUIRE_INDICES(c.deletions, 3, 8);
-    }
-
-    SECTION("shifts destination of previous moves after the insertion point") {
-        c.moves = {{10, 5}, {10, 2}, {3, 10}};
-        c.insert(4);
-        REQUIRE_MOVES(c, {10, 6}, {10, 2}, {3, 11});
-    }
-}
-
-TEST_CASE("collection_change: modify()") {
-    _impl::CollectionChangeBuilder c;
-
-    SECTION("marks the row as modified") {
-        c.modify(5);
-        REQUIRE_INDICES(c.modifications, 5);
-        REQUIRE(c.columns.empty());
-    }
-
-    SECTION("also marks newly inserted rows as modified") {
-        c.insert(5);
-        c.modify(5);
-        REQUIRE_INDICES(c.modifications, 5);
-        REQUIRE(c.columns.empty());
-    }
-
-    SECTION("is idempotent") {
-        c.modify(5);
-        c.modify(5);
-        c.modify(5);
-        c.modify(5);
-        REQUIRE_INDICES(c.modifications, 5);
-        REQUIRE(c.columns.empty());
-    }
-
-    SECTION("marks the appropriate column as modified when applicable") {
-        c.modify(5, 2);
-        REQUIRE_INDICES(c.modifications, 5);
-        REQUIRE(c.columns.size() == 1);
-        REQUIRE_INDICES(c.columns[2], 5);
-
-        c.modify(4, 2);
-        REQUIRE_INDICES(c.modifications, 4, 5);
-        REQUIRE(c.columns.size() == 1);
-        REQUIRE_INDICES(c.columns[2], 4, 5);
-
-        c.modify(3, 1);
-        REQUIRE_INDICES(c.modifications, 3, 4, 5);
-        REQUIRE(c.columns.size() == 2);
-        REQUIRE_INDICES(c.columns[1], 3);
-        REQUIRE_INDICES(c.columns[2], 4, 5);
-    }
-}
-
-TEST_CASE("collection_change: erase()") {
-    _impl::CollectionChangeBuilder c;
-
-    SECTION("adds the row to the deletions set") {
-        c.erase(5);
-        REQUIRE_INDICES(c.deletions, 5);
-    }
-
-    SECTION("is shifted for previous deletions") {
-        c.erase(5);
-        c.erase(6);
-        REQUIRE_INDICES(c.deletions, 5, 7);
-    }
-
-    SECTION("is shifted for previous insertions") {
-        c.insert(5);
-        c.erase(6);
-        REQUIRE_INDICES(c.deletions, 5);
-    }
-
-    SECTION("removes previous insertions") {
-        c.insert(5);
-        c.erase(5);
-        REQUIRE(c.insertions.empty());
-        REQUIRE(c.deletions.empty());
-    }
-
-    SECTION("removes previous modifications") {
-        c.modify(5, 0);
-        c.erase(5);
-        REQUIRE(c.modifications.empty());
-        REQUIRE(c.columns[0].empty());
-        REQUIRE_INDICES(c.deletions, 5);
-    }
-
-    SECTION("shifts previous modifications") {
-        c.modify(5, 0);
-        c.erase(4);
-        REQUIRE_INDICES(c.modifications, 4);
-        REQUIRE_COLUMN_INDICES(c.columns, 0, 4);
-        REQUIRE_INDICES(c.deletions, 4);
-    }
-
-    SECTION("removes previous moves to the row being erased") {
-        c.moves = {{10, 5}};
-        c.erase(5);
-        REQUIRE(c.moves.empty());
-    }
-
-    SECTION("shifts the destination of previous moves") {
-        c.moves = {{10, 5}, {10, 2}, {3, 10}};
-        c.erase(4);
-        REQUIRE_MOVES(c, {10, 4}, {10, 2}, {3, 9});
-    }
-}
-
-TEST_CASE("collection_change: clear()") {
-    _impl::CollectionChangeBuilder c;
-
-    SECTION("removes all insertions") {
-        c.insertions = {1, 2, 3};
-        c.clear(0);
-        REQUIRE(c.insertions.empty());
-    }
-
-    SECTION("removes all modifications") {
-        c.modifications = {1, 2, 3};
-        c.clear(0);
-        REQUIRE(c.modifications.empty());
-    }
-
-    SECTION("removes all moves") {
-        c.moves = {{1, 3}};
-        c.clear(0);
-        REQUIRE(c.moves.empty());
-    }
-
-    SECTION("sets deletions to the number of rows before any changes") {
-        c.insertions = {1, 2, 3};
-        c.clear(5);
-        REQUIRE_INDICES(c.deletions, 0, 1);
-
-        c.deletions = {1, 2, 3};
-        c.clear(5);
-        REQUIRE_INDICES(c.deletions, 0, 1, 2, 3, 4, 5, 6, 7);
-    }
-}
-
-TEST_CASE("collection_change: move()") {
-    _impl::CollectionChangeBuilder c;
-
-    SECTION("adds the move to the list of moves") {
-        c.move(5, 6);
-        REQUIRE_MOVES(c, {5, 6});
-    }
-
-    SECTION("updates previous moves to the source of this move") {
-        c.move(5, 6);
-        c.move(6, 7);
-        REQUIRE_MOVES(c, {5, 7});
-    }
-
-    SECTION("shifts previous moves and is shifted by them") {
-        c.move(5, 10);
-        c.move(6, 12);
-        REQUIRE_MOVES(c, {5, 9}, {7, 12});
-
-        c.move(10, 0);
-        REQUIRE_MOVES(c, {5, 10}, {7, 12}, {11, 0});
-    }
-
-    SECTION("does not report a move if the source is newly inserted") {
-        c.insert(5);
-        c.move(5, 10);
-        REQUIRE_INDICES(c.insertions, 10);
-        REQUIRE(c.moves.empty());
-    }
-
-    SECTION("shifts previous insertions and modifications") {
-        c.insert(5);
-        c.modify(6, 0);
-        c.move(10, 0);
-        REQUIRE_INDICES(c.insertions, 0, 6);
-        REQUIRE_INDICES(c.modifications, 7);
-        REQUIRE_COLUMN_INDICES(c.columns, 0, 7);
-        REQUIRE_MOVES(c, {9, 0});
-    }
-
-    SECTION("marks the target row as modified if the source row was") {
-        c.modify(5, 0);
-
-        c.move(5, 10);
-        REQUIRE_INDICES(c.modifications, 10);
-        REQUIRE_COLUMN_INDICES(c.columns, 0, 10);
-
-        c.move(6, 12);
-        REQUIRE_INDICES(c.modifications, 9);
-        REQUIRE_COLUMN_INDICES(c.columns, 0, 9);
-    }
-
-    SECTION("bumps previous moves to the same location") {
-        c.move(5, 10);
-        c.move(7, 10);
-        REQUIRE_MOVES(c, {5, 9}, {8, 10});
-
-        c = {};
-        c.move(5, 10);
-        c.move(15, 10);
-        REQUIRE_MOVES(c, {5, 11}, {15, 10});
-    }
-
-    SECTION("collapses redundant swaps of adjacent rows to a no-op") {
-        c.move(7, 8);
-        c.move(7, 8);
-        c.clean_up_stale_moves();
-        REQUIRE(c.empty());
-    }
-}
-
-TEST_CASE("collection_change: calculate() table order") {
-    _impl::CollectionChangeBuilder c;
-
-    auto all_modified = [](size_t) { return true; };
-    auto none_modified = [](size_t) { return false; };
-    bool in_table_order = true;
-
-    SECTION("returns an empty set when input and output are identical") {
-        c = _impl::CollectionChangeBuilder::calculate({1, 2, 3}, {1, 2, 3}, none_modified, in_table_order);
-        REQUIRE(c.empty());
-    }
-
-    SECTION("marks all as inserted when prev is empty") {
-        c = _impl::CollectionChangeBuilder::calculate({}, {1, 2, 3}, all_modified, in_table_order);
-        REQUIRE_INDICES(c.insertions, 0, 1, 2);
-    }
-
-    SECTION("marks all as deleted when new is empty") {
-        c = _impl::CollectionChangeBuilder::calculate({1, 2, 3}, {}, all_modified, in_table_order);
-        REQUIRE_INDICES(c.deletions, 0, 1, 2);
-    }
-
-    SECTION("marks npos rows in prev as deleted") {
-        c = _impl::CollectionChangeBuilder::calculate({-1, 1, 2, 3, -1}, {1, 2, 3}, all_modified, in_table_order);
-        REQUIRE_INDICES(c.deletions, 0, 4);
-    }
-
-    SECTION("marks modified rows which do not move as modified") {
-        c = _impl::CollectionChangeBuilder::calculate({1, 2, 3}, {1, 2, 3}, all_modified, in_table_order);
-        REQUIRE_INDICES(c.modifications, 0, 1, 2);
-    }
-
-    SECTION("does not mark unmodified rows as modified") {
-        c = _impl::CollectionChangeBuilder::calculate({1, 2, 3}, {1, 2, 3}, none_modified, in_table_order);
-        REQUIRE(c.modifications.empty());
-    }
-
-    SECTION("marks newly added rows as insertions") {
-        c = _impl::CollectionChangeBuilder::calculate({2, 3}, {1, 2, 3}, all_modified, in_table_order);
-        REQUIRE_INDICES(c.insertions, 0);
-
-        c = _impl::CollectionChangeBuilder::calculate({1, 3}, {1, 2, 3}, all_modified, in_table_order);
-        REQUIRE_INDICES(c.insertions, 1);
-
-        c = _impl::CollectionChangeBuilder::calculate({1, 2}, {1, 2, 3}, all_modified, in_table_order);
-        REQUIRE_INDICES(c.insertions, 2);
-    }
-
-    SECTION("marks removed rows as deleted") {
-        c = _impl::CollectionChangeBuilder::calculate({1, 2, 3}, {1, 2}, all_modified, in_table_order);
-        REQUIRE_INDICES(c.deletions, 2);
-
-        c = _impl::CollectionChangeBuilder::calculate({1, 2, 3}, {1, 3}, all_modified, in_table_order);
-        REQUIRE_INDICES(c.deletions, 1);
-
-        c = _impl::CollectionChangeBuilder::calculate({1, 2, 3}, {2, 3}, all_modified, in_table_order);
-        REQUIRE_INDICES(c.deletions, 0);
-    }
-
-    SECTION("marks rows as both inserted and deleted") {
-        c = _impl::CollectionChangeBuilder::calculate({1, 2, 3}, {1, 3, 4}, all_modified, in_table_order);
-        REQUIRE_INDICES(c.deletions, 1);
-        REQUIRE_INDICES(c.insertions, 2);
-        REQUIRE(c.moves.empty());
-    }
-
-    SECTION("does not mark rows as modified if they are new") {
-        c = _impl::CollectionChangeBuilder::calculate({3}, {3, 5}, all_modified, in_table_order);
-        REQUIRE_INDICES(c.modifications, 0);
-    }
-
-#if 0 // FIXME: these tests might be applicable to LinkingObjects
-    SECTION("reports moves which can be produced by move_last_over()") {
-        auto calc = [&](std::vector<int64_t> values) {
-            return _impl::CollectionChangeBuilder::calculate(values, {1, 2, 3}, none_modified, all);
-        };
-
-        REQUIRE(calc({1, 2, 3}).empty());
-        REQUIRE_MOVES(calc({1, 3, 2}), {2, 1});
-        REQUIRE_MOVES(calc({2, 1, 3}), {1, 0});
-        REQUIRE_MOVES(calc({2, 3, 1}), {2, 0});
-        REQUIRE_MOVES(calc({3, 1, 2}), {1, 0}, {2, 1});
-        REQUIRE_MOVES(calc({3, 2, 1}), {2, 0}, {1, 1});
-    }
-
-    SECTION("resolves ambiguous moves using the candidate set") {
-        c = _impl::CollectionChangeBuilder::calculate({3, 1, 2}, {1, 2, 3}, none_modified, all);
-        REQUIRE_MOVES(c, {1, 0}, {2, 1});
-        c = _impl::CollectionChangeBuilder::calculate({3, 1, 2}, {1, 2, 3}, none_modified, IndexSet{3});
-        REQUIRE_MOVES(c, {0, 2});
-    }
-#endif
-}
-
-TEST_CASE("collection_change: calculate() sorted") {
-    _impl::CollectionChangeBuilder c;
-
-    auto all_modified = [](size_t) { return true; };
-    auto none_modified = [](size_t) { return false; };
-    size_t npos = -1;
-
-    SECTION("returns an empty set when input and output are identical") {
-        c = _impl::CollectionChangeBuilder::calculate({1, 2, 3}, {1, 2, 3}, none_modified);
-        REQUIRE(c.empty());
-    }
-
-    SECTION("marks all as inserted when prev is empty") {
-        c = _impl::CollectionChangeBuilder::calculate({}, {1, 2, 3}, all_modified);
-        REQUIRE_INDICES(c.insertions, 0, 1, 2);
-    }
-
-    SECTION("marks all as deleted when new is empty") {
-        c = _impl::CollectionChangeBuilder::calculate({1, 2, 3}, {}, all_modified);
-        REQUIRE_INDICES(c.deletions, 0, 1, 2);
-    }
-
-    SECTION("marks npos rows in prev as deleted") {
-        c = _impl::CollectionChangeBuilder::calculate({npos, 1, 2, 3, npos}, {1, 2, 3}, all_modified);
-        REQUIRE_INDICES(c.deletions, 0, 4);
-    }
-
-    SECTION("marks modified rows which do not move as modified") {
-        c = _impl::CollectionChangeBuilder::calculate({1, 2, 3}, {1, 2, 3}, all_modified);
-        REQUIRE_INDICES(c.modifications, 0, 1, 2);
-    }
-
-    SECTION("does not mark unmodified rows as modified") {
-        c = _impl::CollectionChangeBuilder::calculate({1, 2, 3}, {1, 2, 3}, none_modified);
-        REQUIRE(c.modifications.empty());
-    }
-
-    SECTION("marks newly added rows as insertions") {
-        c = _impl::CollectionChangeBuilder::calculate({2, 3}, {1, 2, 3}, all_modified);
-        REQUIRE_INDICES(c.insertions, 0);
-
-        c = _impl::CollectionChangeBuilder::calculate({1, 3}, {1, 2, 3}, all_modified);
-        REQUIRE_INDICES(c.insertions, 1);
-
-        c = _impl::CollectionChangeBuilder::calculate({1, 2}, {1, 2, 3}, all_modified);
-        REQUIRE_INDICES(c.insertions, 2);
-    }
-
-    SECTION("marks removed rows as deleted") {
-        c = _impl::CollectionChangeBuilder::calculate({1, 2, 3}, {1, 2}, all_modified);
-        REQUIRE_INDICES(c.deletions, 2);
-
-        c = _impl::CollectionChangeBuilder::calculate({1, 2, 3}, {1, 3}, all_modified);
-        REQUIRE_INDICES(c.deletions, 1);
-
-        c = _impl::CollectionChangeBuilder::calculate({1, 2, 3}, {2, 3}, all_modified);
-        REQUIRE_INDICES(c.deletions, 0);
-    }
-
-    SECTION("marks rows as both inserted and deleted") {
-        c = _impl::CollectionChangeBuilder::calculate({1, 2, 3}, {1, 3, 4}, all_modified);
-        REQUIRE_INDICES(c.deletions, 1);
-        REQUIRE_INDICES(c.insertions, 2);
-        REQUIRE(c.moves.empty());
-    }
-
-    SECTION("marks rows as modified even if they moved") {
-        c = _impl::CollectionChangeBuilder::calculate({3, 5}, {5, 3}, all_modified);
-        REQUIRE_INDICES(c.deletions, 1);
-        REQUIRE_INDICES(c.insertions, 0);
-        REQUIRE_INDICES(c.modifications, 0, 1);
-    }
-
-    SECTION("does not mark rows as modified if they are new") {
-        c = _impl::CollectionChangeBuilder::calculate({3}, {3, 5}, all_modified);
-        REQUIRE_INDICES(c.modifications, 0);
-    }
-
-    SECTION("reports inserts/deletes for simple reorderings") {
-        auto calc = [&](std::vector<size_t> old_rows, std::vector<size_t> new_rows) {
-            return _impl::CollectionChangeBuilder::calculate(old_rows, new_rows, none_modified);
-        };
-
-        c = calc({1, 2, 3}, {1, 2, 3});
-        REQUIRE(c.insertions.empty());
-        REQUIRE(c.deletions.empty());
-
-        c = calc({1, 2, 3}, {1, 3, 2});
-        REQUIRE_INDICES(c.insertions, 1);
-        REQUIRE_INDICES(c.deletions, 2);
-
-        c = calc({1, 2, 3}, {2, 1, 3});
-        REQUIRE_INDICES(c.insertions, 0);
-        REQUIRE_INDICES(c.deletions, 1);
-
-        c = calc({1, 2, 3}, {2, 3, 1});
-        REQUIRE_INDICES(c.insertions, 2);
-        REQUIRE_INDICES(c.deletions, 0);
-
-        c = calc({1, 2, 3}, {3, 1, 2});
-        REQUIRE_INDICES(c.insertions, 0);
-        REQUIRE_INDICES(c.deletions, 2);
-
-        c = calc({1, 2, 3}, {3, 2, 1});
-        REQUIRE_INDICES(c.insertions, 0, 1);
-        REQUIRE_INDICES(c.deletions, 1, 2);
-
-        c = calc({1, 3, 2}, {1, 2, 3});
-        REQUIRE_INDICES(c.insertions, 1);
-        REQUIRE_INDICES(c.deletions, 2);
-
-        c = calc({1, 3, 2}, {1, 3, 2});
-        REQUIRE(c.insertions.empty());
-        REQUIRE(c.deletions.empty());
-
-        c = calc({1, 3, 2}, {2, 1, 3});
-        REQUIRE_INDICES(c.insertions, 0);
-        REQUIRE_INDICES(c.deletions, 2);
-
-        c = calc({1, 3, 2}, {2, 3, 1});
-        REQUIRE_INDICES(c.insertions, 0, 1);
-        REQUIRE_INDICES(c.deletions, 1, 2);
-
-        c = calc({1, 3, 2}, {3, 1, 2});
-        REQUIRE_INDICES(c.insertions, 0);
-        REQUIRE_INDICES(c.deletions, 1);
-
-        c = calc({1, 3, 2}, {3, 2, 1});
-        REQUIRE_INDICES(c.insertions, 2);
-        REQUIRE_INDICES(c.deletions, 0);
-
-        c = calc({2, 1, 3}, {1, 2, 3});
-        REQUIRE_INDICES(c.insertions, 0);
-        REQUIRE_INDICES(c.deletions, 1);
-
-        c = calc({2, 1, 3}, {1, 3, 2});
-        REQUIRE_INDICES(c.insertions, 2);
-        REQUIRE_INDICES(c.deletions, 0);
-
-        c = calc({2, 1, 3}, {2, 1, 3});
-        REQUIRE(c.insertions.empty());
-        REQUIRE(c.deletions.empty());
-
-        c = calc({2, 1, 3}, {2, 3, 1});
-        REQUIRE_INDICES(c.insertions, 1);
-        REQUIRE_INDICES(c.deletions, 2);
-
-        c = calc({2, 1, 3}, {3, 1, 2});
-        REQUIRE_INDICES(c.insertions, 0, 1);
-        REQUIRE_INDICES(c.deletions, 1, 2);
-
-        c = calc({2, 1, 3}, {3, 2, 1});
-        REQUIRE_INDICES(c.insertions, 0);
-        REQUIRE_INDICES(c.deletions, 2);
-
-        c = calc({2, 3, 1}, {1, 2, 3});
-        REQUIRE_INDICES(c.insertions, 0);
-        REQUIRE_INDICES(c.deletions, 2);
-
-        c = calc({2, 3, 1}, {1, 3, 2});
-        REQUIRE_INDICES(c.insertions, 0, 1);
-        REQUIRE_INDICES(c.deletions, 1, 2);
-
-        c = calc({2, 3, 1}, {2, 1, 3});
-        REQUIRE_INDICES(c.insertions, 1);
-        REQUIRE_INDICES(c.deletions, 2);
-
-        c = calc({2, 3, 1}, {2, 3, 1});
-        REQUIRE(c.insertions.empty());
-        REQUIRE(c.deletions.empty());
-
-        c = calc({2, 3, 1}, {3, 1, 2});
-        REQUIRE_INDICES(c.insertions, 2);
-        REQUIRE_INDICES(c.deletions, 0);
-
-        c = calc({2, 3, 1}, {3, 2, 1});
-        REQUIRE_INDICES(c.insertions, 0);
-        REQUIRE_INDICES(c.deletions, 1);
-
-        c = calc({3, 1, 2}, {1, 2, 3});
-        REQUIRE_INDICES(c.insertions, 2);
-        REQUIRE_INDICES(c.deletions, 0);
-
-        c = calc({3, 1, 2}, {1, 3, 2});
-        REQUIRE_INDICES(c.insertions, 0);
-        REQUIRE_INDICES(c.deletions, 1);
-
-        c = calc({3, 1, 2}, {2, 1, 3});
-        REQUIRE_INDICES(c.insertions, 0, 1);
-        REQUIRE_INDICES(c.deletions, 1, 2);
-
-        c = calc({3, 1, 2}, {2, 3, 1});
-        REQUIRE_INDICES(c.insertions, 0);
-        REQUIRE_INDICES(c.deletions, 2);
-
-        c = calc({3, 1, 2}, {3, 1, 2});
-        REQUIRE(c.insertions.empty());
-        REQUIRE(c.deletions.empty());
-
-        c = calc({3, 1, 2}, {3, 2, 1});
-        REQUIRE_INDICES(c.insertions, 1);
-        REQUIRE_INDICES(c.deletions, 2);
-
-        c = calc({3, 2, 1}, {1, 2, 3});
-        REQUIRE_INDICES(c.insertions, 0, 1);
-        REQUIRE_INDICES(c.deletions, 1, 2);
-
-        c = calc({3, 2, 1}, {1, 3, 2});
-        REQUIRE_INDICES(c.insertions, 0);
-        REQUIRE_INDICES(c.deletions, 2);
-
-        c = calc({3, 2, 1}, {2, 1, 3});
-        REQUIRE_INDICES(c.insertions, 2);
-        REQUIRE_INDICES(c.deletions, 0);
-
-        c = calc({3, 2, 1}, {2, 3, 1});
-        REQUIRE_INDICES(c.insertions, 0);
-        REQUIRE_INDICES(c.deletions, 1);
-
-        c = calc({3, 2, 1}, {3, 1, 2});
-        REQUIRE_INDICES(c.insertions, 1);
-        REQUIRE_INDICES(c.deletions, 2);
-
-        c = calc({3, 2, 1}, {3, 2, 1});
-        REQUIRE(c.insertions.empty());
-        REQUIRE(c.deletions.empty());
-    }
-
-    SECTION("prefers to produce diffs where modified rows are the ones to move when it is ambiguous") {
-        auto two_modified = [](size_t ndx) { return ndx == 2; };
-        c = _impl::CollectionChangeBuilder::calculate({1, 2, 3}, {1, 3, 2}, two_modified);
-        REQUIRE_INDICES(c.deletions, 1);
-        REQUIRE_INDICES(c.insertions, 2);
-
-        auto three_modified = [](size_t ndx) { return ndx == 3; };
-        c = _impl::CollectionChangeBuilder::calculate({1, 2, 3}, {1, 3, 2}, three_modified);
-        REQUIRE_INDICES(c.deletions, 2);
-        REQUIRE_INDICES(c.insertions, 1);
-    }
-
-    SECTION("prefers smaller diffs over larger diffs moving only modified rows") {
-        auto two_modified = [](size_t ndx) { return ndx == 2; };
-        c = _impl::CollectionChangeBuilder::calculate({1, 2, 3}, {2, 3, 1}, two_modified);
-        REQUIRE_INDICES(c.deletions, 0);
-        REQUIRE_INDICES(c.insertions, 2);
-    }
-
-    SECTION("supports duplicate indices") {
-        c = _impl::CollectionChangeBuilder::calculate({1, 1, 2, 2, 3, 3},
-                                                      {1, 2, 3, 1, 2, 3},
-                                                      all_modified);
-        REQUIRE_INDICES(c.deletions, 3, 5);
-        REQUIRE_INDICES(c.insertions, 1, 2);
-    }
-
-    SECTION("deletes and inserts the last option when any in a range could be deleted") {
-        c = _impl::CollectionChangeBuilder::calculate({3, 2, 1, 1, 2, 3},
-                                                      {1, 1, 2, 2, 3, 3},
-                                                      all_modified);
-        REQUIRE_INDICES(c.deletions, 0, 1);
-        REQUIRE_INDICES(c.insertions, 3, 5);
-    }
-
-    SECTION("reports insertions/deletions when the number of duplicate entries changes") {
-        c = _impl::CollectionChangeBuilder::calculate({1, 1, 1, 1, 2, 3},
-                                                      {1, 2, 3, 1},
-                                                      all_modified);
-        REQUIRE_INDICES(c.deletions, 1, 2, 3);
-        REQUIRE_INDICES(c.insertions, 3);
-
-        c = _impl::CollectionChangeBuilder::calculate({1, 2, 3, 1},
-                                                      {1, 1, 1, 1, 2, 3},
-                                                      all_modified);
-        REQUIRE_INDICES(c.deletions, 3);
-        REQUIRE_INDICES(c.insertions, 1, 2, 3);
-    }
-
-    SECTION("properly recurses into smaller subblocks") {
-        std::vector<size_t> prev = {10, 1, 2, 11, 3, 4, 5, 12, 6, 7, 13};
-        std::vector<size_t> next = {13, 1, 2, 12, 3, 4, 5, 11, 6, 7, 10};
-        c = _impl::CollectionChangeBuilder::calculate(prev, next, all_modified);
-        REQUIRE_INDICES(c.deletions, 0, 3, 7, 10);
-        REQUIRE_INDICES(c.insertions, 0, 3, 7, 10);
-    }
-
-    SECTION("produces diffs which let merge collapse insert -> move -> delete to no-op") {
-        auto four_modified = [](size_t ndx) { return ndx == 4; };
-        for (int insert_pos = 0; insert_pos < 4; ++insert_pos) {
-            for (int move_to_pos = 0; move_to_pos < 4; ++move_to_pos) {
-                if (insert_pos == move_to_pos)
-                    continue;
-                CAPTURE(insert_pos);
-                CAPTURE(move_to_pos);
-
-                std::vector<size_t> after_insert = {1, 2, 3};
-                after_insert.insert(after_insert.begin() + insert_pos, 4);
-                c = _impl::CollectionChangeBuilder::calculate({1, 2, 3}, after_insert, four_modified);
-
-                std::vector<size_t> after_move = {1, 2, 3};
-                after_move.insert(after_move.begin() + move_to_pos, 4);
-                c.merge(_impl::CollectionChangeBuilder::calculate(after_insert, after_move, four_modified));
-
-                c.merge(_impl::CollectionChangeBuilder::calculate(after_move, {1, 2, 3}, four_modified));
-                REQUIRE(c.empty());
-            }
-        }
-    }
-}
-
-TEST_CASE("collection_change: merge()") {
-    _impl::CollectionChangeBuilder c;
-
-    SECTION("is a no-op if the new set is empty") {
-        c = {{1, 2, 3}, {4, 5}, {6, 7}, {{8, 9}}};
-        c.columns = {{0, {6}}, {1, {7}}};
-        c.merge({});
-        REQUIRE_INDICES(c.deletions, 1, 2, 3, 8);
-        REQUIRE_INDICES(c.insertions, 4, 5, 9);
-        REQUIRE_INDICES(c.modifications, 6, 7);
-        REQUIRE_COLUMN_INDICES(c.columns, 0, 6);
-        REQUIRE_COLUMN_INDICES(c.columns, 1, 7);
-        REQUIRE_MOVES(c, {8, 9});
-    }
-
-    SECTION("replaces the set with the new set if the old set is empty") {
-        c.merge({{1, 2, 3}, {4, 5}, {6, 7}, {{8, 9}}});
-        REQUIRE_INDICES(c.deletions, 1, 2, 3, 8);
-        REQUIRE_INDICES(c.insertions, 4, 5, 9);
-        REQUIRE_INDICES(c.modifications, 6, 7);
-        REQUIRE_MOVES(c, {8, 9});
-    }
-
-    SECTION("shifts deletions by previous deletions") {
-        c = {{5}, {}, {}, {}};
-        c.merge({{3}, {}, {}, {}});
-        REQUIRE_INDICES(c.deletions, 3, 5);
-
-        c = {{5}, {}, {}, {}};
-        c.merge({{4}, {}, {}, {}});
-        REQUIRE_INDICES(c.deletions, 4, 5);
-
-        c = {{5}, {}, {}, {}};
-        c.merge({{5}, {}, {}, {}});
-        REQUIRE_INDICES(c.deletions, 5, 6);
-
-        c = {{5}, {}, {}, {}};
-        c.merge({{6}, {}, {}, {}});
-        REQUIRE_INDICES(c.deletions, 5, 7);
-    }
-
-    SECTION("shifts deletions by previous insertions") {
-        c = {{}, {5}, {}, {}};
-        c.merge({{4}, {}, {}, {}});
-        REQUIRE_INDICES(c.deletions, 4);
-
-        c = {{}, {5}, {}, {}};
-        c.merge({{6}, {}, {}, {}});
-        REQUIRE_INDICES(c.deletions, 5);
-    }
-
-    SECTION("shifts previous insertions by deletions") {
-        c = {{}, {2, 3}, {}, {}};
-        c.merge({{1}, {}, {}, {}});
-        REQUIRE_INDICES(c.insertions, 1, 2);
-    }
-
-    SECTION("removes previous insertions for newly deleted rows") {
-        c = {{}, {1, 2}, {}, {}};
-        c.merge({{2}, {}, {}, {}});
-        REQUIRE_INDICES(c.insertions, 1);
-    }
-
-    SECTION("removes previous modifications for newly deleted rows") {
-        c = {{}, {}, {2, 3}, {}};
-        c.merge({{2}, {}, {}, {}});
-        REQUIRE_INDICES(c.modifications, 2);
-    }
-
-    SECTION("shifts previous modifications for deletions of other rows") {
-        c = {{}, {}, {2, 3}, {}};
-        c.merge({{1}, {}, {}, {}});
-        REQUIRE_INDICES(c.modifications, 1, 2);
-    }
-
-    SECTION("removes moves to rows which have been deleted") {
-        c = {{}, {}, {}, {{2, 3}}};
-        c.merge({{3}, {}, {}, {}});
-        REQUIRE(c.moves.empty());
-    }
-
-    SECTION("shifts destinations of previous moves to reflect new deletions") {
-        c = {{}, {}, {}, {{2, 5}}};
-        c.merge({{3}, {}, {}, {}});
-        REQUIRE_MOVES(c, {2, 4});
-    }
-
-    SECTION("does not modify old deletions based on new insertions") {
-        c = {{1, 3}, {}, {}, {}};
-        c.merge({{}, {1, 2, 3}, {}, {}});
-        REQUIRE_INDICES(c.deletions, 1, 3);
-        REQUIRE_INDICES(c.insertions, 1, 2, 3);
-    }
-
-    SECTION("shifts previous insertions to reflect new insertions") {
-        c = {{}, {1, 5}, {}, {}};
-        c.merge({{}, {1, 4}, {}, {}});
-        REQUIRE_INDICES(c.insertions, 1, 2, 4, 7);
-    }
-
-    SECTION("shifts previous modifications to reflect new insertions") {
-        c = {{}, {}, {1, 5}, {}};
-        c.merge({{}, {1, 4}, {}, {}});
-        REQUIRE_INDICES(c.modifications, 2, 7);
-        REQUIRE_INDICES(c.insertions, 1, 4);
-    }
-
-    SECTION("shifts previous move destinations to reflect new insertions") {
-        c = {{}, {}, {}, {{2, 5}}};
-        c.merge({{}, {3}, {}});
-        REQUIRE_MOVES(c, {2, 6});
-    }
-
-    SECTION("does not modify old deletions based on new modifications") {
-        c = {{1, 2, 3}, {}, {}, {}};
-        c.merge({{}, {}, {2}});
-        REQUIRE_INDICES(c.deletions, 1, 2, 3);
-        REQUIRE_INDICES(c.modifications, 2);
-    }
-
-    SECTION("tracks modifications made to previously inserted rows") {
-        c = {{}, {2}, {}, {}};
-        c.merge({{}, {}, {1, 2, 3}});
-        REQUIRE_INDICES(c.insertions, 2);
-        REQUIRE_INDICES(c.modifications, 1, 2, 3);
-    }
-
-    SECTION("unions modifications with old modifications") {
-        c = {{}, {}, {2}, {}};
-        c.merge({{}, {}, {1, 2, 3}});
-        REQUIRE_INDICES(c.modifications, 1, 2, 3);
-    }
-
-    SECTION("tracks modifications for previous moves") {
-        c = {{}, {}, {}, {{1, 2}}};
-        c.merge({{}, {}, {2, 3}});
-        REQUIRE_INDICES(c.modifications, 2, 3);
-    }
-
-    SECTION("updates new move sources to reflect previous inserts and deletes") {
-        c = {{1}, {}, {}, {}};
-        c.merge({{}, {}, {}, {{2, 3}}});
-        REQUIRE_MOVES(c, {3, 3});
-
-        c = {{}, {1}, {}, {}};
-        c.merge({{}, {}, {}, {{2, 3}}});
-        REQUIRE_MOVES(c, {1, 3});
-
-        c = {{2}, {4}, {}, {}};
-        c.merge({{}, {}, {}, {{5, 10}}});
-        REQUIRE_MOVES(c, {5, 10});
-    }
-
-    SECTION("updates the row modified for rows moved after a modification") {
-        c = {{}, {}, {1}, {}};
-        c.merge({{}, {}, {}, {{1, 3}}});
-        REQUIRE_INDICES(c.modifications, 3);
-        REQUIRE_MOVES(c, {1, 3});
-    }
-
-    SECTION("updates the row modified for chained moves") {
-        c = {{}, {}, {1}, {}};
-        c.merge({{}, {}, {}, {{1, 3}}});
-        c.merge({{}, {}, {}, {{3, 5}}});
-        REQUIRE_INDICES(c.modifications, 5);
-        REQUIRE_MOVES(c, {1, 5});
-    }
-
-    SECTION("updates the row inserted for moves of previously new rows") {
-        c = {{}, {1}, {}, {}};
-        c.merge({{}, {}, {}, {{1, 3}}});
-        REQUIRE(c.moves.empty());
-        REQUIRE_INDICES(c.insertions, 3);
-    }
-
-    SECTION("updates old moves when the destination is moved again") {
-        c = {{}, {}, {}, {{1, 3}}};
-        c.merge({{}, {}, {}, {{3, 5}}});
-        REQUIRE_MOVES(c, {1, 5});
-    }
-
-    SECTION("shifts destination of previous moves to reflect new moves like an insert/delete pair would") {
-        c = {{}, {}, {}, {{1, 3}}};
-        c.merge({{}, {}, {}, {{2, 5}}});
-        REQUIRE_MOVES(c, {1, 2}, {3, 5});
-
-        c = {{}, {}, {}, {{1, 10}}};
-        c.merge({{}, {}, {}, {{2, 5}}});
-        REQUIRE_MOVES(c, {1, 10}, {3, 5});
-
-        c = {{}, {}, {}, {{5, 10}}};
-        c.merge({{}, {}, {}, {{12, 2}}});
-        REQUIRE_MOVES(c, {5, 11}, {12, 2});
-    }
-
-    SECTION("moves shift previous inserts like an insert/delete pair would") {
-        c = {{}, {5}};
-        c.merge({{}, {}, {}, {{2, 6}}});
-        REQUIRE_INDICES(c.insertions, 4, 6);
-    }
-
-    SECTION("moves shift previous modifications like an insert/delete pair would") {
-        c = {{}, {}, {5}};
-        c.merge({{}, {}, {}, {{2, 6}}});
-        REQUIRE_INDICES(c.modifications, 4);
-    }
-
-    SECTION("moves are shifted by previous deletions like an insert/delete pair would") {
-        c = {{5}};
-        c.merge({{}, {}, {}, {{2, 6}}});
-        REQUIRE_MOVES(c, {2, 6});
-
-        c = {{5}};
-        c.merge({{}, {}, {}, {{6, 2}}});
-        REQUIRE_MOVES(c, {7, 2});
-    }
-
-    SECTION("leapfrogging rows collapse to an empty changeset") {
-        c = {{1}, {0}, {}, {{1, 0}}};
-        c.merge({{1}, {0}, {}, {{1, 0}}});
-        REQUIRE(c.empty());
-    }
-
-    SECTION("modify -> move -> unmove leaves row marked as modified") {
-        c = {{}, {}, {1}};
-        c.merge({{1}, {2}, {}, {{1, 2}}});
-        c.merge({{1}});
-
-        REQUIRE_INDICES(c.deletions, 2);
-        REQUIRE(c.insertions.empty());
-        REQUIRE(c.moves.empty());
-        REQUIRE_INDICES(c.modifications, 1);
-    }
-
-    SECTION("modifying a previously moved row which stops being a move due to more deletions") {
-        // Make it stop being a move in the same transaction as the modify
-        c = {{1, 2}, {0, 1}, {}, {{1, 0}, {2, 1}}};
-        c.merge({{0, 2}, {1}, {0}, {}});
-
-        REQUIRE_INDICES(c.deletions, 0, 1);
-        REQUIRE_INDICES(c.insertions, 1);
-        REQUIRE_INDICES(c.modifications, 0);
-        REQUIRE(c.moves.empty());
-
-        // Same net change, but make it no longer a move in the transaction after the modify
-        c = {{1, 2}, {0, 1}, {}, {{1, 0}, {2, 1}}};
-        c.merge({{}, {}, {1}, {}});
-        c.merge({{0, 2}, {0}, {}, {{2, 0}}});
-        c.merge({{0}, {1}, {}, {}});
-
-        REQUIRE_INDICES(c.deletions, 0, 1);
-        REQUIRE_INDICES(c.insertions, 1);
-        REQUIRE_INDICES(c.modifications, 0);
-        REQUIRE(c.moves.empty());
-    }
-
-    SECTION("column-level modifications") {
-        _impl::CollectionChangeBuilder c2;
-        c = {{}, {}, {1, 2, 3}, {}};
-        c.columns = {{0, {1}}, {1, {2, 3}}};
-
-        SECTION("preserved on no-op merges") {
-            c.merge({});
-            REQUIRE_COLUMN_INDICES(c.columns, 0, 1);
-            REQUIRE_COLUMN_INDICES(c.columns, 1, 2, 3);
-
-            c2.merge(std::move(c));
-            REQUIRE_COLUMN_INDICES(c2.columns, 0, 1);
-            REQUIRE_COLUMN_INDICES(c2.columns, 1, 2, 3);
-        }
-
-        SECTION("merged with other column-level modifications") {
-            c2.modifications = {0, 4};
-            c2.columns = {{0, {1, 2}}, {2, {4}}};
-            c.merge(std::move(c2));
-
-            REQUIRE_COLUMN_INDICES(c.columns, 0, 1, 2);
-            REQUIRE_COLUMN_INDICES(c.columns, 1, 2, 3);
-            REQUIRE_COLUMN_INDICES(c.columns, 2, 4);
-        }
-
-        SECTION("removed by deletions") {
-            c2.deletions = {2};
-            c.merge(std::move(c2));
-            REQUIRE_COLUMN_INDICES(c.columns, 0, 1);
-            REQUIRE_COLUMN_INDICES(c.columns, 1, 2);
-        }
-
-        SECTION("shifted by insertions") {
-            c2.insertions = {3};
-            c.merge(std::move(c2));
-            REQUIRE_COLUMN_INDICES(c.columns, 0, 1);
-            REQUIRE_COLUMN_INDICES(c.columns, 1, 2, 4);
-        }
-    }
-}

+ 0 - 610
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/index_set.cpp

@@ -1,610 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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 "catch2/catch.hpp"
-
-#include "index_set.hpp"
-
-#include "util/index_helpers.hpp"
-
-TEST_CASE("index_set: contains()") {
-    SECTION("returns false if the index is before the first entry in the set") {
-        realm::IndexSet set = {1, 2, 5};
-        REQUIRE_FALSE(set.contains(0));
-    }
-
-    SECTION("returns false if the index is after the last entry in the set") {
-        realm::IndexSet set = {1, 2, 5};
-        REQUIRE_FALSE(set.contains(6));
-    }
-
-    SECTION("returns false if the index is between ranges in the set") {
-        realm::IndexSet set = {1, 2, 5};
-        REQUIRE_FALSE(set.contains(4));
-    }
-
-    SECTION("returns true if the index is in the set") {
-        realm::IndexSet set = {1, 2, 5};
-        REQUIRE(set.contains(1));
-        REQUIRE(set.contains(2));
-        REQUIRE(set.contains(5));
-    }
-}
-
-TEST_CASE("index_set: count()") {
-    SECTION("returns the number of indices in the set in the given range") {
-        realm::IndexSet set = {1, 2, 3, 5};
-        REQUIRE(set.count(0, 6) == 4);
-        REQUIRE(set.count(0, 5) == 3);
-        REQUIRE(set.count(0, 4) == 3);
-        REQUIRE(set.count(0, 3) == 2);
-        REQUIRE(set.count(0, 2) == 1);
-        REQUIRE(set.count(0, 1) == 0);
-        REQUIRE(set.count(0, 0) == 0);
-
-        REQUIRE(set.count(0, 6) == 4);
-        REQUIRE(set.count(1, 6) == 4);
-        REQUIRE(set.count(2, 6) == 3);
-        REQUIRE(set.count(3, 6) == 2);
-        REQUIRE(set.count(4, 6) == 1);
-        REQUIRE(set.count(5, 6) == 1);
-        REQUIRE(set.count(6, 6) == 0);
-    }
-
-    SECTION("includes full ranges in the middle") {
-        realm::IndexSet set = {1, 3, 4, 5, 10};
-        REQUIRE(set.count(0, 11) == 5);
-    }
-
-    SECTION("truncates ranges at the beginning and end") {
-        realm::IndexSet set = {1, 2, 3, 5, 6, 7, 8, 9};
-        REQUIRE(set.count(3, 9) == 5);
-    }
-
-    SECTION("handles full chunks well") {
-        size_t count = realm::_impl::ChunkedRangeVector::max_size * 4;
-        realm::IndexSet set;
-        for (size_t i = 0; i < count; ++i) {
-            set.add(i * 3);
-            set.add(i * 3 + 1);
-        }
-
-        for (size_t i = 0; i < count * 3; ++i) {
-            REQUIRE(set.count(i) == 2 * count - (i + 1) * 2 / 3);
-            REQUIRE(set.count(0, i) == (i + 1) / 3 + (i + 2) / 3);
-        }
-    }
-}
-
-TEST_CASE("index_set: add()") {
-    realm::IndexSet set;
-
-    SECTION("extends existing ranges when next to an edge") {
-        set.add(1);
-        REQUIRE_INDICES(set, 1);
-
-        set.add(2);
-        REQUIRE_INDICES(set, 1, 2);
-
-        set.add(0);
-        REQUIRE_INDICES(set, 0, 1, 2);
-    }
-
-    SECTION("does not extend ranges over gaps") {
-        set.add(0);
-        REQUIRE_INDICES(set, 0);
-
-        set.add(2);
-        REQUIRE_INDICES(set, 0, 2);
-    }
-
-    SECTION("does nothing when the index is already in the set") {
-        set.add(0);
-        set.add(0);
-        REQUIRE_INDICES(set, 0);
-    }
-
-    SECTION("merges existing ranges when adding the index between them") {
-        set = {0, 2, 4};
-
-        set.add(1);
-        REQUIRE_INDICES(set, 0, 1, 2, 4);
-    }
-
-    SECTION("combines multiple index sets without any shifting") {
-        set = {0, 2, 6};
-
-        set.add({1, 4, 5});
-        REQUIRE_INDICES(set, 0, 1, 2, 4, 5, 6);
-    }
-
-    SECTION("handles front additions of ranges") {
-        for (size_t i = 20; i > 0; i -= 2)
-            set.add(i);
-        REQUIRE_INDICES(set, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20);
-    }
-
-    SECTION("merges ranges even when they are in different chunks") {
-        realm::IndexSet set2;
-        for (int i = 0; i < 20; ++i) {
-            set.add(i * 2);
-            set2.add(i);
-            set2.add(i * 2);
-        }
-        set.add(set2);
-        REQUIRE(set.count() == 30);
-    }
-}
-
-TEST_CASE("index_set: add_shifted()") {
-    realm::IndexSet set;
-
-    SECTION("on an empty set is just add()") {
-        set.add_shifted(5);
-        REQUIRE_INDICES(set, 5);
-    }
-
-    SECTION("before the first range is just add()") {
-        set = {10};
-        set.add_shifted(5);
-        REQUIRE_INDICES(set, 5, 10);
-    }
-
-    SECTION("on first index of a range extends the range") {
-        set = {5};
-
-        set.add_shifted(5);
-        REQUIRE_INDICES(set, 5, 6);
-
-        set.add_shifted(5);
-        REQUIRE_INDICES(set, 5, 6, 7);
-    }
-
-    SECTION("in the middle of a range is shifted by that range") {
-        set = {5, 6, 7};
-        set.add_shifted(6);
-        REQUIRE_INDICES(set, 5, 6, 7, 9);
-    }
-
-    SECTION("after the last range adds the total count to the index to be added") {
-        set = {5};
-
-        set.add_shifted(6);
-        REQUIRE_INDICES(set, 5, 7);
-
-        set.add_shifted(10);
-        REQUIRE_INDICES(set, 5, 7, 12);
-    }
-
-    SECTION("in between ranges can be bumped into the next range") {
-        set = {5, 7};
-        set.add_shifted(6);
-        REQUIRE_INDICES(set, 5, 7, 8);
-    }
-}
-
-TEST_CASE("index_set: add_shifted_by()") {
-    realm::IndexSet set;
-
-    SECTION("does nothing given an empty set to add") {
-        set = {5, 6, 7};
-        set.add_shifted_by({5, 6}, {});
-        REQUIRE_INDICES(set, 5, 6, 7);
-    }
-
-    SECTION("does nothing if values is a subset of shifted_by") {
-        set = {5, 6, 7};
-        set.add_shifted_by({3, 4}, {3, 4});
-        REQUIRE_INDICES(set, 5, 6, 7);
-    }
-
-    SECTION("just adds the indices when they are all before the old indices and the shifted-by set is empty") {
-        set = {5, 6};
-        set.add_shifted_by({}, {3, 4});
-        REQUIRE_INDICES(set, 3, 4, 5, 6);
-    }
-
-    SECTION("adds the indices shifted by the old count when they are all after the old indices and the shifted-by set is empty") {
-        set = {5, 6};
-        set.add_shifted_by({}, {7, 9, 11, 13});
-        REQUIRE_INDICES(set, 5, 6, 9, 11, 13, 15);
-    }
-
-    SECTION("acts like bulk add_shifted() when shifted_by is empty") {
-        set = {5, 10, 15, 20, 25};
-        set.add_shifted_by({}, {4, 5, 11});
-        REQUIRE_INDICES(set, 4, 5, 6, 10, 13, 15, 20, 25);
-    }
-
-    SECTION("shifts indices in values back by the number of indices in shifted_by before them") {
-        set = {5};
-        set.add_shifted_by({0, 2, 3}, {6});
-        REQUIRE_INDICES(set, 3, 5);
-
-        set = {5};
-        set.add_shifted_by({1, 3}, {4});
-        REQUIRE_INDICES(set, 2, 5);
-    }
-
-    SECTION("discards indices in both shifted_by and values") {
-        set = {5};
-        set.add_shifted_by({2}, {2, 4});
-        REQUIRE_INDICES(set, 3, 5);
-    }
-}
-
-TEST_CASE("index_set: set()") {
-    realm::IndexSet set;
-
-    SECTION("clears the existing indices and replaces with the range [0, value)") {
-        set = {8, 9};
-        set.set(5);
-        REQUIRE_INDICES(set, 0, 1, 2, 3, 4);
-    }
-}
-
-TEST_CASE("index_set: insert_at()") {
-    realm::IndexSet set;
-
-    SECTION("on an empty set is add()") {
-        set.insert_at(5);
-        REQUIRE_INDICES(set, 5);
-
-        set = {};
-        set.insert_at({1, 3, 5});
-        REQUIRE_INDICES(set, 1, 3, 5);
-    }
-
-    SECTION("with an empty set is a no-op") {
-        set = {5, 6};
-        set.insert_at(realm::IndexSet{});
-        REQUIRE_INDICES(set, 5, 6);
-    }
-
-    SECTION("extends ranges containing the target range") {
-        set = {5, 6};
-
-        set.insert_at(5);
-        REQUIRE_INDICES(set, 5, 6, 7);
-
-        set.insert_at(6, 2);
-        REQUIRE_INDICES(set, 5, 6, 7, 8, 9);
-
-        set.insert_at({5, 7, 11});
-        REQUIRE_INDICES(set, 5, 6, 7, 8, 9, 10, 11, 12);
-    }
-
-    SECTION("shifts ranges after the insertion point") {
-        set = {5, 6};
-
-        set.insert_at(3);
-        REQUIRE_INDICES(set, 3, 6, 7);
-
-        set.insert_at(0, 2);
-        REQUIRE_INDICES(set, 0, 1, 5, 8, 9);
-    }
-
-    SECTION("does not shift ranges before the insertion point") {
-        set = {5, 6};
-
-        set.insert_at(10);
-        REQUIRE_INDICES(set, 5, 6, 10);
-
-        set.insert_at({15, 16});
-        REQUIRE_INDICES(set, 5, 6, 10, 15, 16);
-    }
-
-    SECTION("can not join ranges") {
-        set = {5, 7};
-        set.insert_at(6);
-        REQUIRE_INDICES(set, 5, 6, 8);
-    }
-
-    SECTION("adds later ranges after shifting for previous insertions") {
-        set = {5, 10};
-        set.insert_at({5, 10});
-        REQUIRE_INDICES(set, 5, 6, 10, 12);
-    }
-}
-
-TEST_CASE("index_set: shift_for_insert_at()") {
-    realm::IndexSet set;
-
-    SECTION("does nothing given an empty set of insertion points") {
-        set = {5, 8};
-        set.shift_for_insert_at(realm::IndexSet{});
-        REQUIRE_INDICES(set, 5, 8);
-    }
-
-    SECTION("does nothing when called on an empty set") {
-        set = {};
-        set.shift_for_insert_at({5, 8});
-        REQUIRE(set.empty());
-    }
-
-    SECTION("does nothing when the insertion points are all after the current indices") {
-        set = {10, 20};
-        set.shift_for_insert_at({30, 40});
-        REQUIRE_INDICES(set, 10, 20);
-    }
-
-    SECTION("does shift when the insertion points are all before the current indices") {
-        set = {10, 20};
-        set.shift_for_insert_at({2, 4});
-        REQUIRE_INDICES(set, 12, 22);
-    }
-
-    SECTION("shifts indices at or after the insertion points") {
-        set = {5};
-
-        set.shift_for_insert_at(4);
-        REQUIRE_INDICES(set, 6);
-
-        set.shift_for_insert_at(6);
-        REQUIRE_INDICES(set, 7);
-
-        set.shift_for_insert_at({3, 8});
-        REQUIRE_INDICES(set, 9);
-    }
-
-    SECTION("shifts indices by the count specified") {
-        set = {5};
-        set.shift_for_insert_at(3, 10);
-        REQUIRE_INDICES(set, 15);
-    }
-
-    SECTION("does not shift indices before the insertion points") {
-        set = {5};
-
-        set.shift_for_insert_at(6);
-        REQUIRE_INDICES(set, 5);
-
-        set.shift_for_insert_at({3, 8});
-        REQUIRE_INDICES(set, 6);
-    }
-
-    SECTION("splits ranges containing the insertion points") {
-        set = {5, 6, 7, 8};
-
-        set.shift_for_insert_at(6);
-        REQUIRE_INDICES(set, 5, 7, 8, 9);
-
-        set.shift_for_insert_at({8, 10, 12});
-        REQUIRE_INDICES(set, 5, 7, 9, 11);
-    }
-}
-
-TEST_CASE("index_set: erase_at()") {
-    realm::IndexSet set;
-
-    SECTION("is a no-op on an empty set") {
-        set.erase_at(10);
-        REQUIRE(set.empty());
-
-        set.erase_at({1, 5, 8});
-        REQUIRE(set.empty());
-    }
-
-    SECTION("does nothing when given an empty set") {
-        set = {5};
-        set.erase_at(realm::IndexSet{});
-        REQUIRE_INDICES(set, 5);
-    }
-
-    SECTION("removes the specified indices") {
-        set = {5};
-        set.erase_at(5);
-        REQUIRE(set.empty());
-
-        set = {4, 7};
-        set.erase_at({4, 7});
-        REQUIRE(set.empty());
-    }
-
-    SECTION("does not modify indices before the removed one") {
-        set = {5, 8};
-        set.erase_at(8);
-        REQUIRE_INDICES(set, 5);
-
-        set = {5, 8, 9};
-        set.erase_at({8, 9});
-        REQUIRE_INDICES(set, 5);
-    }
-
-    SECTION("shifts indices after the removed one") {
-        set = {5, 8};
-        set.erase_at(5);
-        REQUIRE_INDICES(set, 7);
-
-        set = {5, 10, 15, 20};
-        set.erase_at({5, 10});
-        REQUIRE_INDICES(set, 13, 18);
-    }
-
-    SECTION("shrinks ranges when used on one of the edges of them") {
-        set = {5, 6, 7, 8};
-        set.erase_at(8);
-        REQUIRE_INDICES(set, 5, 6, 7);
-        set.erase_at(5);
-        REQUIRE_INDICES(set, 5, 6);
-
-        set = {5, 6, 7, 8};
-        set.erase_at({5, 8});
-        REQUIRE_INDICES(set, 5, 6);
-    }
-
-    SECTION("shrinks ranges when used in the middle of them") {
-        set = {5, 6, 7, 8};
-        set.erase_at(7);
-        REQUIRE_INDICES(set, 5, 6, 7);
-
-        set = {5, 6, 7, 8};
-        set.erase_at({6, 7});
-        REQUIRE_INDICES(set, 5, 6);
-    }
-
-    SECTION("merges ranges when the gap between them is deleted") {
-        set = {3, 5};
-        set.erase_at(4);
-        REQUIRE_INDICES(set, 3, 4);
-
-        set = {3, 5, 7};
-        set.erase_at({4, 6});
-        REQUIRE_INDICES(set, 3, 4, 5);
-    }
-}
-
-TEST_CASE("index_set: erase_or_unshift()") {
-    realm::IndexSet set;
-
-    SECTION("removes the given index") {
-        set = {1, 2};
-        set.erase_or_unshift(2);
-        REQUIRE_INDICES(set, 1);
-    }
-
-    SECTION("shifts indexes after the given index") {
-        set = {1, 5};
-        set.erase_or_unshift(2);
-        REQUIRE_INDICES(set, 1, 4);
-    }
-
-    SECTION("returns npos for indices in the set") {
-        set = {1, 3, 5};
-        REQUIRE(realm::IndexSet(set).erase_or_unshift(1) == realm::IndexSet::npos);
-        REQUIRE(realm::IndexSet(set).erase_or_unshift(3) == realm::IndexSet::npos);
-        REQUIRE(realm::IndexSet(set).erase_or_unshift(5) == realm::IndexSet::npos);
-    }
-
-    SECTION("returns the number of indices in the set before the index for ones not in the set") {
-        set = {1, 3, 5, 6};
-        REQUIRE(realm::IndexSet(set).erase_or_unshift(0) == 0);
-        REQUIRE(realm::IndexSet(set).erase_or_unshift(2) == 1);
-        REQUIRE(realm::IndexSet(set).erase_or_unshift(4) == 2);
-        REQUIRE(realm::IndexSet(set).erase_or_unshift(7) == 3);
-    }
-
-}
-
-TEST_CASE("index_set: remove()") {
-    realm::IndexSet set;
-
-    SECTION("is a no-op if the set is empty") {
-        set.remove(4);
-        REQUIRE(set.empty());
-
-        set.remove({1, 2, 3});
-        REQUIRE(set.empty());
-    }
-
-    SECTION("is a no-op if the set to remove is empty") {
-        set = {5};
-        set.remove(realm::IndexSet{});
-        REQUIRE_INDICES(set, 5);
-    }
-
-    SECTION("is a no-op if the index to remove is not in the set") {
-        set = {5};
-        set.remove(4);
-        set.remove(6);
-        set.remove({4, 6});
-        REQUIRE_INDICES(set, 5);
-    }
-
-    SECTION("removes one-element ranges") {
-        set = {5};
-        set.remove(5);
-        REQUIRE(set.empty());
-
-        set = {5};
-        set.remove({3, 4, 5});
-        REQUIRE(set.empty());
-    }
-
-    SECTION("shrinks ranges beginning with the index") {
-        set = {5, 6, 7};
-        set.remove(5);
-        REQUIRE_INDICES(set, 6, 7);
-
-        set = {5, 6, 7};
-        set.remove({3, 5});
-        REQUIRE_INDICES(set, 6, 7);
-    }
-
-    SECTION("shrinks ranges ending with the index") {
-        set = {5, 6, 7};
-        set.remove(7);
-        REQUIRE_INDICES(set, 5, 6);
-
-        set = {5, 6, 7};
-        set.remove({3, 7});
-        REQUIRE_INDICES(set, 5, 6);
-    }
-
-    SECTION("splits ranges containing the index") {
-        set = {5, 6, 7};
-        set.remove(6);
-        REQUIRE_INDICES(set, 5, 7);
-
-        set = {5, 6, 7};
-        set.remove({3, 6});
-        REQUIRE_INDICES(set, 5, 7);
-    }
-
-    SECTION("does not shift other indices and uses unshifted positions") {
-        set = {5, 6, 7, 10, 11, 12, 13, 15};
-        set.remove({6, 11, 13});
-        REQUIRE_INDICES(set, 5, 7, 10, 12, 15);
-    }
-}
-
-TEST_CASE("index_set: shift()") {
-    realm::IndexSet set;
-
-    SECTION("is ind + count(0, ind), but adds the count-so-far to the stop index") {
-        set = {1, 3, 5, 6};
-        REQUIRE(set.shift(0) == 0);
-        REQUIRE(set.shift(1) == 2);
-        REQUIRE(set.shift(2) == 4);
-        REQUIRE(set.shift(3) == 7);
-        REQUIRE(set.shift(4) == 8);
-    }
-}
-
-TEST_CASE("index_set: unshift()") {
-    realm::IndexSet set;
-
-    SECTION("is index - count(0, index)") {
-        set = {1, 3, 5, 6};
-        REQUIRE(set.unshift(0) == 0);
-        REQUIRE(set.unshift(2) == 1);
-        REQUIRE(set.unshift(4) == 2);
-        REQUIRE(set.unshift(7) == 3);
-        REQUIRE(set.unshift(8) == 4);
-    }
-}
-
-TEST_CASE("index_set: clear()") {
-    realm::IndexSet set;
-
-    SECTION("removes all indices from the set") {
-        set = {1, 2, 3};
-        set.clear();
-        REQUIRE(set.empty());
-    }
-}

+ 0 - 912
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/list.cpp

@@ -1,912 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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 "catch2/catch.hpp"
-
-#include "util/test_file.hpp"
-#include "util/index_helpers.hpp"
-
-#include "binding_context.hpp"
-#include "list.hpp"
-#include "object.hpp"
-#include "object_schema.hpp"
-#include "property.hpp"
-#include "results.hpp"
-#include "schema.hpp"
-
-#include "impl/realm_coordinator.hpp"
-#include "impl/object_accessor_impl.hpp"
-
-#include <realm/version.hpp>
-#include <realm/db.hpp>
-
-#include <cstdint>
-
-using namespace realm;
-
-TEST_CASE("list") {
-    InMemoryTestFile config;
-    config.automatic_change_notifications = false;
-    auto r = Realm::get_shared_realm(config);
-    r->update_schema({
-        {"origin", {
-            {"pk", PropertyType::Int, Property::IsPrimary{true}},
-            {"array", PropertyType::Array|PropertyType::Object, "target"}
-        }},
-        {"target", {
-            {"value", PropertyType::Int}
-        }},
-        {"other_origin", {
-            {"array", PropertyType::Array|PropertyType::Object, "other_target"}
-        }},
-        {"other_target", {
-            {"value", PropertyType::Int}
-        }},
-    });
-
-    auto& coordinator = *_impl::RealmCoordinator::get_coordinator(config.path);
-
-    auto origin = r->read_group().get_table("class_origin");
-    auto target = r->read_group().get_table("class_target");
-    auto other_origin = r->read_group().get_table("class_other_origin");
-    auto other_target = r->read_group().get_table("class_other_target");
-    ColKey col_link = origin->get_column_key("array");
-    ColKey col_value = target->get_column_key("value");
-    ColKey other_col_link = other_origin->get_column_key("array");
-    ColKey other_col_value = other_target->get_column_key("value");
-
-    r->begin_transaction();
-
-    std::vector<ObjKey> target_keys;
-    target->create_objects(10, target_keys);
-    for (int i = 0; i < 10; ++i)
-        target->get_object(target_keys[i]).set_all(i);
-
-    Obj obj = origin->create_object();
-    auto lv = obj.get_linklist_ptr(col_link);
-    for (int i = 0; i < 10; ++i)
-        lv->add(target_keys[i]);
-    auto lv2 = origin->create_object().get_linklist_ptr(col_link);
-    for (int i = 0; i < 10; ++i)
-        lv2->add(target_keys[i]);
-
-    ObjKeys other_target_keys({3, 5, 7, 9, 11, 13, 15, 17, 19, 21});
-    other_target->create_objects(other_target_keys);
-    for (int i = 0; i < 10; ++i)
-        other_target->get_object(other_target_keys[i]).set_all(i);
-
-    Obj other_obj = other_origin->create_object();
-    auto other_lv = other_obj.get_linklist_ptr(other_col_link);
-    for (int i = 0; i < 10; ++i)
-        other_lv->add(other_target_keys[i]);
-
-    r->commit_transaction();
-
-    auto r2 = coordinator.get_realm();
-    auto r2_lv = r2->read_group().get_table("class_origin")->get_object(0).get_linklist_ptr(col_link);
-
-    SECTION("add_notification_block()") {
-        CollectionChangeSet change;
-        List lst(r, obj, col_link);
-
-        auto write = [&](auto&& f) {
-            r->begin_transaction();
-            f();
-            r->commit_transaction();
-
-            advance_and_notify(*r);
-        };
-
-        auto require_change = [&] {
-            auto token = lst.add_notification_callback([&](CollectionChangeSet c, std::exception_ptr) {
-                change = c;
-            });
-            advance_and_notify(*r);
-            return token;
-        };
-
-        auto require_no_change = [&] {
-            bool first = true;
-            auto token = lst.add_notification_callback([&, first](CollectionChangeSet, std::exception_ptr) mutable {
-                REQUIRE(first);
-                first = false;
-            });
-            advance_and_notify(*r);
-            return token;
-        };
-
-        SECTION("modifying the list sends a change notifications") {
-            auto token = require_change();
-            write([&] { if (lv2->size() > 5) lst.remove(5); });
-            REQUIRE_INDICES(change.deletions, 5);
-        }
-
-        SECTION("modifying a different list doesn't send a change notification") {
-            auto token = require_no_change();
-            write([&] { if (lv2->size() > 5) lv2->remove(5); });
-        }
-
-        SECTION("deleting the list sends a change notification") {
-            auto token = require_change();
-            write([&] { obj.remove(); });
-            REQUIRE_INDICES(change.deletions, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
-
-            // Should not resend delete all notification after another commit
-            change = {};
-            write([&] { target->create_object(); });
-            REQUIRE(change.empty());
-        }
-
-        SECTION("deleting list before first run of notifier reports deletions") {
-            auto token = lst.add_notification_callback([&](CollectionChangeSet c, std::exception_ptr) {
-                change = c;
-            });
-            advance_and_notify(*r);
-            write([&] { origin->begin()->remove(); });
-            REQUIRE_INDICES(change.deletions, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
-        }
-
-        SECTION("modifying one of the target rows sends a change notification") {
-            auto token = require_change();
-            write([&] { lst.get(5).set(col_value, 6); });
-            REQUIRE_INDICES(change.modifications, 5);
-        }
-
-        SECTION("deleting a target row sends a change notification") {
-            auto token = require_change();
-            write([&] { target->remove_object(target_keys[5]); });
-            REQUIRE_INDICES(change.deletions, 5);
-        }
-
-        SECTION("adding a row and then modifying the target row does not mark the row as modified") {
-            auto token = require_change();
-            write([&] {
-                Obj obj = target->get_object(target_keys[5]);
-                lst.add(obj);
-                obj.set(col_value, 10);
-            });
-            REQUIRE_INDICES(change.insertions, 10);
-            REQUIRE_INDICES(change.modifications, 5);
-        }
-
-        SECTION("modifying and then moving a row reports move/insert but not modification") {
-            auto token = require_change();
-            write([&] {
-                target->get_object(target_keys[5]).set(col_value, 10);
-                lst.move(5, 8);
-            });
-            REQUIRE_INDICES(change.insertions, 8);
-            REQUIRE_INDICES(change.deletions, 5);
-            REQUIRE_MOVES(change, {5, 8});
-            REQUIRE(change.modifications.empty());
-        }
-
-        SECTION("modifying a row which appears multiple times in a list marks them all as modified") {
-            r->begin_transaction();
-            lst.add(target_keys[5]);
-            r->commit_transaction();
-
-            auto token = require_change();
-            write([&] { target->get_object(target_keys[5]).set(col_value, 10); });
-            REQUIRE_INDICES(change.modifications, 5, 10);
-        }
-
-        SECTION("deleting a row which appears multiple times in a list marks them all as modified") {
-            r->begin_transaction();
-            lst.add(target_keys[5]);
-            r->commit_transaction();
-
-            auto token = require_change();
-            write([&] { target->remove_object(target_keys[5]); });
-            REQUIRE_INDICES(change.deletions, 5, 10);
-        }
-
-        SECTION("clearing the target table sends a change notification") {
-            auto token = require_change();
-            write([&] { target->clear(); });
-            REQUIRE_INDICES(change.deletions, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
-        }
-
-        SECTION("moving a target row does not send a change notification") {
-            // Remove a row from the LV so that we have one to delete that's not in the list
-            r->begin_transaction();
-            if (lv->size() > 2)
-                lv->remove(2);
-            r->commit_transaction();
-
-            auto token = require_no_change();
-            write([&] { target->remove_object(target_keys[2]); });
-        }
-
-        SECTION("multiple LinkViews for the same LinkList can get notifications") {
-            r->begin_transaction();
-            target->clear();
-            std::vector<ObjKey> keys;
-            target->create_objects(5, keys);
-            r->commit_transaction();
-
-            auto get_list = [&] {
-                auto r = Realm::get_shared_realm(config);
-                auto obj = r->read_group().get_table("class_origin")->get_object(0);
-                return List(r, obj, col_link);
-            };
-            auto change_list = [&] {
-                r->begin_transaction();
-                if (lv->size()) {
-                    target->get_object(lv->size() - 1).set(col_value, int64_t(lv->size()));
-                }
-                lv->add(keys[lv->size()]);
-                r->commit_transaction();
-            };
-
-            List lists[3];
-            NotificationToken tokens[3];
-            CollectionChangeSet changes[3];
-
-            for (int i = 0; i < 3; ++i) {
-                lists[i] = get_list();
-                tokens[i] = lists[i].add_notification_callback([i, &changes](CollectionChangeSet c, std::exception_ptr) {
-                    changes[i] = std::move(c);
-                });
-                change_list();
-            }
-
-            // Each of the Lists now has a different source version and state at
-            // that version, so they should all see different changes despite
-            // being for the same LinkList
-            for (auto& list : lists)
-                advance_and_notify(*list.get_realm());
-
-            REQUIRE_INDICES(changes[0].insertions, 0, 1, 2);
-            REQUIRE(changes[0].modifications.empty());
-
-            REQUIRE_INDICES(changes[1].insertions, 1, 2);
-            REQUIRE_INDICES(changes[1].modifications, 0);
-
-            REQUIRE_INDICES(changes[2].insertions, 2);
-            REQUIRE_INDICES(changes[2].modifications, 1);
-
-            // After making another change, they should all get the same notification
-            change_list();
-            for (auto& list : lists)
-                advance_and_notify(*list.get_realm());
-
-            for (int i = 0; i < 3; ++i) {
-                REQUIRE_INDICES(changes[i].insertions, 3);
-                REQUIRE_INDICES(changes[i].modifications, 2);
-            }
-        }
-
-        SECTION("multiple callbacks for the same Lists can be skipped individually") {
-            auto token = require_no_change();
-            auto token2 = require_change();
-
-            r->begin_transaction();
-            lv->add(target_keys[0]);
-            token.suppress_next();
-            r->commit_transaction();
-
-            advance_and_notify(*r);
-            REQUIRE_INDICES(change.insertions, 10);
-        }
-
-        SECTION("multiple Lists for the same LinkView can be skipped individually") {
-            auto token = require_no_change();
-
-            List list2(r, obj, col_link);
-            auto token2 = list2.add_notification_callback([&](CollectionChangeSet c, std::exception_ptr) {
-                change = c;
-            });
-            advance_and_notify(*r);
-
-            r->begin_transaction();
-            lv->add(target_keys[0]);
-            token.suppress_next();
-            r->commit_transaction();
-
-            advance_and_notify(*r);
-            REQUIRE_INDICES(change.insertions, 10);
-        }
-
-        SECTION("skipping only effects the current transaction even if no notification would occur anyway") {
-            auto token = require_change();
-
-            // would not produce a notification even if it wasn't skipped because no changes were made
-            r->begin_transaction();
-            token.suppress_next();
-            r->commit_transaction();
-            advance_and_notify(*r);
-            REQUIRE(change.empty());
-
-            // should now produce a notification
-            r->begin_transaction();
-            lv->add(target_keys[0]);
-            r->commit_transaction();
-            advance_and_notify(*r);
-            REQUIRE_INDICES(change.insertions, 10);
-        }
-
-        SECTION("modifying a different table does not send a change notification") {
-            auto token = require_no_change();
-            write([&] { other_lv->add(other_target_keys[0]); });
-        }
-
-        SECTION("changes are reported correctly for multiple tables") {
-            List list2(r, *other_lv);
-            CollectionChangeSet other_changes;
-            auto token1 = list2.add_notification_callback([&](CollectionChangeSet c, std::exception_ptr) {
-                other_changes = std::move(c);
-            });
-            auto token2 = require_change();
-
-            write([&] {
-                lv->add(target_keys[1]);
-
-                other_origin->create_object();
-                if (other_lv->size() > 0)
-                    other_lv->insert(1, other_target_keys[0]);
-
-                lv->add(target_keys[2]);
-            });
-            REQUIRE_INDICES(change.insertions, 10, 11);
-            REQUIRE_INDICES(other_changes.insertions, 1);
-
-            write([&] {
-                lv->add(target_keys[3]);
-                other_obj.remove();
-                lv->add(target_keys[4]);
-            });
-            REQUIRE_INDICES(change.insertions, 12, 13);
-            REQUIRE_INDICES(other_changes.deletions, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
-
-            write([&] {
-                lv->add(target_keys[5]);
-                other_origin->clear();
-                lv->add(target_keys[6]);
-            });
-            REQUIRE_INDICES(change.insertions, 14, 15);
-        }
-
-        SECTION("tables-of-interest are tracked properly for multiple source versions") {
-            // Add notifiers for different tables at different versions to verify
-            // that the tables of interest are updated correctly as we process
-            // new notifiers
-            CollectionChangeSet changes1, changes2;
-            auto token1 = lst.add_notification_callback([&](CollectionChangeSet c, std::exception_ptr) {
-                changes1 = std::move(c);
-            });
-
-            r2->begin_transaction();
-            r2->read_group().get_table("class_target")->get_object(target_keys[0]).set(col_value, 10);
-            r2->read_group().get_table("class_other_target")->get_object(other_target_keys[1]).set(other_col_value, 10);
-            r2->commit_transaction();
-
-            List list2(r2, r2->read_group().get_table("class_other_origin")->get_object(0), other_col_link);
-            auto token2 = list2.add_notification_callback([&](CollectionChangeSet c, std::exception_ptr) {
-                changes2 = std::move(c);
-            });
-
-            auto r3 = coordinator.get_realm();
-            r3->begin_transaction();
-            r3->read_group().get_table("class_target")->get_object(target_keys[2]).set(col_value, 10);
-            r3->read_group().get_table("class_other_target")->get_object(other_target_keys[3]).set(other_col_value, 10);
-            r3->commit_transaction();
-
-            advance_and_notify(*r);
-            advance_and_notify(*r2);
-
-            REQUIRE_INDICES(changes1.modifications, 0, 2);
-            REQUIRE_INDICES(changes2.modifications, 3);
-        }
-
-        SECTION("modifications are reported for rows that are moved and then moved back in a second transaction") {
-            auto token = require_change();
-
-            r2->begin_transaction();
-            r2_lv->get_object(5).set(col_value, 10);
-            r2_lv->get_object(1).set(col_value, 10);
-            r2_lv->move(5, 8);
-            r2_lv->move(1, 2);
-            r2->commit_transaction();
-
-            coordinator.on_change();
-
-            r2->begin_transaction();
-            if (r2_lv->size() > 8)
-                r2_lv->move(8, 5);
-            r2->commit_transaction();
-            advance_and_notify(*r);
-
-            REQUIRE_INDICES(change.deletions, 1);
-            REQUIRE_INDICES(change.insertions, 2);
-            REQUIRE_INDICES(change.modifications, 5);
-            REQUIRE_MOVES(change, {1, 2});
-        }
-
-        SECTION("changes are sent in initial notification") {
-            auto token = lst.add_notification_callback([&](CollectionChangeSet c, std::exception_ptr) {
-                change = c;
-            });
-            r2->begin_transaction();
-            r2_lv->remove(5);
-            r2->commit_transaction();
-            advance_and_notify(*r);
-            REQUIRE_INDICES(change.deletions, 5);
-        }
-
-        SECTION("changes are sent in initial notification after removing and then re-adding callback") {
-            auto token = lst.add_notification_callback([&](CollectionChangeSet, std::exception_ptr) {
-                REQUIRE(false);
-            });
-            token = {};
-
-            auto write = [&] {
-                r2->begin_transaction();
-                r2_lv->remove(5);
-                r2->commit_transaction();
-            };
-
-            SECTION("add new callback before transaction") {
-                token = lst.add_notification_callback([&](CollectionChangeSet c, std::exception_ptr) {
-                    change = c;
-                });
-
-                write();
-
-                advance_and_notify(*r);
-                REQUIRE_INDICES(change.deletions, 5);
-            }
-
-            SECTION("add new callback after transaction") {
-                write();
-
-                token = lst.add_notification_callback([&](CollectionChangeSet c, std::exception_ptr) {
-                    change = c;
-                });
-
-                advance_and_notify(*r);
-                REQUIRE_INDICES(change.deletions, 5);
-            }
-
-            SECTION("add new callback after transaction and after changeset was calculated") {
-                write();
-                coordinator.on_change();
-
-                token = lst.add_notification_callback([&](CollectionChangeSet c, std::exception_ptr) {
-                    change = c;
-                });
-
-                advance_and_notify(*r);
-                REQUIRE_INDICES(change.deletions, 5);
-            }
-        }
-    }
-
-    SECTION("sorted add_notification_block()") {
-        List lst(r, *lv);
-        Results results = lst.sort({{{col_value}}, {false}});
-
-        int notification_calls = 0;
-        CollectionChangeSet change;
-        auto token = results.add_notification_callback([&](CollectionChangeSet c, std::exception_ptr err) {
-            REQUIRE_FALSE(err);
-            change = c;
-            ++notification_calls;
-        });
-
-        advance_and_notify(*r);
-
-        auto write = [&](auto&& f) {
-            r->begin_transaction();
-            f();
-            r->commit_transaction();
-
-            advance_and_notify(*r);
-        };
-        SECTION("add duplicates") {
-            write([&] {
-                lst.add(target_keys[5]);
-                lst.add(target_keys[5]);
-                lst.add(target_keys[5]);
-            });
-            REQUIRE(notification_calls == 2);
-            REQUIRE_INDICES(change.insertions, 5, 6, 7);
-        }
-
-        SECTION("change order by modifying target") {
-            write([&] {
-                lst.get(5).set(col_value, 15);
-            });
-            REQUIRE(notification_calls == 2);
-            REQUIRE_INDICES(change.deletions, 4);
-            REQUIRE_INDICES(change.insertions, 0);
-        }
-
-        SECTION("swap") {
-            write([&] {
-                lst.swap(1, 2);
-            });
-            REQUIRE(notification_calls == 1);
-        }
-
-        SECTION("move") {
-            write([&] {
-                lst.move(5, 3);
-            });
-            REQUIRE(notification_calls == 1);
-        }
-    }
-
-    SECTION("filtered add_notification_block()") {
-        List lst(r, *lv);
-        Results results = lst.filter(target->where().less(col_value, 9));
-
-        int notification_calls = 0;
-        CollectionChangeSet change;
-        auto token = results.add_notification_callback([&](CollectionChangeSet c, std::exception_ptr err) {
-            REQUIRE_FALSE(err);
-            change = c;
-            ++notification_calls;
-        });
-
-        advance_and_notify(*r);
-
-        auto write = [&](auto&& f) {
-            r->begin_transaction();
-            f();
-            r->commit_transaction();
-
-            advance_and_notify(*r);
-        };
-        SECTION("add duplicates") {
-            write([&] {
-                lst.add(target_keys[5]);
-                lst.add(target_keys[5]);
-                lst.add(target_keys[5]);
-            });
-            REQUIRE(notification_calls == 2);
-            REQUIRE_INDICES(change.insertions, 9, 10, 11);
-        }
-
-        SECTION("swap") {
-            write([&] {
-                lst.swap(1, 2);
-            });
-            REQUIRE(notification_calls == 2);
-            REQUIRE_INDICES(change.deletions, 2);
-            REQUIRE_INDICES(change.insertions, 1);
-
-            write([&] {
-                lst.swap(5, 8);
-            });
-            REQUIRE(notification_calls == 3);
-            REQUIRE_INDICES(change.deletions, 5, 8);
-            REQUIRE_INDICES(change.insertions, 5, 8);
-        }
-
-        SECTION("move") {
-            write([&] {
-                lst.move(5, 3);
-            });
-            REQUIRE(notification_calls == 2);
-            REQUIRE_INDICES(change.deletions, 5);
-            REQUIRE_INDICES(change.insertions, 3);
-        }
-
-        SECTION("move non-matching entry") {
-            write([&] {
-                lst.move(9, 3);
-            });
-            REQUIRE(notification_calls == 1);
-        }
-    }
-
-    SECTION("sort()") {
-        auto objectschema = &*r->schema().find("target");
-        List list(r, *lv);
-        auto results = list.sort({{{col_value}}, {false}});
-
-        REQUIRE(&results.get_object_schema() == objectschema);
-        REQUIRE(results.get_mode() == Results::Mode::LinkList);
-        REQUIRE(results.size() == 10);
-
-        // Aggregates don't inherently have to convert to TableView, but do
-        // because aggregates aren't implemented for LinkView
-        REQUIRE(results.sum(col_value) == 45);
-        REQUIRE(results.get_mode() == Results::Mode::TableView);
-
-        // Reset to LinkView mode to test implicit conversion to TableView on get()
-        results = list.sort({{{col_value}}, {false}});
-        for (size_t i = 0; i < 10; ++i)
-            REQUIRE(results.get(i).get_key() == target_keys[9 - i]);
-        REQUIRE_THROWS_WITH(results.get(10), "Requested index 10 greater than max 9");
-        REQUIRE(results.get_mode() == Results::Mode::TableView);
-
-        // Zero sort columns should leave it in LinkView mode
-        results = list.sort(SortDescriptor());
-        for (size_t i = 0; i < 10; ++i)
-            REQUIRE(results.get(i).get_key() == target_keys[i]);
-        REQUIRE_THROWS_WITH(results.get(10), "Requested index 10 greater than max 9");
-        REQUIRE(results.get_mode() == Results::Mode::LinkList);
-    }
-
-    SECTION("filter()") {
-        auto objectschema = &*r->schema().find("target");
-        List list(r, *lv);
-        auto results = list.filter(target->where().greater(col_value, 5));
-
-        REQUIRE(&results.get_object_schema() == objectschema);
-        REQUIRE(results.get_mode() == Results::Mode::Query);
-        REQUIRE(results.size() == 4);
-
-        for (size_t i = 0; i < 4; ++i) {
-            REQUIRE(results.get(i).get_key().value == i + 6);
-        }
-    }
-
-    SECTION("snapshot()") {
-        auto objectschema = &*r->schema().find("target");
-        List list(r, *lv);
-
-        auto snapshot = list.snapshot();
-        REQUIRE(&snapshot.get_object_schema() == objectschema);
-        REQUIRE(snapshot.get_mode() == Results::Mode::TableView);
-        REQUIRE(snapshot.size() == 10);
-
-        r->begin_transaction();
-        for (size_t i = 0; i < 5; ++i) {
-            list.remove(0);
-        }
-        REQUIRE(snapshot.size() == 10);
-        for (size_t i = 0; i < snapshot.size(); ++i) {
-            REQUIRE(snapshot.get(i).is_valid());
-        }
-        for (size_t i = 0; i < 5; ++i) {
-            target->remove_object(target_keys[i]);
-        }
-        REQUIRE(snapshot.size() == 10);
-        for (size_t i = 0; i < 5; ++i) {
-            REQUIRE(!snapshot.get(i).is_valid());
-        }
-        for (size_t i = 5; i < 10; ++i) {
-            REQUIRE(snapshot.get(i).is_valid());
-        }
-        list.add(target_keys[5]);
-        REQUIRE(snapshot.size() == 10);
-    }
-
-    SECTION("get_object_schema()") {
-        List list(r, *lv);
-        auto objectschema = &*r->schema().find("target");
-        REQUIRE(&list.get_object_schema() == objectschema);
-    }
-
-    SECTION("delete_at()") {
-        List list(r, *lv);
-        r->begin_transaction();
-        auto initial_view_size = lv->size();
-        auto initial_target_size = target->size();
-        list.delete_at(1);
-        REQUIRE(lv->size() == initial_view_size - 1);
-        REQUIRE(target->size() == initial_target_size - 1);
-        r->cancel_transaction();
-    }
-
-    SECTION("delete_all()") {
-        List list(r, *lv);
-        r->begin_transaction();
-        list.delete_all();
-        REQUIRE(lv->size() == 0);
-        REQUIRE(target->size() == 0);
-        r->cancel_transaction();
-    }
-
-    SECTION("as_results().clear()") {
-        List list(r, *lv);
-        r->begin_transaction();
-        list.as_results().clear();
-        REQUIRE(lv->size() == 0);
-        REQUIRE(target->size() == 0);
-        r->cancel_transaction();
-    }
-
-    SECTION("snapshot().clear()") {
-        List list(r, *lv);
-        r->begin_transaction();
-        auto snapshot = list.snapshot();
-        snapshot.clear();
-        REQUIRE(snapshot.size() == 10);
-        REQUIRE(list.size() == 0);
-        REQUIRE(lv->size() == 0);
-        REQUIRE(target->size() == 0);
-        r->cancel_transaction();
-    }
-
-    SECTION("add(RowExpr)") {
-        List list(r, *lv);
-        r->begin_transaction();
-        SECTION("adds rows from the correct table") {
-            list.add(target_keys[5]);
-            REQUIRE(list.size() == 11);
-            REQUIRE(list.get(10).get_key() == target_keys[5]);
-        }
-
-        SECTION("throws for rows from the wrong table") {
-            REQUIRE_THROWS(list.add(obj));
-        }
-        r->cancel_transaction();
-    }
-
-    SECTION("insert(RowExpr)") {
-        List list(r, *lv);
-        r->begin_transaction();
-
-        SECTION("insert rows from the correct table") {
-            list.insert(0, target_keys[5]);
-            REQUIRE(list.size() == 11);
-            REQUIRE(list.get(0).get_key() == target_keys[5]);
-        }
-
-        SECTION("throws for rows from the wrong table") {
-            REQUIRE_THROWS(list.insert(0, obj));
-        }
-
-        SECTION("throws for out of bounds insertions") {
-            REQUIRE_THROWS(list.insert(11, target_keys[5]));
-            REQUIRE_NOTHROW(list.insert(10, target_keys[5]));
-        }
-        r->cancel_transaction();
-    }
-
-    SECTION("set(RowExpr)") {
-        List list(r, *lv);
-        r->begin_transaction();
-
-        SECTION("assigns for rows from the correct table") {
-            list.set(0, target_keys[5]);
-            REQUIRE(list.size() == 10);
-            REQUIRE(list.get(0).get_key() == target_keys[5]);
-        }
-
-        SECTION("throws for rows from the wrong table") {
-            REQUIRE_THROWS(list.set(0, obj));
-        }
-
-        SECTION("throws for out of bounds sets") {
-            REQUIRE_THROWS(list.set(10, target_keys[5]));
-        }
-        r->cancel_transaction();
-    }
-
-    SECTION("find(RowExpr)") {
-        List list(r, *lv);
-        Obj obj1 = target->get_object(target_keys[1]);
-        Obj obj5 = target->get_object(target_keys[5]);
-
-        SECTION("returns index in list for values in the list") {
-            REQUIRE(list.find(obj5) == 5);
-        }
-
-        SECTION("returns index in list and not index in table") {
-            r->begin_transaction();
-            list.remove(1);
-            REQUIRE(list.find(obj5) == 4);
-            REQUIRE(list.as_results().index_of(obj5) == 4);
-            r->cancel_transaction();
-        }
-
-        SECTION("returns npos for values not in the list") {
-            r->begin_transaction();
-            list.remove(1);
-            REQUIRE(list.find(obj1) == npos);
-            REQUIRE(list.as_results().index_of(obj1) == npos);
-            r->cancel_transaction();
-        }
-
-        SECTION("throws for row in wrong table") {
-            REQUIRE_THROWS(list.find(obj));
-            REQUIRE_THROWS(list.as_results().index_of(obj));
-        }
-    }
-
-    SECTION("find(Query)") {
-        List list(r, *lv);
-
-        SECTION("returns index in list for values in the list") {
-            REQUIRE(list.find(std::move(target->where().equal(col_value, 5))) == 5);
-        }
-
-        SECTION("returns index in list and not index in table") {
-            r->begin_transaction();
-            list.remove(1);
-            REQUIRE(list.find(std::move(target->where().equal(col_value, 5))) == 4);
-            r->cancel_transaction();
-        }
-
-        SECTION("returns npos for values not in the list") {
-            REQUIRE(list.find(std::move(target->where().equal(col_value, 11))) == npos);
-        }
-    }
-
-    SECTION("add(Context)") {
-        List list(r, *lv);
-        CppContext ctx(r, &list.get_object_schema());
-        r->begin_transaction();
-
-        SECTION("adds boxed RowExpr") {
-            list.add(ctx, util::Any(target->get_object(target_keys[5])));
-            REQUIRE(list.size() == 11);
-            REQUIRE(list.get(10).get_key().value == 5);
-        }
-
-        SECTION("adds boxed realm::Object") {
-            realm::Object obj(r, list.get_object_schema(), target->get_object(target_keys[5]));
-            list.add(ctx, util::Any(obj));
-            REQUIRE(list.size() == 11);
-            REQUIRE(list.get(10).get_key() == target_keys[5]);
-        }
-
-        SECTION("creates new object for dictionary") {
-            list.add(ctx, util::Any(AnyDict{{"value", INT64_C(20)}}));
-            REQUIRE(list.size() == 11);
-            REQUIRE(target->size() == 11);
-            REQUIRE(list.get(10).get<Int>(col_value) == 20);
-        }
-
-        SECTION("throws for object in wrong table") {
-            REQUIRE_THROWS(list.add(ctx, util::Any(origin->get_object(0))));
-            realm::Object object(r, *r->schema().find("origin"), origin->get_object(0));
-            REQUIRE_THROWS(list.add(ctx, util::Any(object)));
-        }
-
-        r->cancel_transaction();
-    }
-
-    SECTION("find(Context)") {
-        List list(r, *lv);
-        CppContext ctx(r, &list.get_object_schema());
-
-        SECTION("returns index in list for boxed RowExpr") {
-            REQUIRE(list.find(ctx, util::Any(target->get_object(target_keys[5]))) == 5);
-        }
-
-        SECTION("returns index in list for boxed Object") {
-            realm::Object obj(r, *r->schema().find("origin"), target->get_object(target_keys[5]));
-            REQUIRE(list.find(ctx, util::Any(obj)) == 5);
-        }
-
-        SECTION("does not insert new objects for dictionaries") {
-            REQUIRE(list.find(ctx, util::Any(AnyDict{{"value", INT64_C(20)}})) == npos);
-            REQUIRE(target->size() == 10);
-        }
-
-        SECTION("throws for object in wrong table") {
-            REQUIRE_THROWS(list.find(ctx, util::Any(obj)));
-        }
-    }
-
-    SECTION("get(Context)") {
-        List list(r, *lv);
-        CppContext ctx(r, &list.get_object_schema());
-
-        Object obj;
-        REQUIRE_NOTHROW(obj = any_cast<Object&&>(list.get(ctx, 1)));
-        REQUIRE(obj.is_valid());
-        REQUIRE(obj.obj().get_key() == target_keys[1]);
-    }
-}

+ 0 - 52
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/main.cpp

@@ -1,52 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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.
-//
-////////////////////////////////////////////////////////////////////////////
-
-#define CATCH_CONFIG_RUNNER
-#include "catch2/catch.hpp"
-
-#include <limits.h>
-
-#ifdef _MSC_VER
-#include <Shlwapi.h>
-#pragma comment(lib, "Shlwapi.lib")
-#else
-#include <libgen.h>
-#endif
-
-int main(int argc, char** argv) {
-#ifdef _MSC_VER
-    char path[MAX_PATH];
-    if (GetModuleFileNameA(NULL, path, sizeof(path)) == 0) {
-        fprintf(stderr, "Failed to retrieve path to exectuable.\n");
-        return 1;
-    }
-    PathRemoveFileSpecA(path);
-    SetCurrentDirectoryA(path);
-#else
-    char executable[PATH_MAX];
-    if (realpath(argv[0], executable) == NULL) {
-        fprintf(stderr, "Failed to resolve path to exectuable.\n");
-        return 1;
-    }
-    const char* directory = dirname(executable);
-    chdir(directory);
-#endif
-
-    int result = Catch::Session().run(argc, argv);
-    return result < 0xff ? result : 0xff;
-}

+ 0 - 2059
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/migrations.cpp

@@ -1,2059 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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 "catch2/catch.hpp"
-
-#include "util/test_file.hpp"
-
-#include "object_schema.hpp"
-#include "object_store.hpp"
-#include "property.hpp"
-#include "schema.hpp"
-
-#include "impl/object_accessor_impl.hpp"
-
-#include <realm/group.hpp>
-#include <realm/table.hpp>
-#include <realm/util/scope_exit.hpp>
-
-#ifdef _WIN32
-#include <Windows.h>
-#endif
-
-using namespace realm;
-
-#define VERIFY_SCHEMA(r, m) verify_schema((r), __LINE__, m)
-
-#define REQUIRE_UPDATE_SUCCEEDS(r, s, version) do { \
-    REQUIRE_NOTHROW((r).update_schema(s, version)); \
-    VERIFY_SCHEMA(r, false); \
-    REQUIRE((r).schema() == s); \
-} while (0)
-
-#define REQUIRE_NO_MIGRATION_NEEDED(r, schema1, schema2) do { \
-    REQUIRE_UPDATE_SUCCEEDS(r, schema1, 0); \
-    REQUIRE_UPDATE_SUCCEEDS(r, schema2, 0); \
-} while (0)
-
-#define REQUIRE_MIGRATION_NEEDED(r, schema1, schema2) do { \
-    REQUIRE_UPDATE_SUCCEEDS(r, schema1, 0); \
-    REQUIRE_THROWS((r).update_schema(schema2)); \
-    REQUIRE((r).schema() == schema1); \
-    REQUIRE_UPDATE_SUCCEEDS(r, schema2, 1); \
-} while (0)
-
-namespace {
-void verify_schema(Realm& r, int line, bool in_migration)
-{
-    CAPTURE(line);
-    for (auto&& object_schema : r.schema()) {
-        auto table = r.read_group().get_table(object_schema.table_key);
-        REQUIRE(table);
-        REQUIRE(std::string(table->get_name()) == ObjectStore::table_name_for_object_type(object_schema.name));
-        CAPTURE(object_schema.name);
-        std::string primary_key;
-        if (!in_migration) {
-            primary_key = ObjectStore::get_primary_key_for_object(r.read_group(), object_schema.name);
-            REQUIRE(primary_key == object_schema.primary_key);
-        }
-        else {
-            primary_key = object_schema.primary_key;
-        }
-        for (auto&& prop : object_schema.persisted_properties) {
-            auto col = table->get_column_key(prop.name);
-            CAPTURE(prop.name);
-            REQUIRE(col);
-            REQUIRE(col == prop.column_key);
-            REQUIRE(to_underlying(ObjectSchema::from_core_type(*table, col)) ==
-                    to_underlying(prop.type));
-            REQUIRE(table->has_search_index(col) == prop.requires_index());
-            REQUIRE(bool(prop.is_primary) == (prop.name == primary_key));
-        }
-    }
-}
-
-TableRef get_table(std::shared_ptr<Realm> const& realm, StringData object_type)
-{
-    return ObjectStore::table_for_object_type(realm->read_group(), object_type);
-}
-
-// Helper functions for modifying Schema objects, mostly for the sake of making
-// it clear what exactly is different about the 2+ schema objects used in
-// various tests
-Schema add_table(Schema const& schema, ObjectSchema object_schema)
-{
-    std::vector<ObjectSchema> new_schema(schema.begin(), schema.end());
-    new_schema.push_back(std::move(object_schema));
-    return new_schema;
-}
-
-Schema remove_table(Schema const& schema, StringData object_name)
-{
-    std::vector<ObjectSchema> new_schema;
-    std::remove_copy_if(schema.begin(), schema.end(), std::back_inserter(new_schema),
-                        [&](auto&& object_schema) { return object_schema.name == object_name; });
-    return new_schema;
-}
-
-Schema add_property(Schema schema, StringData object_name, Property property)
-{
-    schema.find(object_name)->persisted_properties.push_back(std::move(property));
-    return schema;
-}
-
-Schema remove_property(Schema schema, StringData object_name, StringData property_name)
-{
-    auto& properties = schema.find(object_name)->persisted_properties;
-    properties.erase(find_if(begin(properties), end(properties),
-                             [&](auto&& prop) { return prop.name == property_name; }));
-    return schema;
-}
-
-Schema set_indexed(Schema schema, StringData object_name, StringData property_name, bool value)
-{
-    schema.find(object_name)->property_for_name(property_name)->is_indexed = value;
-    return schema;
-}
-
-Schema set_optional(Schema schema, StringData object_name, StringData property_name, bool value)
-{
-    auto& prop = *schema.find(object_name)->property_for_name(property_name);
-    if (value)
-        prop.type |= PropertyType::Nullable;
-    else
-        prop.type &= ~PropertyType::Nullable;
-    return schema;
-}
-
-Schema set_type(Schema schema, StringData object_name, StringData property_name, PropertyType value)
-{
-    schema.find(object_name)->property_for_name(property_name)->type = value;
-    return schema;
-}
-
-Schema set_target(Schema schema, StringData object_name, StringData property_name, StringData new_target)
-{
-    schema.find(object_name)->property_for_name(property_name)->object_type = new_target;
-    return schema;
-}
-
-Schema set_primary_key(Schema schema, StringData object_name, StringData new_primary_property)
-{
-    auto& object_schema = *schema.find(object_name);
-    if (auto old_primary = object_schema.primary_key_property()) {
-        old_primary->is_primary = false;
-    }
-    if (new_primary_property.size()) {
-        object_schema.property_for_name(new_primary_property)->is_primary = true;
-    }
-    object_schema.primary_key = new_primary_property;
-    return schema;
-}
-auto create_objects(Table& table, size_t count) {
-    std::vector<ObjKey> keys;
-    table.create_objects(count, keys);
-    return keys;
-};
-} // anonymous namespace
-
-TEST_CASE("migration: Automatic") {
-    InMemoryTestFile config;
-    config.automatic_change_notifications = false;
-
-    SECTION("no migration required") {
-        SECTION("add object schema") {
-            auto realm = Realm::get_shared_realm(config);
-
-            Schema schema1 = {};
-            Schema schema2 = add_table(schema1, {"object", {
-                {"value", PropertyType::Int}
-            }});
-            Schema schema3 = add_table(schema2, {"object2", {
-                {"value", PropertyType::Int}
-            }});
-            REQUIRE_UPDATE_SUCCEEDS(*realm, schema1, 0);
-            REQUIRE_UPDATE_SUCCEEDS(*realm, schema2, 0);
-            REQUIRE_UPDATE_SUCCEEDS(*realm, schema3, 0);
-        }
-
-        SECTION("remove object schema") {
-            auto realm = Realm::get_shared_realm(config);
-
-            Schema schema1 = {
-                {"object", {
-                    {"value", PropertyType::Int}
-                }},
-                {"object2", {
-                    {"value", PropertyType::Int}
-                }},
-            };
-            Schema schema2 = remove_table(schema1, "object2");
-            Schema schema3 = remove_table(schema2, "object");
-            REQUIRE_UPDATE_SUCCEEDS(*realm, schema3, 0);
-            REQUIRE_UPDATE_SUCCEEDS(*realm, schema2, 0);
-            REQUIRE_UPDATE_SUCCEEDS(*realm, schema1, 0);
-        }
-
-        SECTION("add index") {
-            auto realm = Realm::get_shared_realm(config);
-            Schema schema = {
-                {"object", {
-                    {"value", PropertyType::Int}
-                }},
-            };
-            REQUIRE_NO_MIGRATION_NEEDED(*realm, schema, set_indexed(schema, "object", "value", true));
-        }
-
-        SECTION("remove index") {
-            auto realm = Realm::get_shared_realm(config);
-            Schema schema = {
-                {"object", {
-                    {"value", PropertyType::Int, Property::IsPrimary{false}, Property::IsIndexed{true}}
-                }},
-            };
-            REQUIRE_NO_MIGRATION_NEEDED(*realm, schema, set_indexed(schema, "object", "value", false));
-        }
-
-        SECTION("reordering properties") {
-            auto realm = Realm::get_shared_realm(config);
-
-            Schema schema1 = {
-                {"object", {
-                    {"col1", PropertyType::Int},
-                    {"col2", PropertyType::Int},
-                }},
-            };
-            Schema schema2 = {
-                {"object", {
-                    {"col2", PropertyType::Int},
-                    {"col1", PropertyType::Int},
-                }},
-            };
-            REQUIRE_NO_MIGRATION_NEEDED(*realm, schema1, schema2);
-        }
-    }
-
-    SECTION("migration required") {
-        SECTION("add property to existing object schema") {
-            auto realm = Realm::get_shared_realm(config);
-
-            Schema schema1 = {
-                {"object", {
-                    {"col1", PropertyType::Int},
-                }},
-            };
-            auto schema2 = add_property(schema1, "object",
-                                        {"col2", PropertyType::Int});
-            REQUIRE_MIGRATION_NEEDED(*realm, schema1, schema2);
-        }
-
-        SECTION("remove property from existing object schema") {
-            auto realm = Realm::get_shared_realm(config);
-            Schema schema = {
-                {"object", {
-                    {"col1", PropertyType::Int},
-                    {"col2", PropertyType::Int},
-                }},
-            };
-            REQUIRE_MIGRATION_NEEDED(*realm, schema, remove_property(schema, "object", "col2"));
-        }
-
-        SECTION("migratation which replaces a persisted property with a computed one") {
-            auto realm = Realm::get_shared_realm(config);
-            Schema schema1 = {
-                {"object", {
-                    {"value", PropertyType::Int},
-                    {"link", PropertyType::Object|PropertyType::Nullable, "object2"},
-                }},
-                {"object2", {
-                    {"value", PropertyType::Int},
-                    {"inverse", PropertyType::Object|PropertyType::Nullable, "object"},
-                }},
-            };
-            Schema schema2 = remove_property(schema1, "object", "link");
-            Property new_property{"link", PropertyType::LinkingObjects|PropertyType::Array, "object2", "inverse"};
-            schema2.find("object")->computed_properties.emplace_back(new_property);
-
-            REQUIRE_UPDATE_SUCCEEDS(*realm, schema1, 0);
-            REQUIRE_THROWS((*realm).update_schema(schema2));
-            REQUIRE((*realm).schema() == schema1);
-            REQUIRE_NOTHROW((*realm).update_schema(schema2, 1,
-                            [](SharedRealm, SharedRealm, Schema&) { /* empty but present migration handler */ }));
-            VERIFY_SCHEMA(*realm, false);
-            REQUIRE((*realm).schema() == schema2);
-        }
-
-        SECTION("change property type") {
-            auto realm = Realm::get_shared_realm(config);
-            Schema schema = {
-                {"object", {
-                    {"value", PropertyType::Int},
-                }},
-            };
-            REQUIRE_MIGRATION_NEEDED(*realm, schema, set_type(schema, "object", "value", PropertyType::Float));
-        }
-
-        SECTION("make property nullable") {
-            auto realm = Realm::get_shared_realm(config);
-
-            Schema schema = {
-                {"object", {
-                    {"value", PropertyType::Int},
-                }},
-            };
-            REQUIRE_MIGRATION_NEEDED(*realm, schema, set_optional(schema, "object", "value", true));
-        }
-
-        SECTION("make property required") {
-            auto realm = Realm::get_shared_realm(config);
-
-            Schema schema = {
-                {"object", {
-                    {"value", PropertyType::Int|PropertyType::Nullable},
-                }},
-            };
-            REQUIRE_MIGRATION_NEEDED(*realm, schema, set_optional(schema, "object", "value", false));
-        }
-
-        SECTION("change link target") {
-            auto realm = Realm::get_shared_realm(config);
-
-            Schema schema = {
-                {"target 1", {
-                    {"value", PropertyType::Int},
-                }},
-                {"target 2", {
-                    {"value", PropertyType::Int},
-                }},
-                {"origin", {
-                    {"value", PropertyType::Object|PropertyType::Nullable, "target 1"},
-                }},
-            };
-            REQUIRE_MIGRATION_NEEDED(*realm, schema, set_target(schema, "origin", "value", "target 2"));
-        }
-
-        SECTION("add pk") {
-            auto realm = Realm::get_shared_realm(config);
-
-            Schema schema = {
-                {"object", {
-                    {"value", PropertyType::Int},
-                }},
-            };
-            REQUIRE_MIGRATION_NEEDED(*realm, schema, set_primary_key(schema, "object", "value"));
-        }
-
-        SECTION("remove pk") {
-            auto realm = Realm::get_shared_realm(config);
-
-            Schema schema = {
-                {"object", {
-                    {"value", PropertyType::Int, Property::IsPrimary{true}},
-                }},
-            };
-            REQUIRE_MIGRATION_NEEDED(*realm, schema, set_primary_key(schema, "object", ""));
-        }
-
-        SECTION("adding column and table in same migration doesn't add duplicate columns") {
-            auto realm = Realm::get_shared_realm(config);
-
-            Schema schema1 = {
-                {"object", {
-                    {"col1", PropertyType::Int},
-                }},
-            };
-            auto schema2 = add_table(add_property(schema1, "object", {"col2", PropertyType::Int}),
-                                     {"object2", {{"value", PropertyType::Int}}});
-            REQUIRE_UPDATE_SUCCEEDS(*realm, schema1, 0);
-            REQUIRE_UPDATE_SUCCEEDS(*realm, schema2, 1);
-
-            auto& table = *get_table(realm, "object2");
-            REQUIRE(table.get_column_count() == 1);
-        }
-    }
-
-    SECTION("migration block invocations") {
-        SECTION("not called for initial creation of schema") {
-            Schema schema = {
-                {"object", {
-                    {"value", PropertyType::Int},
-                }},
-            };
-            auto realm = Realm::get_shared_realm(config);
-            realm->update_schema(schema, 5, [](SharedRealm, SharedRealm, Schema&) { REQUIRE(false); });
-        }
-
-        SECTION("not called when schema version is unchanged even if there are schema changes") {
-            Schema schema1 = {
-                {"object", {
-                    {"value", PropertyType::Int},
-                }},
-            };
-            Schema schema2 = add_table(schema1, {"second object", {
-                {"value", PropertyType::Int},
-            }});
-            auto realm = Realm::get_shared_realm(config);
-            realm->update_schema(schema1, 1);
-            realm->update_schema(schema2, 1, [](SharedRealm, SharedRealm, Schema&) { REQUIRE(false); });
-        }
-
-        SECTION("called when schema version is bumped even if there are no schema changes") {
-            Schema schema = {
-                {"object", {
-                    {"value", PropertyType::Int},
-                }},
-            };
-            auto realm = Realm::get_shared_realm(config);
-            realm->update_schema(schema);
-            bool called = false;
-            realm->update_schema(schema, 5, [&](SharedRealm, SharedRealm, Schema&) { called = true; });
-            REQUIRE(called);
-        }
-    }
-
-    SECTION("migration errors") {
-        SECTION("schema version cannot go down") {
-            auto realm = Realm::get_shared_realm(config);
-            realm->update_schema({}, 1);
-            realm->update_schema({}, 2);
-            REQUIRE_THROWS(realm->update_schema({}, 0));
-        }
-
-        SECTION("insert duplicate keys for existing PK during migration") {
-            Schema schema = {
-                {"object", {
-                    {"value", PropertyType::Int, Property::IsPrimary{true}},
-                }},
-            };
-            auto realm = Realm::get_shared_realm(config);
-            realm->update_schema(schema, 1);
-            REQUIRE_THROWS(realm->update_schema(schema, 2, [](SharedRealm, SharedRealm realm, Schema&) {
-                auto table = ObjectStore::table_for_object_type(realm->read_group(), "object");
-                create_objects(*table, 2);
-            }));
-        }
-
-        SECTION("add pk to existing table with duplicate keys") {
-            Schema schema = {
-                {"object", {
-                    {"value", PropertyType::Int},
-                }},
-            };
-            auto realm = Realm::get_shared_realm(config);
-            realm->update_schema(schema, 1);
-
-            realm->begin_transaction();
-            auto table = ObjectStore::table_for_object_type(realm->read_group(), "object");
-            create_objects(*table, 2);
-            realm->commit_transaction();
-
-            schema = set_primary_key(schema, "object", "value");
-            REQUIRE_THROWS(realm->update_schema(schema, 2, nullptr));
-        }
-
-        SECTION("throwing an exception from migration function rolls back all changes") {
-            Schema schema1 = {
-                {"object", {
-                    {"value", PropertyType::Int},
-                }},
-            };
-            Schema schema2 = add_property(schema1, "object",
-                                          {"value2", PropertyType::Int});
-            auto realm = Realm::get_shared_realm(config);
-            realm->update_schema(schema1, 1);
-
-            REQUIRE_THROWS(realm->update_schema(schema2, 2, [](SharedRealm, SharedRealm realm, Schema&) {
-                auto table = ObjectStore::table_for_object_type(realm->read_group(), "object");
-                table->create_object();
-                throw 5;
-            }));
-
-            auto table = ObjectStore::table_for_object_type(realm->read_group(), "object");
-            REQUIRE(table->size() == 0);
-            REQUIRE(realm->schema_version() == 1);
-            REQUIRE(realm->schema() == schema1);
-        }
-    }
-
-    SECTION("valid migrations") {
-        SECTION("changing all columns does not lose row count") {
-            Schema schema = {
-                {"object", {
-                    {"value", PropertyType::Int},
-                }},
-            };
-            auto realm = Realm::get_shared_realm(config);
-            realm->update_schema(schema, 1);
-
-            realm->begin_transaction();
-            auto table = ObjectStore::table_for_object_type(realm->read_group(), "object");
-            create_objects(*table, 10);
-            realm->commit_transaction();
-
-            schema = set_type(schema, "object", "value", PropertyType::Float);
-            realm->update_schema(schema, 2);
-            REQUIRE(table->size() == 10);
-        }
-
-        SECTION("values for required properties are copied when converitng to nullable") {
-            Schema schema = {
-                {"object", {
-                    {"value", PropertyType::Int},
-                }},
-            };
-            auto realm = Realm::get_shared_realm(config);
-            realm->update_schema(schema, 1);
-
-            realm->begin_transaction();
-            auto table = ObjectStore::table_for_object_type(realm->read_group(), "object");
-            auto key = table->get_column_key("value");
-            create_objects(*table, 10);
-            for (int i = 0; i < 10; ++i)
-                table->get_object(i).set(key, i);
-            realm->commit_transaction();
-
-            realm->update_schema(set_optional(schema, "object", "value", true), 2);
-            key = table->get_column_key("value");
-            for (int i = 0; i < 10; ++i)
-                REQUIRE(table->get_object(i).get<util::Optional<int64_t>>(key) == i);
-        }
-
-        SECTION("values for nullable properties are discarded when converitng to required") {
-            Schema schema = {
-                {"object", {
-                    {"value", PropertyType::Int|PropertyType::Nullable},
-                }},
-            };
-            auto realm = Realm::get_shared_realm(config);
-            realm->update_schema(schema, 1);
-
-            realm->begin_transaction();
-            auto table = ObjectStore::table_for_object_type(realm->read_group(), "object");
-            auto key = table->get_column_key("value");
-            create_objects(*table, 10);
-            for (int i = 0; i < 10; ++i)
-                table->get_object(i).set(key, i);
-            realm->commit_transaction();
-
-            realm->update_schema(set_optional(schema, "object", "value", false), 2);
-            key = table->get_column_key("value");
-            for (size_t i = 0; i < 10; ++i)
-                REQUIRE(table->get_object(i).get<int64_t>(key) == 0);
-        }
-
-        SECTION("deleting table removed from the schema deletes it") {
-            Schema schema = {
-                {"object", {
-                    {"value", PropertyType::Int|PropertyType::Nullable},
-                }},
-            };
-            auto realm = Realm::get_shared_realm(config);
-            realm->update_schema(schema, 1);
-
-            realm->update_schema({}, 2, [](SharedRealm, SharedRealm realm, Schema&) {
-                ObjectStore::delete_data_for_object(realm->read_group(), "object");
-            });
-            REQUIRE_FALSE(ObjectStore::table_for_object_type(realm->read_group(), "object"));
-        }
-
-        SECTION("deleting table still in the schema recreates it with no rows") {
-            Schema schema = {
-                {"object", {
-                    {"value", PropertyType::Int|PropertyType::Nullable},
-                }},
-            };
-            auto realm = Realm::get_shared_realm(config);
-            realm->update_schema(schema, 1);
-
-            realm->begin_transaction();
-            ObjectStore::table_for_object_type(realm->read_group(), "object")->create_object();
-            realm->commit_transaction();
-
-            realm->update_schema(schema, 2, [](SharedRealm, SharedRealm realm, Schema&) {
-                ObjectStore::delete_data_for_object(realm->read_group(), "object");
-            });
-            auto table = ObjectStore::table_for_object_type(realm->read_group(), "object");
-            REQUIRE(table);
-            REQUIRE(table->size() == 0);
-        }
-
-        SECTION("deleting table which doesn't exist does nothing") {
-            Schema schema = {
-                {"object", {
-                    {"value", PropertyType::Int|PropertyType::Nullable},
-                }},
-            };
-            auto realm = Realm::get_shared_realm(config);
-            realm->update_schema(schema, 1);
-
-            REQUIRE_NOTHROW(realm->update_schema({}, 2, [](SharedRealm, SharedRealm realm, Schema&) {
-                ObjectStore::delete_data_for_object(realm->read_group(), "foo");
-            }));
-        }
-    }
-
-    SECTION("schema correctness during migration") {
-        InMemoryTestFile config;
-        config.schema_mode = SchemaMode::Automatic;
-        auto realm = Realm::get_shared_realm(config);
-
-        Schema schema = {
-            {"object", {
-                {"pk", PropertyType::Int, Property::IsPrimary{true}},
-                {"value", PropertyType::Int, Property::IsPrimary{false}, Property::IsIndexed{true}},
-                {"optional", PropertyType::Int|PropertyType::Nullable},
-            }},
-            {"link origin", {
-                {"not a pk", PropertyType::Int},
-                {"object", PropertyType::Object|PropertyType::Nullable, "object"},
-                {"array", PropertyType::Array|PropertyType::Object, "object"},
-            }}
-        };
-        realm->update_schema(schema);
-
-#define VERIFY_SCHEMA_IN_MIGRATION(target_schema) do { \
-    Schema new_schema = (target_schema); \
-    realm->update_schema(new_schema, 1, [&](SharedRealm old_realm, SharedRealm new_realm, Schema&) { \
-        REQUIRE(old_realm->schema_version() == 0); \
-        REQUIRE(old_realm->schema() == schema); \
-        REQUIRE(new_realm->schema_version() == 1); \
-        REQUIRE(new_realm->schema() == new_schema); \
-        VERIFY_SCHEMA(*old_realm, true); \
-        VERIFY_SCHEMA(*new_realm, true); \
-    }); \
-    REQUIRE(realm->schema() == new_schema); \
-    VERIFY_SCHEMA(*realm, false); \
-} while (false)
-
-        SECTION("add new table") {
-            VERIFY_SCHEMA_IN_MIGRATION(add_table(schema, {"new table", {
-                {"value", PropertyType::Int},
-            }}));
-        }
-        SECTION("add property to table") {
-            VERIFY_SCHEMA_IN_MIGRATION(add_property(schema, "object", {"new", PropertyType::Int}));
-        }
-        SECTION("remove property from table") {
-            VERIFY_SCHEMA_IN_MIGRATION(remove_property(schema, "object", "value"));
-        }
-        SECTION("remove multiple properties from table") {
-            VERIFY_SCHEMA_IN_MIGRATION(remove_property(remove_property(schema, "object", "value"), "object", "optional"));
-        }
-        SECTION("add primary key to table") {
-            VERIFY_SCHEMA_IN_MIGRATION(set_primary_key(schema, "link origin", "not a pk"));
-        }
-        SECTION("remove primary key from table") {
-            VERIFY_SCHEMA_IN_MIGRATION(set_primary_key(schema, "object", ""));
-        }
-        SECTION("change primary key") {
-            VERIFY_SCHEMA_IN_MIGRATION(set_primary_key(schema, "object", "value"));
-        }
-        SECTION("change property type") {
-            VERIFY_SCHEMA_IN_MIGRATION(set_type(schema, "object", "value", PropertyType::Date));
-        }
-        SECTION("change link target") {
-            VERIFY_SCHEMA_IN_MIGRATION(set_target(schema, "link origin", "object", "link origin"));
-        }
-        SECTION("change linklist target") {
-            VERIFY_SCHEMA_IN_MIGRATION(set_target(schema, "link origin", "array", "link origin"));
-        }
-        SECTION("make property optional") {
-            VERIFY_SCHEMA_IN_MIGRATION(set_optional(schema, "object", "value", true));
-        }
-        SECTION("make property required") {
-            VERIFY_SCHEMA_IN_MIGRATION(set_optional(schema, "object", "optional", false));
-        }
-        SECTION("add index") {
-            VERIFY_SCHEMA_IN_MIGRATION(set_indexed(schema, "object", "optional", true));
-        }
-        SECTION("remove index") {
-            VERIFY_SCHEMA_IN_MIGRATION(set_indexed(schema, "object", "value", false));
-        }
-        SECTION("reorder properties") {
-            auto schema2 = schema;
-            auto& properties = schema2.find("object")->persisted_properties;
-            std::swap(properties[0], properties[1]);
-            VERIFY_SCHEMA_IN_MIGRATION(schema2);
-        }
-    }
-
-    SECTION("object accessors inside migrations") {
-        using namespace std::string_literals;
-
-        Schema schema{
-            {"all types", {
-                {"pk", PropertyType::Int, Property::IsPrimary{true}},
-                {"bool", PropertyType::Bool},
-                {"int", PropertyType::Int},
-                {"float", PropertyType::Float},
-                {"double", PropertyType::Double},
-                {"string", PropertyType::String},
-                {"data", PropertyType::Data},
-                {"date", PropertyType::Date},
-                {"object", PropertyType::Object|PropertyType::Nullable, "link target"},
-                {"array", PropertyType::Object|PropertyType::Array, "array target"},
-            }},
-            {"link target", {
-                {"value", PropertyType::Int},
-            }, {
-                {"origin", PropertyType::LinkingObjects|PropertyType::Array, "all types", "object"},
-            }},
-            {"array target", {
-                {"value", PropertyType::Int},
-            }},
-            {"int pk", {
-                {"pk", PropertyType::Int, Property::IsPrimary{true}},
-                {"value", PropertyType::Int},
-            }},
-            {"string pk", {
-                {"pk", PropertyType::String, Property::IsPrimary{true}},
-                {"value", PropertyType::Int},
-            }},
-        };
-
-        InMemoryTestFile config;
-        config.schema_mode = SchemaMode::Automatic;
-        config.schema = schema;
-        auto realm = Realm::get_shared_realm(config);
-
-        CppContext ctx(realm);
-        util::Any values = AnyDict{
-            {"pk", INT64_C(1)},
-            {"bool", true},
-            {"int", INT64_C(5)},
-            {"float", 2.2f},
-            {"double", 3.3},
-            {"string", "hello"s},
-            {"data", "olleh"s},
-            {"date", Timestamp(10, 20)},
-            {"object", AnyDict{{"value", INT64_C(10)}}},
-            {"array", AnyVector{AnyDict{{"value", INT64_C(20)}}}},
-        };
-        realm->begin_transaction();
-        Object::create(ctx, realm, *realm->schema().find("all types"), values);
-        realm->commit_transaction();
-
-        SECTION("read values from old realm") {
-            Schema schema{
-                {"all types", {
-                    {"pk", PropertyType::Int, Property::IsPrimary{true}},
-                }},
-            };
-            realm->update_schema(schema, 2, [](auto old_realm, auto new_realm, Schema&) {
-                CppContext ctx(old_realm);
-                Object obj = Object::get_for_primary_key(ctx, old_realm, "all types",
-                                                         util::Any(INT64_C(1)));
-                REQUIRE(obj.is_valid());
-
-                REQUIRE(any_cast<bool>(obj.get_property_value<util::Any>(ctx, "bool")) == true);
-                REQUIRE(any_cast<int64_t>(obj.get_property_value<util::Any>(ctx, "int")) == 5);
-                REQUIRE(any_cast<float>(obj.get_property_value<util::Any>(ctx, "float")) == 2.2f);
-                REQUIRE(any_cast<double>(obj.get_property_value<util::Any>(ctx, "double")) == 3.3);
-                REQUIRE(any_cast<std::string>(obj.get_property_value<util::Any>(ctx, "string")) == "hello");
-                REQUIRE(any_cast<std::string>(obj.get_property_value<util::Any>(ctx, "data")) == "olleh");
-                REQUIRE(any_cast<Timestamp>(obj.get_property_value<util::Any>(ctx, "date")) == Timestamp(10, 20));
-
-                auto link = any_cast<Object>(obj.get_property_value<util::Any>(ctx, "object"));
-                REQUIRE(link.is_valid());
-                REQUIRE(any_cast<int64_t>(link.get_property_value<util::Any>(ctx, "value")) == 10);
-
-                auto list = any_cast<List>(obj.get_property_value<util::Any>(ctx, "array"));
-                REQUIRE(list.size() == 1);
-
-                CppContext list_ctx(ctx, *obj.get_object_schema().property_for_name("array"));
-                link = any_cast<Object>(list.get(list_ctx, 0));
-                REQUIRE(link.is_valid());
-                REQUIRE(any_cast<int64_t>(link.get_property_value<util::Any>(list_ctx, "value")) == 20);
-
-                CppContext ctx2(new_realm);
-                obj = Object::get_for_primary_key(ctx, new_realm, "all types",
-                                                  util::Any(INT64_C(1)));
-                REQUIRE(obj.is_valid());
-                REQUIRE_THROWS(obj.get_property_value<util::Any>(ctx, "bool"));
-            });
-        }
-
-        SECTION("cannot mutate old realm") {
-            realm->update_schema(schema, 2, [](auto old_realm, auto, Schema&) {
-                CppContext ctx(old_realm);
-                Object obj = Object::get_for_primary_key(ctx, old_realm, "all types",
-                                                         util::Any(INT64_C(1)));
-                REQUIRE(obj.is_valid());
-                REQUIRE_THROWS(obj.set_property_value(ctx, "bool", util::Any(false)));
-                REQUIRE_THROWS(old_realm->begin_transaction());
-            });
-        }
-
-        SECTION("cannot read values for removed properties from new realm") {
-            Schema schema{
-                {"all types", {
-                    {"pk", PropertyType::Int, Property::IsPrimary{true}},
-                }},
-            };
-            realm->update_schema(schema, 2, [](auto, auto new_realm, Schema&) {
-                CppContext ctx(new_realm);
-                Object obj = Object::get_for_primary_key(ctx, new_realm, "all types",
-                                                         util::Any(INT64_C(1)));
-                REQUIRE(obj.is_valid());
-                REQUIRE_THROWS(obj.get_property_value<util::Any>(ctx, "bool"));
-                REQUIRE_THROWS(obj.get_property_value<util::Any>(ctx, "object"));
-                REQUIRE_THROWS(obj.get_property_value<util::Any>(ctx, "array"));
-            });
-        }
-
-        SECTION("read values from new object") {
-            realm->update_schema(schema, 2, [](auto, auto new_realm, Schema&) {
-                CppContext ctx(new_realm);
-                Object obj = Object::get_for_primary_key(ctx, new_realm, "all types",
-                                                         util::Any(INT64_C(1)));
-                REQUIRE(obj.is_valid());
-
-
-                auto link = any_cast<Object>(obj.get_property_value<util::Any>(ctx, "object"));
-                REQUIRE(link.is_valid());
-                REQUIRE(any_cast<int64_t>(link.get_property_value<util::Any>(ctx, "value")) == 10);
-
-                auto list = any_cast<List>(obj.get_property_value<util::Any>(ctx, "array"));
-                REQUIRE(list.size() == 1);
-
-                CppContext list_ctx(ctx, *obj.get_object_schema().property_for_name("array"));
-                link = any_cast<Object>(list.get(list_ctx, 0));
-                REQUIRE(link.is_valid());
-                REQUIRE(any_cast<int64_t>(link.get_property_value<util::Any>(list_ctx, "value")) == 20);
-            });
-        }
-
-        SECTION("read and write values in new object") {
-            realm->update_schema(schema, 2, [](auto, auto new_realm, Schema&) {
-                CppContext ctx(new_realm);
-                Object obj = Object::get_for_primary_key(ctx, new_realm, "all types",
-                                                         util::Any(INT64_C(1)));
-                REQUIRE(obj.is_valid());
-
-                REQUIRE(any_cast<bool>(obj.get_property_value<util::Any>(ctx, "bool")) == true);
-                obj.set_property_value(ctx, "bool", util::Any(false));
-                REQUIRE(any_cast<bool>(obj.get_property_value<util::Any>(ctx, "bool")) == false);
-
-                REQUIRE(any_cast<int64_t>(obj.get_property_value<util::Any>(ctx, "int")) == 5);
-                obj.set_property_value(ctx, "int", util::Any(INT64_C(6)));
-                REQUIRE(any_cast<int64_t>(obj.get_property_value<util::Any>(ctx, "int")) == 6);
-
-                REQUIRE(any_cast<float>(obj.get_property_value<util::Any>(ctx, "float")) == 2.2f);
-                obj.set_property_value(ctx, "float", util::Any(1.23f));
-                REQUIRE(any_cast<float>(obj.get_property_value<util::Any>(ctx, "float")) == 1.23f);
-
-                REQUIRE(any_cast<double>(obj.get_property_value<util::Any>(ctx, "double")) == 3.3);
-                obj.set_property_value(ctx, "double", util::Any(1.23));
-                REQUIRE(any_cast<double>(obj.get_property_value<util::Any>(ctx, "double")) == 1.23);
-
-                REQUIRE(any_cast<std::string>(obj.get_property_value<util::Any>(ctx, "string")) == "hello");
-                obj.set_property_value(ctx, "string", util::Any("abc"s));
-                REQUIRE(any_cast<std::string>(obj.get_property_value<util::Any>(ctx, "string")) == "abc");
-
-                REQUIRE(any_cast<std::string>(obj.get_property_value<util::Any>(ctx, "data")) == "olleh");
-                obj.set_property_value(ctx, "data", util::Any("abc"s));
-                REQUIRE(any_cast<std::string>(obj.get_property_value<util::Any>(ctx, "data")) == "abc");
-
-                REQUIRE(any_cast<Timestamp>(obj.get_property_value<util::Any>(ctx, "date")) == Timestamp(10, 20));
-                obj.set_property_value(ctx, "date", util::Any(Timestamp(1, 2)));
-                REQUIRE(any_cast<Timestamp>(obj.get_property_value<util::Any>(ctx, "date")) == Timestamp(1, 2));
-
-                Object linked_obj(new_realm, "link target", 0);
-                Object new_obj(new_realm, get_table(new_realm, "link target")->create_object());
-
-                auto linking = any_cast<Results>(linked_obj.get_property_value<util::Any>(ctx, "origin"));
-                REQUIRE(linking.size() == 1);
-
-                REQUIRE(any_cast<Object>(obj.get_property_value<util::Any>(ctx, "object")).obj().get_key()
-                        == linked_obj.obj().get_key());
-                obj.set_property_value(ctx, "object", util::Any(new_obj));
-                REQUIRE(any_cast<Object>(obj.get_property_value<util::Any>(ctx, "object")).obj().get_key()
-                        == new_obj.obj().get_key());
-
-                REQUIRE(linking.size() == 0);
-            });
-        }
-
-        SECTION("create object in new realm") {
-            realm->update_schema(schema, 2, [&values](auto, auto new_realm, Schema&) {
-                REQUIRE(new_realm->is_in_transaction());
-
-                CppContext ctx(new_realm);
-                any_cast<AnyDict&>(values)["pk"] = INT64_C(2);
-                Object obj = Object::create(ctx, new_realm, "all types", values);
-
-                REQUIRE(get_table(new_realm, "all types")->size() == 2);
-                REQUIRE(get_table(new_realm, "link target")->size() == 2);
-                REQUIRE(get_table(new_realm, "array target")->size() == 2);
-                REQUIRE(any_cast<int64_t>(obj.get_property_value<util::Any>(ctx, "pk")) == 2);
-            });
-        }
-
-        SECTION("upsert in new realm") {
-            realm->update_schema(schema, 2, [&values](auto, auto new_realm, Schema&) {
-                REQUIRE(new_realm->is_in_transaction());
-                CppContext ctx(new_realm);
-                any_cast<AnyDict&>(values)["bool"] = false;
-                Object obj = Object::create(ctx, new_realm, "all types", values, CreatePolicy::UpdateAll);
-                REQUIRE(get_table(new_realm, "all types")->size() == 1);
-                REQUIRE(get_table(new_realm, "link target")->size() == 2);
-                REQUIRE(get_table(new_realm, "array target")->size() == 2);
-                REQUIRE(any_cast<bool>(obj.get_property_value<util::Any>(ctx, "bool")) == false);
-            });
-        }
-
-        SECTION("upsert in new realm after modifying primary key") {
-            realm->update_schema(schema, 2, [&values](auto, auto new_realm, Schema&) {
-                get_table(new_realm, "all types")->set_primary_key_column(ColKey());
-                REQUIRE(new_realm->is_in_transaction());
-                CppContext ctx(new_realm);
-                any_cast<AnyDict&>(values)["bool"] = false;
-                Object obj = Object::create(ctx, new_realm, "all types", values, CreatePolicy::UpdateAll);
-                REQUIRE(get_table(new_realm, "all types")->size() == 1);
-                REQUIRE(get_table(new_realm, "link target")->size() == 2);
-                REQUIRE(get_table(new_realm, "array target")->size() == 2);
-                REQUIRE(any_cast<bool>(obj.get_property_value<util::Any>(ctx, "bool")) == false);
-            });
-        }
-
-        SECTION("change primary key property type") {
-            schema = set_type(schema, "all types", "pk", PropertyType::String);
-            realm->update_schema(schema, 2, [](auto, auto new_realm, auto&) {
-                Object obj(new_realm, "all types", 0);
-
-                CppContext ctx(new_realm);
-                obj.set_property_value(ctx, "pk", util::Any("1"s));
-            });
-        }
-
-        SECTION("set primary key to duplicate values in migration") {
-            auto bad_migration = [&](auto, auto new_realm, Schema&) {
-                // shoud be able to create a new object with the same PK
-                REQUIRE_NOTHROW(Object::create(ctx, new_realm, "all types", values));
-                REQUIRE(get_table(new_realm, "all types")->size() == 2);
-
-                // but it'll fail at the end
-            };
-            REQUIRE_THROWS_AS(realm->update_schema(schema, 2, bad_migration), DuplicatePrimaryKeyValueException);
-            REQUIRE(get_table(realm, "all types")->size() == 1);
-
-            auto good_migration = [&](auto, auto new_realm, Schema&) {
-                REQUIRE_NOTHROW(Object::create(ctx, new_realm, "all types", values));
-
-                // Change the old object's PK to elminate the duplication
-                Object old_obj(new_realm, "all types", 0);
-                CppContext ctx(new_realm);
-                old_obj.set_property_value(ctx, "pk", util::Any(INT64_C(5)));
-            };
-            REQUIRE_NOTHROW(realm->update_schema(schema, 2, good_migration));
-            REQUIRE(get_table(realm, "all types")->size() == 2);
-        }
-
-        SECTION("modify existing int primary key values in migration") {
-            // Create several more objects to increase the chance of things
-            // actually breaking if we're doing invalid things
-            CppContext ctx(realm);
-            auto object_schema = realm->schema().find("all types");
-            realm->begin_transaction();
-            for (int i = 1; i < 10; ++i) {
-                any_cast<AnyDict&>(values)["pk"] = INT64_C(1) + i;
-                any_cast<AnyDict&>(values)["int"] = INT64_C(5) + i;
-                Object::create(ctx, realm, *object_schema, values);
-            }
-            realm->commit_transaction();
-
-            // Increase the PK of each object by one in a migration
-            realm->update_schema(schema, 2, [](auto, auto new_realm, Schema&) {
-                CppContext ctx(new_realm);
-                Results results(new_realm, get_table(new_realm, "all types"));
-                for (size_t i = 0, count = results.size(); i < count; ++i) {
-                    Object obj(new_realm, results.get<Obj>(i));
-                    util::Any v = 1 + any_cast<int64_t>(obj.get_property_value<util::Any>(ctx, "pk"));
-                    obj.set_property_value(ctx, "pk", v);
-                }
-            });
-
-            // Create a new object with the no-longer-used pk of 1
-            realm->begin_transaction();
-            any_cast<AnyDict&>(values)["pk"] = INT64_C(1);
-            any_cast<AnyDict&>(values)["int"] = INT64_C(4);
-            object_schema = realm->schema().find("all types");
-            Object::create(ctx, realm, *object_schema, values);
-            realm->commit_transaction();
-
-            // Verify results
-            auto table = get_table(realm, "all types");
-            REQUIRE(table->size() == 11);
-            REQUIRE(table->get_primary_key_column() == table->get_column_key("pk"));
-            for (int i = 0; i < 10; ++i) {
-                auto obj = table->get_object(i);
-                REQUIRE(obj.get<int64_t>("pk") == i + 2);
-                REQUIRE(obj.get<int64_t>("int") == i + 5);
-            }
-            auto obj = table->get_object(10);
-            REQUIRE(obj.get<int64_t>("pk") == 1);
-            REQUIRE(obj.get<int64_t>("int") == 4);
-        }
-
-        SECTION("modify existing string primary key values in migration") {
-            // Create several objects to increase the chance of things
-            // actually breaking if we're doing invalid things
-            CppContext ctx(realm);
-            auto object_schema = realm->schema().find("string pk");
-            realm->begin_transaction();
-            for (int64_t i = 0; i < 10; ++i) {
-                util::Any values = AnyDict{
-                    {"pk", util::to_string(i)},
-                    {"value", i + 1},
-                };
-                Object::create(ctx, realm, *object_schema, values);
-            }
-            realm->commit_transaction();
-
-            // Increase the PK of each object by one in a migration
-            realm->update_schema(schema, 2, [](auto, auto new_realm, Schema&) {
-                CppContext ctx(new_realm);
-                Results results(new_realm, get_table(new_realm, "string pk"));
-                for (size_t i = 0, count = results.size(); i < count; ++i) {
-                    Object obj(new_realm, results.get<Obj>(i));
-                    util::Any v = util::to_string(any_cast<int64_t>(obj.get_property_value<util::Any>(ctx, "value")));
-                    obj.set_property_value(ctx, "pk", v);
-                }
-            });
-
-            // Create a new object with the no-longer-used pk of 0
-            realm->begin_transaction();
-            util::Any values = AnyDict{
-                {"pk", "0"s},
-                {"value", INT64_C(0)},
-            };
-            object_schema = realm->schema().find("string pk");
-            Object::create(ctx, realm, *object_schema, values);
-            realm->commit_transaction();
-
-            // Verify results
-            auto table = get_table(realm, "string pk");
-            REQUIRE(table->size() == 11);
-            REQUIRE(table->get_primary_key_column() == table->get_column_key("pk"));
-            for (auto& obj : *table) {
-                REQUIRE(util::to_string(obj.get<int64_t>("value")).c_str() == obj.get<StringData>("pk"));
-            }
-        }
-
-        SECTION("create and modify int primary key inside migration") {
-            SECTION("with index") {
-                realm->begin_transaction();
-                auto table = get_table(realm, "int pk");
-                table->add_search_index(table->get_column_key("pk"));
-                realm->commit_transaction();
-            }
-            SECTION("no index") {
-            }
-
-            realm->update_schema(schema, 2, [](auto, auto new_realm, Schema&) {
-                CppContext ctx(new_realm);
-                for (int64_t i = 0; i < 10; ++i) {
-                    auto obj = Object::create(ctx, new_realm, *new_realm->schema().find("int pk"),
-                                              util::Any(AnyDict{
-                        {"pk", INT64_C(0)},
-                        {"value", i}
-                    }));
-                    obj.set_property_value(ctx, "pk", util::Any(i));
-                }
-            });
-
-            auto table = get_table(realm, "int pk");
-            REQUIRE(table->size() == 10);
-            REQUIRE(table->get_primary_key_column() == table->get_column_key("pk"));
-            for (int i = 0; i < 10; ++i) {
-                auto obj = table->get_object(i);
-                REQUIRE(obj.get<int64_t>("pk") == i);
-                REQUIRE(obj.get<int64_t>("value") == i);
-            }
-        }
-
-        SECTION("create and modify string primary key inside migration") {
-            SECTION("with index") {
-                realm->begin_transaction();
-                auto table = get_table(realm, "string pk");
-                table->add_search_index(table->get_column_key("pk"));
-                realm->commit_transaction();
-            }
-            SECTION("no index") {
-            }
-
-            realm->update_schema(schema, 2, [](auto, auto new_realm, Schema&) {
-                CppContext ctx(new_realm);
-                for (int64_t i = 0; i < 10; ++i) {
-                    auto obj = Object::create(ctx, new_realm, *new_realm->schema().find("string pk"),
-                                              util::Any(AnyDict{
-                        {"pk", ""s},
-                        {"value", i}
-                    }));
-                    obj.set_property_value(ctx, "pk", util::Any(util::to_string(i)));
-                }
-            });
-
-            auto table = get_table(realm, "string pk");
-            REQUIRE(table->size() == 10);
-            REQUIRE(table->get_primary_key_column() == table->get_column_key("pk"));
-            for (auto& obj : *table)
-                REQUIRE(obj.get<StringData>("pk") == util::to_string(obj.get<int64_t>("value")).c_str());
-        }
-
-        SECTION("create object after adding primary key") {
-            schema = set_primary_key(schema, "all types", "");
-            realm->update_schema(schema, 2);
-            schema = set_primary_key(schema, "all types", "pk");
-            REQUIRE_NOTHROW(realm->update_schema(schema, 3, [&](auto, auto new_realm, Schema&) {
-                CppContext ctx(new_realm);
-                any_cast<AnyDict&>(values)["pk"] = INT64_C(2);
-                Object::create(ctx, realm, "all types", values);
-            }));
-        }
-    }
-
-    SECTION("property renaming") {
-        InMemoryTestFile config;
-        config.schema_mode = SchemaMode::Automatic;
-        auto realm = Realm::get_shared_realm(config);
-
-        struct Rename {
-            StringData object_type;
-            StringData old_name;
-            StringData new_name;
-        };
-
-        auto apply_renames = [&](std::initializer_list<Rename> renames) -> Realm::MigrationFunction {
-            return [=](SharedRealm, SharedRealm realm, Schema& schema) {
-                for (auto rename : renames) {
-                    ObjectStore::rename_property(realm->read_group(), schema,
-                                                 rename.object_type, rename.old_name, rename.new_name);
-                }
-            };
-        };
-
-#define FAILED_RENAME(old_schema, new_schema, error, ...) do { \
-    realm->update_schema(old_schema, 1); \
-    REQUIRE_THROWS_WITH(realm->update_schema(new_schema, 2, apply_renames({__VA_ARGS__})), error); \
-} while (false)
-
-        Schema schema = {
-            {"object", {
-                {"value", PropertyType::Int},
-            }},
-        };
-
-        SECTION("table does not exist in old schema") {
-            auto schema2 = add_table(schema, {"object 2", {
-                {"value 2", PropertyType::Int},
-            }});
-            FAILED_RENAME(schema, schema2,
-                          "Cannot rename property 'object 2.value' because it does not exist.",
-                          {"object 2", "value", "value 2"});
-        }
-
-        SECTION("table does not exist in new schema") {
-            FAILED_RENAME(schema, {},
-                          "Cannot rename properties for type 'object' because it has been removed from the Realm.",
-                          {"object", "value", "value 2"});
-        }
-
-        SECTION("property does not exist in old schema") {
-            auto schema2 = add_property(schema, "object", {"new", PropertyType::Int});
-            FAILED_RENAME(schema, schema2,
-                          "Cannot rename property 'object.nonexistent' because it does not exist.",
-                          {"object", "nonexistent", "new"});
-        }
-
-        auto rename_value = [](Schema schema) {
-            schema.find("object")->property_for_name("value")->name = "new";
-            return schema;
-        };
-
-        SECTION("property does not exist in new schema") {
-            FAILED_RENAME(schema, rename_value(schema),
-                          "Renamed property 'object.nonexistent' does not exist.",
-                          {"object", "value", "nonexistent"});
-        }
-
-        SECTION("source propety still exists in the new schema") {
-            auto schema2 = add_property(schema, "object",
-                                        {"new", PropertyType::Int});
-            FAILED_RENAME(schema, schema2,
-                          "Cannot rename property 'object.value' to 'new' because the source property still exists.",
-                          {"object", "value", "new"});
-        }
-
-        SECTION("different type") {
-            auto schema2 = rename_value(set_type(schema, "object", "value", PropertyType::Date));
-            FAILED_RENAME(schema, schema2,
-                          "Cannot rename property 'object.value' to 'new' because it would change from type 'int' to 'date'.",
-                          {"object", "value", "new"});
-        }
-
-        SECTION("different link targets") {
-            Schema schema = {
-                {"target", {
-                    {"value", PropertyType::Int},
-                }},
-                {"origin", {
-                    {"link", PropertyType::Object|PropertyType::Nullable, "target"},
-                }},
-            };
-            auto schema2 = set_target(schema, "origin", "link", "origin");
-            schema2.find("origin")->property_for_name("link")->name = "new";
-            FAILED_RENAME(schema, schema2,
-                          "Cannot rename property 'origin.link' to 'new' because it would change from type '<target>' to '<origin>'.",
-                          {"origin", "link", "new"});
-        }
-
-        SECTION("different linklist targets") {
-            Schema schema = {
-                {"target", {
-                    {"value", PropertyType::Int},
-                }},
-                {"origin", {
-                    {"link", PropertyType::Array|PropertyType::Object, "target"},
-                }},
-            };
-            auto schema2 = set_target(schema, "origin", "link", "origin");
-            schema2.find("origin")->property_for_name("link")->name = "new";
-            FAILED_RENAME(schema, schema2,
-                          "Cannot rename property 'origin.link' to 'new' because it would change from type 'array<target>' to 'array<origin>'.",
-                          {"origin", "link", "new"});
-        }
-
-        SECTION("make required") {
-            schema = set_optional(schema, "object", "value", true);
-            auto schema2 = rename_value(set_optional(schema, "object", "value", false));
-            FAILED_RENAME(schema, schema2,
-                          "Cannot rename property 'object.value' to 'new' because it would change from optional to required.",
-                          {"object", "value", "new"});
-        }
-
-        auto init = [&](Schema const& old_schema) {
-            realm->update_schema(old_schema, 1);
-            realm->begin_transaction();
-            auto table = ObjectStore::table_for_object_type(realm->read_group(), "object");
-            table->create_object().set_all(10);
-            realm->commit_transaction();
-        };
-
-#define SUCCESSFUL_RENAME(old_schema, new_schema, ...) do { \
-    init(old_schema); \
-    REQUIRE_NOTHROW(realm->update_schema(new_schema, 2, apply_renames({__VA_ARGS__}))); \
-    REQUIRE(realm->schema() == new_schema); \
-    VERIFY_SCHEMA(*realm, false); \
-    auto table = ObjectStore::table_for_object_type(realm->read_group(), "object"); \
-    auto key = table->get_column_keys()[0]; \
-    if (table->get_column_attr(key).test(col_attr_Nullable)) \
-        REQUIRE(table->begin()->get<util::Optional<int64_t>>(key) == 10); \
-    else \
-        REQUIRE(table->begin()->get<int64_t>(key) == 10); \
-} while (false)
-
-        SECTION("basic valid rename") {
-            auto schema2 = rename_value(schema);
-            SUCCESSFUL_RENAME(schema, schema2,
-                              {"object", "value", "new"});
-        }
-
-        SECTION("chained rename") {
-            auto schema2 = rename_value(schema);
-            SUCCESSFUL_RENAME(schema, schema2,
-                              {"object", "value", "a"},
-                              {"object", "a", "b"},
-                              {"object", "b", "new"});
-        }
-
-        SECTION("old is pk, new is not") {
-            auto schema2 = rename_value(schema);
-            schema = set_primary_key(schema, "object", "value");
-            SUCCESSFUL_RENAME(schema, schema2, {"object", "value", "new"});
-        }
-
-        SECTION("new is pk, old is not") {
-            auto schema2 = set_primary_key(rename_value(schema), "object", "new");
-            SUCCESSFUL_RENAME(schema, schema2, {"object", "value", "new"});
-        }
-
-        SECTION("both are pk") {
-            schema = set_primary_key(schema, "object", "value");
-            auto schema2 = set_primary_key(rename_value(schema), "object", "new");
-            SUCCESSFUL_RENAME(schema, schema2, {"object", "value", "new"});
-        }
-
-        SECTION("make optional") {
-            auto schema2 = rename_value(set_optional(schema, "object", "value", true));
-            SUCCESSFUL_RENAME(schema, schema2,
-                              {"object", "value", "new"});
-        }
-
-        SECTION("add index") {
-            auto schema2 = rename_value(set_indexed(schema, "object", "value", true));
-            SUCCESSFUL_RENAME(schema, schema2, {"object", "value", "new"});
-        }
-
-        SECTION("remove index") {
-            auto schema2 = rename_value(schema);
-            schema = set_indexed(schema, "object", "value", true);
-            SUCCESSFUL_RENAME(schema, schema2, {"object", "value", "new"});
-        }
-
-        SECTION("create object inside migration after renaming pk") {
-            schema = set_primary_key(schema, "object", "value");
-            auto new_schema = set_primary_key(rename_value(schema), "object", "new");
-            init(schema);
-            REQUIRE_NOTHROW(realm->update_schema(new_schema, 2, [](auto, auto realm, Schema& schema) {
-                ObjectStore::rename_property(realm->read_group(), schema,
-                                             "object", "value", "new");
-
-                CppContext ctx(realm);
-                util::Any values = AnyDict{{"new", INT64_C(11)}};
-                Object::create(ctx, realm, "object", values);
-            }));
-            REQUIRE(realm->schema() == new_schema);
-            VERIFY_SCHEMA(*realm, false);
-            auto table = ObjectStore::table_for_object_type(realm->read_group(), "object");
-            auto key = table->get_column_keys()[0];
-            auto it = table->begin();
-            REQUIRE(it->get<int64_t>(key) == 10);
-            REQUIRE((++it)->get<int64_t>(key) == 11);
-        }
-    }
-}
-
-TEST_CASE("migration: Immutable") {
-    TestFile config;
-
-    auto realm_with_schema = [&](Schema schema) {
-        {
-            auto realm = Realm::get_shared_realm(config);
-            realm->update_schema(std::move(schema));
-        }
-        config.schema_mode = SchemaMode::Immutable;
-        return Realm::get_shared_realm(config);
-    };
-
-    SECTION("allowed schema mismatches") {
-        SECTION("index") {
-            auto realm = realm_with_schema({
-                {"object", {
-                    {"indexed", PropertyType::Int, Property::IsPrimary{false}, Property::IsIndexed{true}},
-                    {"unindexed", PropertyType::Int},
-                }},
-            });
-            Schema schema = {
-                {"object", {
-                    {"indexed", PropertyType::Int},
-                    {"unindexed", PropertyType::Int, Property::IsPrimary{false}, Property::IsIndexed{true}},
-                }},
-            };
-            REQUIRE_NOTHROW(realm->update_schema(schema));
-            REQUIRE(realm->schema() == schema);
-        }
-
-        SECTION("extra tables") {
-            auto realm = realm_with_schema({
-                {"object", {
-                    {"value", PropertyType::Int},
-                }},
-                {"object 2", {
-                    {"value", PropertyType::Int},
-                }},
-            });
-            Schema schema = {
-                {"object", {
-                    {"value", PropertyType::Int},
-                }},
-            };
-            REQUIRE_NOTHROW(realm->update_schema(schema));
-        }
-
-        SECTION("missing tables") {
-            auto realm = realm_with_schema({
-                {"object", {
-                    {"value", PropertyType::Int},
-                }},
-            });
-            Schema schema = {
-                {"object", {
-                    {"value", PropertyType::Int},
-                }},
-                {"second object", {
-                    {"value", PropertyType::Int},
-                }},
-            };
-            REQUIRE_NOTHROW(realm->update_schema(schema));
-            REQUIRE(realm->schema() == schema);
-
-            auto object_schema = realm->schema().find("object");
-            REQUIRE(object_schema->persisted_properties.size() == 1);
-            REQUIRE(object_schema->persisted_properties[0].column_key);
-
-            object_schema = realm->schema().find("second object");
-            REQUIRE(object_schema->persisted_properties.size() == 1);
-            REQUIRE(!object_schema->persisted_properties[0].column_key);
-        }
-
-        SECTION("extra columns in table") {
-            auto realm = realm_with_schema({
-                {"object", {
-                    {"value", PropertyType::Int},
-                    {"value 2", PropertyType::Int},
-                }},
-            });
-            Schema schema = {
-                {"object", {
-                    {"value", PropertyType::Int},
-                }},
-            };
-            REQUIRE_NOTHROW(realm->update_schema(schema));
-        }
-    }
-
-    SECTION("disallowed mismatches") {
-        SECTION("missing columns in table") {
-            auto realm = realm_with_schema({
-                {"object", {
-                    {"value", PropertyType::Int},
-                }},
-            });
-            Schema schema = {
-                {"object", {
-                    {"value", PropertyType::Int},
-                    {"value 2", PropertyType::Int},
-                }},
-            };
-            REQUIRE_THROWS(realm->update_schema(schema));
-        }
-
-        SECTION("bump schema version") {
-            Schema schema = {
-                {"object", {
-                    {"value", PropertyType::Int},
-                }},
-            };
-            auto realm = realm_with_schema(schema);
-            REQUIRE_THROWS(realm->update_schema(schema, 1));
-        }
-    }
-}
-
-TEST_CASE("migration: ReadOnly") {
-    TestFile config;
-
-    auto realm_with_schema = [&](Schema schema) {
-        {
-            auto realm = Realm::get_shared_realm(config);
-            realm->update_schema(std::move(schema));
-        }
-        config.schema_mode = SchemaMode::ReadOnlyAlternative;
-        return Realm::get_shared_realm(config);
-    };
-
-    SECTION("allowed schema mismatches") {
-        SECTION("index") {
-            auto realm = realm_with_schema({
-                {"object", {
-                    {"indexed", PropertyType::Int, Property::IsPrimary{false}, Property::IsIndexed{true}},
-                    {"unindexed", PropertyType::Int},
-                }},
-            });
-            Schema schema = {
-                {"object", {
-                    {"indexed", PropertyType::Int},
-                    {"unindexed", PropertyType::Int, Property::IsPrimary{false}, Property::IsIndexed{true}},
-                }},
-            };
-            REQUIRE_NOTHROW(realm->update_schema(schema));
-            REQUIRE(realm->schema() == schema);
-        }
-
-        SECTION("extra tables") {
-            auto realm = realm_with_schema({
-                {"object", {
-                    {"value", PropertyType::Int},
-                }},
-                {"object 2", {
-                    {"value", PropertyType::Int},
-                }},
-            });
-            Schema schema = {
-                {"object", {
-                    {"value", PropertyType::Int},
-                }},
-            };
-            REQUIRE_NOTHROW(realm->update_schema(schema));
-        }
-
-        SECTION("extra columns in table") {
-            auto realm = realm_with_schema({
-                {"object", {
-                    {"value", PropertyType::Int},
-                    {"value 2", PropertyType::Int},
-                }},
-            });
-            Schema schema = {
-                {"object", {
-                    {"value", PropertyType::Int},
-                }},
-            };
-            REQUIRE_NOTHROW(realm->update_schema(schema));
-        }
-
-        SECTION("missing tables") {
-            auto realm = realm_with_schema({
-                {"object", {
-                    {"value", PropertyType::Int},
-                }},
-            });
-            Schema schema = {
-                {"object", {
-                    {"value", PropertyType::Int},
-                }},
-                {"second object", {
-                    {"value", PropertyType::Int},
-                }},
-            };
-            REQUIRE_NOTHROW(realm->update_schema(schema));
-        }
-
-        SECTION("bump schema version") {
-            Schema schema = {
-                {"object", {
-                    {"value", PropertyType::Int},
-                }},
-            };
-            auto realm = realm_with_schema(schema);
-            REQUIRE_NOTHROW(realm->update_schema(schema, 1));
-        }
-    }
-
-    SECTION("disallowed mismatches") {
-
-        SECTION("missing columns in table") {
-            auto realm = realm_with_schema({
-                {"object", {
-                    {"value", PropertyType::Int},
-                }},
-            });
-            Schema schema = {
-                {"object", {
-                    {"value", PropertyType::Int},
-                    {"value 2", PropertyType::Int},
-                }},
-            };
-            REQUIRE_THROWS(realm->update_schema(schema));
-        }
-    }
-}
-
-TEST_CASE("migration: ResetFile") {
-    TestFile config;
-    config.schema_mode = SchemaMode::ResetFile;
-
-    Schema schema = {
-        {"object", {
-            {"value", PropertyType::Int},
-        }},
-        {"object 2", {
-            {"value", PropertyType::Int},
-        }},
-    };
-
-// To verify that the file has actually be deleted and recreated, on
-// non-Windows we need to hold an open file handle to the old file to force
-// using a new inode, but on Windows we *can't*
-#ifdef _WIN32
-    auto get_fileid = [&] {
-        // this is wrong for non-ascii but it's what core does
-        std::wstring ws(config.path.begin(), config.path.end());
-        HANDLE handle = CreateFile2(ws.c_str(), GENERIC_READ,
-                                    FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING,
-                                    nullptr);
-        REQUIRE(handle != INVALID_HANDLE_VALUE);
-        auto close = util::make_scope_exit([=]() noexcept { CloseHandle(handle); });
-
-        BY_HANDLE_FILE_INFORMATION info{};
-        REQUIRE(GetFileInformationByHandle(handle, &info));
-        return (DWORDLONG)info.nFileIndexHigh + (DWORDLONG)info.nFileIndexLow;
-    };
-#else
-    auto get_fileid = [&] {
-        util::File::UniqueID id;
-        util::File::get_unique_id(config.path, id);
-        return id.inode;
-    };
-    File holder(config.path, File::mode_Write);
-#endif
-
-    {
-        auto realm = Realm::get_shared_realm(config);
-        auto ino = get_fileid();
-        realm->update_schema(schema);
-        REQUIRE(ino == get_fileid());
-        realm->begin_transaction();
-        ObjectStore::table_for_object_type(realm->read_group(), "object")->create_object();
-        realm->commit_transaction();
-    }
-    auto realm = Realm::get_shared_realm(config);
-    auto ino = get_fileid();
-
-    SECTION("file is reset when schema version increases") {
-        realm->update_schema(schema, 1);
-        REQUIRE(ObjectStore::table_for_object_type(realm->read_group(), "object")->size() == 0);
-        REQUIRE(ino != get_fileid());
-    }
-
-    SECTION("file is reset when an existing table is modified") {
-        realm->update_schema(add_property(schema, "object",
-                                          {"value 2", PropertyType::Int}));
-        REQUIRE(ObjectStore::table_for_object_type(realm->read_group(), "object")->size() == 0);
-        REQUIRE(ino != get_fileid());
-    }
-
-    SECTION("file is not reset when adding a new table") {
-        realm->update_schema(add_table(schema, {"object 3", {
-            {"value", PropertyType::Int},
-        }}));
-        REQUIRE(ObjectStore::table_for_object_type(realm->read_group(), "object")->size() == 1);
-        REQUIRE(realm->schema().size() == 3);
-        REQUIRE(ino == get_fileid());
-    }
-
-    SECTION("file is not reset when removing a table") {
-        realm->update_schema(remove_table(schema, "object 2"));
-        REQUIRE(ObjectStore::table_for_object_type(realm->read_group(), "object")->size() == 1);
-        REQUIRE(ObjectStore::table_for_object_type(realm->read_group(), "object 2"));
-        REQUIRE(realm->schema().size() == 1);
-        REQUIRE(ino == get_fileid());
-    }
-
-    SECTION("file is not reset when adding an index") {
-        realm->update_schema(set_indexed(schema, "object", "value", true));
-        REQUIRE(ObjectStore::table_for_object_type(realm->read_group(), "object")->size() == 1);
-        REQUIRE(ino == get_fileid());
-    }
-
-    SECTION("file is not reset when removing an index") {
-        realm->update_schema(set_indexed(schema, "object", "value", true));
-        realm->update_schema(schema);
-        REQUIRE(ObjectStore::table_for_object_type(realm->read_group(), "object")->size() == 1);
-        REQUIRE(ino == get_fileid());
-    }
-}
-
-TEST_CASE("migration: Additive") {
-    Schema schema = {
-        {"object", {
-            {"value", PropertyType::Int, Property::IsPrimary{false}, Property::IsIndexed{true}},
-            {"value 2", PropertyType::Int|PropertyType::Nullable},
-        }},
-    };
-
-    TestFile config;
-    config.schema_mode = SchemaMode::Additive;
-    config.schema = schema;
-    auto realm = Realm::get_shared_realm(config);
-    realm->update_schema(schema);
-
-    SECTION("can add new properties to existing tables") {
-        REQUIRE_NOTHROW(realm->update_schema(add_property(schema, "object",
-                                                          {"value 3", PropertyType::Int})));
-        REQUIRE(ObjectStore::table_for_object_type(realm->read_group(), "object")->get_column_count() == 3);
-    }
-
-    SECTION("can add new tables") {
-        REQUIRE_NOTHROW(realm->update_schema(add_table(schema, {"object 2", {
-            {"value", PropertyType::Int},
-        }})));
-        REQUIRE(ObjectStore::table_for_object_type(realm->read_group(), "object"));
-        REQUIRE(ObjectStore::table_for_object_type(realm->read_group(), "object 2"));
-    }
-
-    SECTION("indexes are updated when schema version is bumped") {
-        auto table = ObjectStore::table_for_object_type(realm->read_group(), "object");
-        auto col_keys = table->get_column_keys();
-        REQUIRE(table->has_search_index(col_keys[0]));
-        REQUIRE(!table->has_search_index(col_keys[1]));
-
-        REQUIRE_NOTHROW(realm->update_schema(set_indexed(schema, "object", "value", false), 1));
-        REQUIRE(!table->has_search_index(col_keys[0]));
-
-        REQUIRE_NOTHROW(realm->update_schema(set_indexed(schema, "object", "value 2", true), 2));
-        REQUIRE(table->has_search_index(col_keys[1]));
-    }
-
-    SECTION("indexes are not updated when schema version is not bumped") {
-        auto table = ObjectStore::table_for_object_type(realm->read_group(), "object");
-        auto col_keys = table->get_column_keys();
-        REQUIRE(table->has_search_index(col_keys[0]));
-        REQUIRE(!table->has_search_index(col_keys[1]));
-
-        REQUIRE_NOTHROW(realm->update_schema(set_indexed(schema, "object", "value", false)));
-        REQUIRE(table->has_search_index(col_keys[0]));
-
-        REQUIRE_NOTHROW(realm->update_schema(set_indexed(schema, "object", "value 2", true)));
-        REQUIRE(!table->has_search_index(col_keys[1]));
-    }
-
-    SECTION("can remove properties from existing tables, but column is not removed") {
-        auto table = ObjectStore::table_for_object_type(realm->read_group(), "object");
-        REQUIRE_NOTHROW(realm->update_schema(remove_property(schema, "object", "value")));
-        REQUIRE(ObjectStore::table_for_object_type(realm->read_group(), "object")->get_column_count() == 2);
-        auto const& properties = realm->schema().find("object")->persisted_properties;
-        REQUIRE(properties.size() == 1);
-        auto col_keys = table->get_column_keys();
-        REQUIRE(col_keys.size() == 2);
-        REQUIRE(properties[0].column_key == col_keys[1]);
-    }
-
-    SECTION("cannot change existing property types") {
-        REQUIRE_THROWS(realm->update_schema(set_type(schema, "object", "value", PropertyType::Float)));
-    }
-
-    SECTION("cannot change existing property nullability") {
-        REQUIRE_THROWS(realm->update_schema(set_optional(schema, "object", "value", true)));
-        REQUIRE_THROWS(realm->update_schema(set_optional(schema, "object", "value 2", false)));
-    }
-
-    SECTION("cannot change existing link targets") {
-        REQUIRE_NOTHROW(realm->update_schema(add_table(schema, {"object 2", {
-            {"link", PropertyType::Object|PropertyType::Nullable, "object"},
-        }})));
-        REQUIRE_THROWS(realm->update_schema(set_target(realm->schema(), "object 2", "link", "object 2")));
-    }
-
-    SECTION("cannot change primary keys") {
-        REQUIRE_THROWS(realm->update_schema(set_primary_key(schema, "object", "value")));
-
-        REQUIRE_NOTHROW(realm->update_schema(add_table(schema, {"object 2", {
-            {"pk", PropertyType::Int, Property::IsPrimary{true}},
-        }})));
-
-        REQUIRE_THROWS(realm->update_schema(set_primary_key(realm->schema(), "object 2", "")));
-    }
-
-    SECTION("schema version is allowed to go down") {
-        REQUIRE_NOTHROW(realm->update_schema(schema, 1));
-        REQUIRE(realm->schema_version() == 1);
-        REQUIRE_NOTHROW(realm->update_schema(schema, 0));
-        REQUIRE(realm->schema_version() == 1);
-    }
-
-    SECTION("migration function is not used") {
-        REQUIRE_NOTHROW(realm->update_schema(schema, 1,
-                                             [&](SharedRealm, SharedRealm, Schema&) { REQUIRE(false); }));
-    }
-
-    SECTION("add new columns from different SG") {
-        auto realm2 = Realm::get_shared_realm(config);
-        auto& group = realm2->read_group();
-        realm2->begin_transaction();
-        auto table = ObjectStore::table_for_object_type(group, "object");
-        auto col_keys = table->get_column_keys();
-        table->add_column(type_Int, "new column");
-        realm2->commit_transaction();
-
-        REQUIRE_NOTHROW(realm->refresh());
-        REQUIRE(realm->schema() == schema);
-        REQUIRE(realm->schema().find("object")->persisted_properties[0].column_key == col_keys[0]);
-        REQUIRE(realm->schema().find("object")->persisted_properties[1].column_key == col_keys[1]);
-    }
-
-    SECTION("opening new Realms uses the correct schema after an external change") {
-        auto realm2 = Realm::get_shared_realm(config);
-        auto& group = realm2->read_group();
-        realm2->begin_transaction();
-        auto table = ObjectStore::table_for_object_type(group, "object");
-        auto col_keys = table->get_column_keys();
-        table->add_column(type_Double, "newcol");
-        realm2->commit_transaction();
-
-        REQUIRE_NOTHROW(realm->refresh());
-        REQUIRE(realm->schema() == schema);
-        REQUIRE(realm->schema().find("object")->persisted_properties[0].column_key == col_keys[0]);
-        REQUIRE(realm->schema().find("object")->persisted_properties[1].column_key == col_keys[1]);
-
-        // Gets the schema from the RealmCoordinator
-        auto realm3 = Realm::get_shared_realm(config);
-        REQUIRE(realm->schema().find("object")->persisted_properties[0].column_key == col_keys[0]);
-        REQUIRE(realm->schema().find("object")->persisted_properties[1].column_key == col_keys[1]);
-
-        // Close and re-open the file entirely so that the coordinator is recreated
-        realm.reset();
-        realm2.reset();
-        realm3.reset();
-
-        realm = Realm::get_shared_realm(config);
-        REQUIRE(realm->schema() == schema);
-        REQUIRE(realm->schema().find("object")->persisted_properties[0].column_key == col_keys[0]);
-        REQUIRE(realm->schema().find("object")->persisted_properties[1].column_key == col_keys[1]);
-    }
-
-    SECTION("can have different subsets of columns in different Realm instances") {
-        auto config2 = config;
-        config2.schema = add_property(schema, "object",
-                                      {"value 3", PropertyType::Int});
-        auto config3 = config;
-        config3.schema = remove_property(schema, "object", "value 2");
-
-        auto config4 = config;
-        config4.schema = util::none;
-
-        auto realm2 = Realm::get_shared_realm(config2);
-        auto realm3 = Realm::get_shared_realm(config3);
-        REQUIRE(realm->schema().find("object")->persisted_properties.size() == 2);
-        REQUIRE(realm2->schema().find("object")->persisted_properties.size() == 3);
-        REQUIRE(realm3->schema().find("object")->persisted_properties.size() == 1);
-
-        realm->refresh();
-        realm2->refresh();
-        REQUIRE(realm->schema().find("object")->persisted_properties.size() == 2);
-        REQUIRE(realm2->schema().find("object")->persisted_properties.size() == 3);
-
-        // No schema specified; should see all of them
-        auto realm4 = Realm::get_shared_realm(config4);
-        REQUIRE(realm4->schema().find("object")->persisted_properties.size() == 3);
-    }
-
-    SECTION("updating a schema to include already-present column") {
-        auto config2 = config;
-        config2.schema = add_property(schema, "object",
-                                      {"value 3", PropertyType::Int});
-        auto realm2 = Realm::get_shared_realm(config2);
-        auto& properties2 = realm2->schema().find("object")->persisted_properties;
-
-        REQUIRE_NOTHROW(realm->update_schema(*config2.schema));
-        REQUIRE(realm->schema().find("object")->persisted_properties.size() == 3);
-        auto& properties = realm->schema().find("object")->persisted_properties;
-        REQUIRE(properties[0].column_key == properties2[0].column_key);
-        REQUIRE(properties[1].column_key == properties2[1].column_key);
-        REQUIRE(properties[2].column_key == properties2[2].column_key);
-    }
-
-    SECTION("increasing schema version without modifying schema properly leaves the schema untouched") {
-        TestFile config1;
-        config1.schema = schema;
-        config1.schema_mode = SchemaMode::Additive;
-        config1.schema_version = 0;
-
-        auto realm1 = Realm::get_shared_realm(config1);
-        REQUIRE(realm1->schema().size() == 1);
-        Schema schema1 = realm1->schema();
-        realm1->close();
-
-        auto config2 = config1;
-        config2.schema_version = 1;
-        auto realm2 = Realm::get_shared_realm(config2);
-        REQUIRE(realm2->schema() == schema1);
-    }
-
-    SECTION("invalid schema update leaves the schema untouched") {
-        auto config2 = config;
-        config2.schema = add_property(schema, "object", {"value 3", PropertyType::Int});
-        auto realm2 = Realm::get_shared_realm(config2);
-
-        REQUIRE_THROWS(realm->update_schema(add_property(schema, "object", {"value 3", PropertyType::Float})));
-        REQUIRE(realm->schema().find("object")->persisted_properties.size() == 2);
-    }
-
-    SECTION("update_schema() does not begin a write transaction when extra columns are present") {
-        realm->begin_transaction();
-
-        auto realm2 = Realm::get_shared_realm(config);
-        // will deadlock if it tries to start a write transaction
-        realm2->update_schema(remove_property(schema, "object", "value"));
-    }
-
-    SECTION("update_schema() does not begin a write transaction when indexes are changed without bumping schema version") {
-        realm->begin_transaction();
-
-        auto realm2 = Realm::get_shared_realm(config);
-        // will deadlock if it tries to start a write transaction
-        realm->update_schema(set_indexed(schema, "object", "value 2", true));
-    }
-
-    SECTION("update_schema() does not begin a write transaction for invalid schema changes") {
-        realm->begin_transaction();
-
-        auto realm2 = Realm::get_shared_realm(config);
-        auto new_schema = add_property(remove_property(schema, "object", "value"),
-                                       "object", {"value", PropertyType::Float});
-        // will deadlock if it tries to start a write transaction
-        REQUIRE_THROWS(realm2->update_schema(new_schema));
-    }
-}
-
-TEST_CASE("migration: Manual") {
-    TestFile config;
-    config.schema_mode = SchemaMode::Manual;
-    auto realm = Realm::get_shared_realm(config);
-
-    Schema schema = {
-        {"object", {
-            {"pk", PropertyType::Int, Property::IsPrimary{true}},
-            {"value", PropertyType::Int, Property::IsPrimary{false}, Property::IsIndexed{true}},
-            {"optional", PropertyType::Int|PropertyType::Nullable},
-        }},
-        {"link origin", {
-            {"not a pk", PropertyType::Int},
-            {"object", PropertyType::Object|PropertyType::Nullable, "object"},
-            {"array", PropertyType::Array|PropertyType::Object, "object"},
-        }}
-    };
-    realm->update_schema(schema);
-    auto col_keys = realm->read_group().get_table("class_object")->get_column_keys();
-
-#define REQUIRE_MIGRATION(schema, migration) do { \
-    Schema new_schema = (schema); \
-    REQUIRE_THROWS(realm->update_schema(new_schema)); \
-    REQUIRE(realm->schema_version() == 0); \
-    REQUIRE_THROWS(realm->update_schema(new_schema, 1, [](SharedRealm, SharedRealm, Schema&){})); \
-    REQUIRE(realm->schema_version() == 0); \
-    REQUIRE_NOTHROW(realm->update_schema(new_schema, 1, migration)); \
-    REQUIRE(realm->schema_version() == 1); \
-} while (false)
-
-    SECTION("add new table") {
-        REQUIRE_MIGRATION(add_table(schema, {"new table", {
-            {"value", PropertyType::Int},
-        }}), [](SharedRealm, SharedRealm realm, Schema&) {
-            realm->read_group().add_table("class_new table")->add_column(type_Int, "value");
-        });
-    }
-    SECTION("add property to table") {
-        REQUIRE_MIGRATION(add_property(schema, "object", {"new", PropertyType::Int}),
-                          [&](SharedRealm, SharedRealm realm, Schema&) {
-                              get_table(realm, "object")->add_column(type_Int, "new");
-                          });
-    }
-    SECTION("remove property from table") {
-        REQUIRE_MIGRATION(remove_property(schema, "object", "value"),
-                          [&](SharedRealm, SharedRealm realm, Schema&) {
-                              get_table(realm, "object")->remove_column(col_keys[1]);
-                          });
-    }
-    SECTION("add primary key to table") {
-        REQUIRE_MIGRATION(set_primary_key(schema, "link origin", "not a pk"),
-                          [&](SharedRealm, SharedRealm realm, Schema&) {
-                              ObjectStore::set_primary_key_for_object(realm->read_group(), "link origin", "not a pk");
-                              auto table = get_table(realm, "link origin");
-                              table->add_search_index(table->get_column_key("not a pk"));
-                          });
-    }
-    SECTION("remove primary key from table") {
-        REQUIRE_MIGRATION(set_primary_key(schema, "object", ""),
-                          [&](SharedRealm, SharedRealm realm, Schema&) {
-                              ObjectStore::set_primary_key_for_object(realm->read_group(), "object", "");
-                              get_table(realm, "object")->remove_search_index(col_keys[0]);
-                          });
-    }
-    SECTION("change primary key") {
-        REQUIRE_MIGRATION(set_primary_key(schema, "object", "value"),
-                          [&](SharedRealm, SharedRealm realm, Schema&) {
-                              ObjectStore::set_primary_key_for_object(realm->read_group(), "object", "value");
-                              auto table = get_table(realm, "object");
-                              table->remove_search_index(col_keys[0]);
-                              table->add_search_index(col_keys[1]);
-                          });
-    }
-    SECTION("change property type") {
-        REQUIRE_MIGRATION(set_type(schema, "object", "value", PropertyType::Date),
-                          [&](SharedRealm, SharedRealm realm, Schema&) {
-                              auto table = get_table(realm, "object");
-                              table->remove_column(col_keys[1]);
-                              auto col = table->add_column(type_Timestamp, "value");
-                              table->add_search_index(col);
-                          });
-    }
-    SECTION("change link target") {
-        REQUIRE_MIGRATION(set_target(schema, "link origin", "object", "link origin"),
-                          [&](SharedRealm, SharedRealm realm, Schema&) {
-                              auto table = get_table(realm, "link origin");
-                              table->remove_column(table->get_column_keys()[1]);
-                              table->add_column_link(type_Link, "object", *table);
-                          });
-    }
-    SECTION("change linklist target") {
-        REQUIRE_MIGRATION(set_target(schema, "link origin", "array", "link origin"),
-                          [&](SharedRealm, SharedRealm realm, Schema&) {
-                              auto table = get_table(realm, "link origin");
-                              table->remove_column(table->get_column_keys()[2]);
-                              table->add_column_link(type_LinkList, "array", *table);
-                          });
-    }
-    SECTION("make property optional") {
-        REQUIRE_MIGRATION(set_optional(schema, "object", "value", true),
-                          [&](SharedRealm, SharedRealm realm, Schema&) {
-                              auto table = get_table(realm, "object");
-                              table->remove_column(col_keys[1]);
-                              auto col = table->add_column(type_Int, "value", true);
-                              table->add_search_index(col);
-                          });
-    }
-    SECTION("make property required") {
-        REQUIRE_MIGRATION(set_optional(schema, "object", "optional", false),
-                          [&](SharedRealm, SharedRealm realm, Schema&) {
-                              auto table = get_table(realm, "object");
-                              table->remove_column(col_keys[2]);
-                              table->add_column(type_Int, "optional", false);
-                          });
-    }
-    SECTION("add index") {
-        REQUIRE_MIGRATION(set_indexed(schema, "object", "optional", true),
-                          [&](SharedRealm, SharedRealm realm, Schema&) {
-                              get_table(realm, "object")->add_search_index(col_keys[2]);
-                          });
-    }
-    SECTION("remove index") {
-        REQUIRE_MIGRATION(set_indexed(schema, "object", "value", false),
-                          [&](SharedRealm, SharedRealm realm, Schema&) {
-                              get_table(realm, "object")->remove_search_index(col_keys[1]);
-                          });
-    }
-    SECTION("reorder properties") {
-        auto schema2 = schema;
-        auto& properties = schema2.find("object")->persisted_properties;
-        std::swap(properties[0], properties[1]);
-        REQUIRE_NOTHROW(realm->update_schema(schema2));
-    }
-
-    SECTION("cannot lower schema version") {
-        REQUIRE_NOTHROW(realm->update_schema(schema, 1, [](SharedRealm, SharedRealm, Schema&){}));
-        REQUIRE(realm->schema_version() == 1);
-        REQUIRE_THROWS(realm->update_schema(schema, 0, [](SharedRealm, SharedRealm, Schema&){}));
-        REQUIRE(realm->schema_version() == 1);
-    }
-
-    SECTION("update_schema() does not begin a write transaction when schema version is unchanged") {
-        realm->begin_transaction();
-
-        auto realm2 = Realm::get_shared_realm(config);
-        // will deadlock if it tries to start a write transaction
-        REQUIRE_NOTHROW(realm2->update_schema(schema));
-        REQUIRE_THROWS(realm2->update_schema(remove_property(schema, "object", "value")));
-    }
-
-    SECTION("null migration callback should throw SchemaMismatchException") {
-        Schema new_schema = remove_property(schema, "object", "value");
-        REQUIRE_THROWS_AS(realm->update_schema(new_schema, 1, nullptr), SchemaMismatchException);
-    }
-}

+ 0 - 13
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/notifications-fuzzer/CMakeLists.txt

@@ -1,13 +0,0 @@
-macro(build_fuzzer_variant variant)
-    add_executable(${variant} command_file.hpp command_file.cpp ${variant}.cpp)
-    target_link_libraries(${variant} realm-object-store)
-    set_target_properties(${variant} PROPERTIES
-      EXCLUDE_FROM_ALL 1
-      EXCLUDE_FROM_DEFAULT_BUILD 1)
-endmacro()
-
-build_fuzzer_variant(fuzzer)
-build_fuzzer_variant(fuzz-sorted-query)
-build_fuzzer_variant(fuzz-unsorted-query)
-build_fuzzer_variant(fuzz-sorted-linkview)
-build_fuzzer_variant(fuzz-unsorted-linkview)

+ 0 - 246
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/notifications-fuzzer/command_file.cpp

@@ -1,246 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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 "command_file.hpp"
-
-#include "impl/realm_coordinator.hpp"
-#include "shared_realm.hpp"
-
-#include <realm/link_view.hpp>
-#include <realm/table.hpp>
-
-#include <istream>
-
-using namespace fuzzer;
-using namespace realm;
-
-#if 0
-#define log(...) fprintf(stderr, __VA_ARGS__)
-#else
-#define log(...)
-#endif
-
-template<typename T>
-static T read_value(std::istream& input)
-{
-    T ret;
-    input >> ret;
-    return ret;
-}
-
-template<typename... Args>
-static auto make_reader(void (*fn)(RealmState&, Args...)) {
-    return [=](std::istream& input) {
-        return std::bind(fn, std::placeholders::_1, read_value<Args>(input)...);
-    };
-}
-
-static void run_add(RealmState& state, int64_t value)
-{
-    log("add %lld\n", value);
-    size_t ndx = state.table.add_empty_row();
-    state.table.set_int(0, ndx, state.uid++);
-    state.table.set_int(1, ndx, value);
-}
-
-static void run_modify(RealmState& state, size_t index, int64_t value)
-{
-    if (index < state.table.size()) {
-        log("modify %zu %lld\n", index, value);
-        state.table.set_int(1, index, value);
-        state.modified.push_back(state.table.get_int(0, index));
-    }
-}
-
-static void run_delete(RealmState& state, size_t index)
-{
-    if (index < state.table.size()) {
-        log("delete %zu (%lld)\n", index, state.table.get_int(1, index));
-        state.table.move_last_over(index);
-    }
-}
-
-static void run_commit(RealmState& state)
-{
-    log("commit\n");
-    state.realm.commit_transaction();
-    state.coordinator.on_change();
-    state.realm.begin_transaction();
-}
-
-static void run_lv_insert(RealmState& state, size_t pos, size_t target)
-{
-    if (!state.lv) return;
-    if (target < state.table.size() && pos <= state.lv->size()) {
-        log("lv insert %zu %zu\n", pos, target);
-        state.lv->insert(pos, target);
-    }
-}
-
-static void run_lv_set(RealmState& state, size_t pos, size_t target)
-{
-    if (!state.lv) return;
-    if (target < state.table.size() && pos < state.lv->size()) {
-        log("lv set %zu %zu\n", pos, target);
-        // We can't reliably detect self-assignment for verification, so don't do it
-        if (state.lv->get(pos).get_index() != target)
-            state.lv->set(pos, target);
-    }
-}
-
-static void run_lv_move(RealmState& state, size_t from, size_t to)
-{
-    if (!state.lv) return;
-    if (from < state.lv->size() && to < state.lv->size()) {
-        log("lv move %zu %zu\n", from, to);
-        // FIXME: only do the move if it has an effect to avoid getting a
-        // notification which we weren't expecting. This is really urgh.
-        for (size_t i = std::min(from, to); i < std::max(from, to); ++i) {
-            if (state.lv->get(i).get_index() != state.lv->get(i + 1).get_index()) {
-                state.lv->move(from, to);
-                break;
-            }
-        }
-    }
-}
-
-static void run_lv_swap(RealmState& state, size_t ndx1, size_t ndx2)
-{
-    if (!state.lv) return;
-    if (ndx1 < state.lv->size() && ndx2 < state.lv->size()) {
-        log("lv swap %zu %zu\n", ndx1, ndx2);
-        if (state.lv->get(ndx1).get_index() != state.lv->get(ndx2).get_index()) {
-            state.lv->swap(ndx1, ndx2);
-            // FIXME: swap() needs to produce moves so that a pair of swaps can
-            // be collapsed away. Currently it just marks the rows as modified.
-            state.modified.push_back(state.lv->get(ndx1).get_int(0));
-            state.modified.push_back(state.lv->get(ndx2).get_int(0));
-        }
-    }
-}
-
-static void run_lv_remove(RealmState& state, size_t pos)
-{
-    if (!state.lv) return;
-    if (pos < state.lv->size()) {
-        log("lv remove %zu\n", pos);
-        state.lv->remove(pos);
-    }
-}
-
-static void run_lv_remove_target(RealmState& state, size_t pos)
-{
-    if (!state.lv) return;
-    if (pos < state.lv->size()) {
-        log("lv target remove %zu\n", pos);
-        state.lv->remove_target_row(pos);
-    }
-}
-
-static std::map<char, std::function<std::function<void (RealmState&)>(std::istream&)>> readers = {
-    // Row functions
-    {'a', make_reader(run_add)},
-    {'c', make_reader(run_commit)},
-    {'d', make_reader(run_delete)},
-    {'m', make_reader(run_modify)},
-
-    // LinkView functions
-    {'i', make_reader(run_lv_insert)},
-    {'s', make_reader(run_lv_set)},
-    {'o', make_reader(run_lv_move)},
-    {'w', make_reader(run_lv_swap)},
-    {'r', make_reader(run_lv_remove)},
-    {'t', make_reader(run_lv_remove_target)},
-};
-
-template<typename T>
-static std::vector<T> read_int_list(std::istream& input_stream)
-{
-    std::vector<T> ret;
-    std::string line;
-    while (std::getline(input_stream, line) && !line.empty()) {
-        try {
-            ret.push_back(std::stoll(line));
-            log("%lld\n", (long long)ret.back());
-        }
-        catch (std::invalid_argument const&) {
-            // not an error
-        }
-        catch (std::out_of_range const&) {
-            // not an error
-        }
-    }
-    log("\n");
-    return ret;
-}
-
-CommandFile::CommandFile(std::istream& input)
-: initial_values(read_int_list<int64_t>(input))
-, initial_list_indices(read_int_list<size_t>(input))
-{
-    if (!input.good())
-        return;
-
-    while (input.good()) {
-        char op = '\0';
-        input >> op;
-        if (!input.good())
-            break;
-
-        auto it = readers.find(op);
-        if (it == readers.end())
-            continue;
-
-        auto fn = it->second(input);
-        if (!input.good())
-            return;
-        commands.push_back(std::move(fn));
-    }
-}
-
-void CommandFile::import(RealmState& state)
-{
-    auto& table = state.table;
-
-    state.realm.begin_transaction();
-
-    table.clear();
-    size_t ndx = table.add_empty_row(initial_values.size());
-    for (auto value : initial_values) {
-        table.set_int(0, ndx, state.uid++);
-        table.set_int(1, ndx++, value);
-    }
-
-    state.lv->clear();
-    for (auto value : initial_list_indices) {
-        if (value < table.size())
-            state.lv->add(value);
-    }
-
-    state.realm.commit_transaction();
-
-}
-
-void CommandFile::run(RealmState& state)
-{
-    state.realm.begin_transaction();
-    for (auto& command : commands) {
-        command(state);
-    }
-    state.realm.commit_transaction();
-}

+ 0 - 56
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/notifications-fuzzer/command_file.hpp

@@ -1,56 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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 <realm/link_view_fwd.hpp>
-
-#include <iosfwd>
-#include <functional>
-#include <memory>
-#include <vector>
-
-namespace realm {
-    class Table;
-    class LinkView;
-    class Realm;
-    namespace _impl {
-        class RealmCoordinator;
-    }
-}
-
-namespace fuzzer {
-struct RealmState {
-    realm::Realm& realm;
-    realm::_impl::RealmCoordinator& coordinator;
-
-    realm::Table& table;
-    realm::LinkViewRef lv;
-    int64_t uid;
-    std::vector<int64_t> modified;
-};
-
-struct CommandFile {
-    std::vector<int64_t> initial_values;
-    std::vector<size_t> initial_list_indices;
-    std::vector<std::function<void (RealmState&)>> commands;
-
-    CommandFile(std::istream& input);
-
-    void import(RealmState& state);
-    void run(RealmState& state);
-};
-}

+ 0 - 21
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/notifications-fuzzer/fuzz-sorted-linkview.cpp

@@ -1,21 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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.
-//
-////////////////////////////////////////////////////////////////////////////
-
-#define FUZZ_SORTED 1
-#define FUZZ_LINKVIEW 1
-#include "fuzzer.cpp"

+ 0 - 21
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/notifications-fuzzer/fuzz-sorted-query.cpp

@@ -1,21 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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.
-//
-////////////////////////////////////////////////////////////////////////////
-
-#define FUZZ_SORTED 1
-#define FUZZ_LINKVIEW 0
-#include "fuzzer.cpp"

+ 0 - 21
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/notifications-fuzzer/fuzz-unsorted-linkview.cpp

@@ -1,21 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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.
-//
-////////////////////////////////////////////////////////////////////////////
-
-#define FUZZ_SORTED 0
-#define FUZZ_LINKVIEW 1
-#include "fuzzer.cpp"

+ 0 - 21
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/notifications-fuzzer/fuzz-unsorted-query.cpp

@@ -1,21 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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.
-//
-////////////////////////////////////////////////////////////////////////////
-
-#define FUZZ_SORTED 0
-#define FUZZ_LINKVIEW 0
-#include "fuzzer.cpp"

+ 0 - 308
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/notifications-fuzzer/fuzzer.cpp

@@ -1,308 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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 "command_file.hpp"
-
-#include "list.hpp"
-#include "object_schema.hpp"
-#include "property.hpp"
-#include "results.hpp"
-#include "schema.hpp"
-#include "impl/realm_coordinator.hpp"
-
-#include <realm/commit_log.hpp>
-#include <realm/disable_sync_to_disk.hpp>
-#include <realm/group_shared.hpp>
-#include <realm/link_view.hpp>
-
-#include <iostream>
-#include <sstream>
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <unistd.h>
-
-using namespace realm;
-
-#ifndef FUZZ_SORTED
-#define FUZZ_SORTED 0
-#endif
-
-#ifndef FUZZ_LINKVIEW
-#define FUZZ_LINKVIEW 0
-#endif
-
-#define FUZZ_LOG 0
-
-// Read from a fd until eof into a string
-// Needs to use unbuffered i/o to work properly with afl
-static void read_all(std::string& buffer, int fd)
-{
-    buffer.clear();
-    size_t offset = 0;
-    while (true) {
-        buffer.resize(offset + 4096);
-        ssize_t bytes_read = read(fd, &buffer[offset], 4096);
-        if (bytes_read < 4096) {
-            buffer.resize(offset + bytes_read);
-            break;
-        }
-        offset += 4096;
-    }
-}
-
-static Query query(fuzzer::RealmState& state)
-{
-#if FUZZ_LINKVIEW
-    return state.table.where(state.lv);
-#else
-    return state.table.where().greater(1, 100).less(1, 50000);
-#endif
-}
-
-static TableView tableview(fuzzer::RealmState& state)
-{
-    auto tv = query(state).find_all();
-#if FUZZ_SORTED
-    tv.sort({1, 0}, {true, true});
-#endif
-    return tv;
-}
-
-// Apply the changes from the command file and then return whether a change
-// notification should occur
-static bool apply_changes(fuzzer::CommandFile& commands, fuzzer::RealmState& state)
-{
-    auto tv = tableview(state);
-#if FUZZ_LOG
-    for (size_t i = 0; i < tv.size(); ++i)
-        fprintf(stderr, "pre: %lld\n", tv.get_int(0, i));
-#endif
-
-    commands.run(state);
-
-    auto tv2 = tableview(state);
-    if (tv.size() != tv2.size())
-        return true;
-
-    for (size_t i = 0; i < tv.size(); ++i) {
-#if FUZZ_LOG
-        fprintf(stderr, "%lld %lld\n", tv.get_int(0, i), tv2.get_int(0, i));
-#endif
-        if (!tv.is_row_attached(i))
-            return true;
-        if (tv.get_int(0, i) != tv2.get_int(0, i))
-            return true;
-        if (find(begin(state.modified), end(state.modified), tv.get_int(0, i)) != end(state.modified))
-            return true;
-    }
-
-    return false;
-}
-
-static auto verify(CollectionChangeIndices const& changes, std::vector<int64_t> values, fuzzer::RealmState& state)
-{
-    auto tv = tableview(state);
-
-    // Apply the changes from the transaction log to our copy of the
-    // initial, using UITableView's batching rules (i.e. delete, then
-    // insert, then update)
-    auto it = util::make_reverse_iterator(changes.deletions.end());
-    auto end = util::make_reverse_iterator(changes.deletions.begin());
-    for (; it != end; ++it) {
-        values.erase(values.begin() + it->first, values.begin() + it->second);
-    }
-
-    for (auto i : changes.insertions.as_indexes()) {
-        values.insert(values.begin() + i, tv.get_int(1, i));
-    }
-
-    if (values.size() != tv.size()) {
-        abort();
-    }
-
-    for (auto i : changes.modifications.as_indexes()) {
-        if (changes.insertions.contains(i))
-            abort();
-        values[i] = tv.get_int(1, i);
-    }
-
-#if FUZZ_SORTED
-    if (!std::is_sorted(values.begin(), values.end()))
-        abort();
-#endif
-
-    for (size_t i = 0; i < values.size(); ++i) {
-        if (values[i] != tv.get_int(1, i)) {
-#if FUZZ_LOG
-            fprintf(stderr, "%lld %lld\n", values[i], tv.get_int(1, i));
-#endif
-            abort();
-        }
-    }
-
-    return values;
-}
-
-static void verify_no_op(CollectionChangeIndices const& changes, std::vector<int64_t> values, fuzzer::RealmState& state)
-{
-    auto new_values = verify(changes, values, state);
-    if (!std::equal(begin(values), end(values), begin(new_values), end(new_values)))
-        abort();
-}
-
-static void test(Realm::Config const& config, SharedRealm& r, SharedRealm& r2, std::istream& input_stream)
-{
-    fuzzer::RealmState state = {
-        *r,
-        *_impl::RealmCoordinator::get_existing_coordinator(r->config().path),
-        *r->read_group()->get_table("class_object"),
-        r->read_group()->get_table("class_linklist")->get_linklist(0, 0),
-        0,
-        {}
-    };
-
-    fuzzer::CommandFile command(input_stream);
-    if (command.initial_values.empty()) {
-        return;
-    }
-    command.import(state);
-
-    fuzzer::RealmState state2 = {
-        *r2,
-        state.coordinator,
-        *r2->read_group()->get_table("class_object"),
-#if FUZZ_LINKVIEW
-        r2->read_group()->get_table("class_linklist")->get_linklist(0, 0),
-#else
-        {},
-#endif
-        state.uid,
-        {}
-    };
-
-#if FUZZ_LINKVIEW && !FUZZ_SORTED
-    auto results = List(r, ObjectSchema(), state.lv);
-#else
-    auto results = Results(r, ObjectSchema(), query(state))
-#if FUZZ_SORTED
-        .sort({{1, 0}, {true, true}})
-#endif
-        ;
-#endif // FUZZ_LINKVIEW
-
-    std::vector<int64_t> initial_values;
-    for (size_t i = 0; i < results.size(); ++i)
-        initial_values.push_back(results.get(i).get_int(1));
-
-    CollectionChangeIndices changes;
-    int notification_calls = 0;
-    auto token = results.add_notification_callback([&](CollectionChangeIndices c, std::exception_ptr err) {
-        if (notification_calls > 0 && c.empty())
-            abort();
-        changes = c;
-        ++notification_calls;
-    });
-
-    state.coordinator.on_change(); r->notify();
-    if (notification_calls != 1) {
-        abort();
-    }
-
-    bool expect_notification = apply_changes(command, state2);
-    state.coordinator.on_change(); r->notify();
-
-    if (expect_notification) {
-        if (notification_calls != 2)
-            abort();
-        verify(changes, initial_values, state);
-    }
-    else {
-        if (notification_calls == 2)
-            verify_no_op(changes, initial_values, state);
-    }
-}
-
-int main(int argc, char** argv) {
-    std::ios_base::sync_with_stdio(false);
-    realm::disable_sync_to_disk();
-
-    Realm::Config config;
-    config.path = "fuzzer.realm";
-    config.in_memory = true;
-    config.automatic_change_notifications = false;
-
-    Schema schema{
-        {"object", "", {
-            {"id", PropertyTypeInt},
-            {"value", PropertyTypeInt}
-        }},
-        {"linklist", "", {
-            {"list", PropertyTypeArray, "object"}
-        }}
-    };
-
-    config.schema = std::make_unique<Schema>(schema);
-    unlink(config.path.c_str());
-
-    auto r = Realm::get_shared_realm(config);
-    auto r2 = Realm::get_shared_realm(config);
-    auto& coordinator = *_impl::RealmCoordinator::get_existing_coordinator(config.path);
-
-    r->begin_transaction();
-    r->read_group()->get_table("class_linklist")->add_empty_row();
-    r->commit_transaction();
-
-    auto test_on = [&](auto& buffer) {
-        std::istringstream ss(buffer);
-        test(config, r, r2, ss);
-        if (r->is_in_transaction())
-            r->cancel_transaction();
-        r2->invalidate();
-        coordinator.on_change();
-    };
-
-    if (argc > 1) {
-        std::string buffer;
-        for (int i = 1; i < argc; ++i) {
-            int fd = open(argv[i], O_RDONLY);
-            if (fd < 0)
-                abort();
-            read_all(buffer, fd);
-            close(fd);
-
-            test_on(buffer);
-        }
-        unlink(config.path.c_str());
-        return 0;
-    }
-
-#ifdef __AFL_HAVE_MANUAL_CONTROL
-    std::string buffer;
-    while (__AFL_LOOP(1000)) {
-        read_all(buffer, 0);
-        test_on(buffer);
-    }
-#else
-    std::string buffer;
-    read_all(buffer, 0);
-    test_on(buffer);
-#endif
-
-    unlink(config.path.c_str());
-    return 0;
-}

+ 0 - 38
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/notifications-fuzzer/input-lv/0

@@ -1,38 +0,0 @@
-3
-100
-200
-400
-1000
-2000
-50
-80
-150
-180
-6000
-5000
-60000
-
-1
-2
-3
-4
-5
-6
-7
-8
-9
-10
-11
-12
-
-a 500
-d 12
-c
-m 11 10000
-a 800
-i 5 13
-s 3 8
-o 2 10
-w 1 6
-r 7
-t 11

+ 0 - 20
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/notifications-fuzzer/input/0

@@ -1,20 +0,0 @@
-3
-100
-200
-400
-1000
-2000
-50
-80
-150
-180
-6000
-5000
-60000
-
-
-a 500
-d 12
-c
-m 11 10000
-a 800

+ 0 - 34
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/notifications-fuzzer/input/1

@@ -1,34 +0,0 @@
-101
-102
-103
-104
-105
-106
-107
-108
-109
-110
-111
-112
-113
-
-
-a 114
-a 115
-a 116
-a 117
-a 118
-a 119
-a 120
-a 121
-a 122
-c
-m 4 200
-m 3 201
-m 2 202
-m 1 203
-m 5 203
-m 6 204
-m 7 205
-c
-d 11

+ 0 - 1017
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/object.cpp

@@ -1,1017 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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 "catch2/catch.hpp"
-
-#include "util/event_loop.hpp"
-#include "util/index_helpers.hpp"
-#include "util/test_file.hpp"
-
-#include "feature_checks.hpp"
-#include "collection_notifications.hpp"
-#include "object_accessor.hpp"
-#include "property.hpp"
-#include "schema.hpp"
-
-#include "impl/realm_coordinator.hpp"
-#include "impl/object_accessor_impl.hpp"
-
-#include <realm/group.hpp>
-#include <realm/util/any.hpp>
-
-#include <cstdint>
-
-using namespace realm;
-
-namespace {
-using AnyDict = std::map<std::string, util::Any>;
-using AnyVec = std::vector<util::Any>;
-template <class T>
-std::vector<T> get_vector(std::initializer_list<T> list)
-{
-    return std::vector<T>(list);
-}
-}
-
-struct TestContext : CppContext {
-    std::map<std::string, AnyDict> defaults;
-
-    using CppContext::CppContext;
-    TestContext(TestContext& parent, realm::Property const& prop)
-    : CppContext(parent, prop)
-    , defaults(parent.defaults)
-    { }
-
-    util::Optional<util::Any>
-    default_value_for_property(ObjectSchema const& object, Property const& prop)
-    {
-        auto obj_it = defaults.find(object.name);
-        if (obj_it == defaults.end())
-            return util::none;
-        auto prop_it = obj_it->second.find(prop.name);
-        if (prop_it == obj_it->second.end())
-            return util::none;
-        return prop_it->second;
-    }
-
-    void will_change(Object const&, Property const&) {}
-    void did_change() {}
-    std::string print(util::Any) { return "not implemented"; }
-    bool allow_missing(util::Any) { return false; }
-};
-
-TEST_CASE("object") {
-    using namespace std::string_literals;
-    _impl::RealmCoordinator::assert_no_open_realms();
-
-    InMemoryTestFile config;
-    config.automatic_change_notifications = false;
-    config.schema = Schema{
-        {"table", {
-            {"value 1", PropertyType::Int},
-            {"value 2", PropertyType::Int},
-        }},
-        {"all types", {
-            {"pk", PropertyType::Int, Property::IsPrimary{true}},
-            {"bool", PropertyType::Bool},
-            {"int", PropertyType::Int},
-            {"float", PropertyType::Float},
-            {"double", PropertyType::Double},
-            {"string", PropertyType::String},
-            {"data", PropertyType::Data},
-            {"date", PropertyType::Date},
-            {"object", PropertyType::Object|PropertyType::Nullable, "link target"},
-
-            {"bool array", PropertyType::Array|PropertyType::Bool},
-            {"int array", PropertyType::Array|PropertyType::Int},
-            {"float array", PropertyType::Array|PropertyType::Float},
-            {"double array", PropertyType::Array|PropertyType::Double},
-            {"string array", PropertyType::Array|PropertyType::String},
-            {"data array", PropertyType::Array|PropertyType::Data},
-            {"date array", PropertyType::Array|PropertyType::Date},
-            {"object array", PropertyType::Array|PropertyType::Object, "array target"},
-        }},
-        {"all optional types", {
-            {"pk", PropertyType::Int|PropertyType::Nullable, Property::IsPrimary{true}},
-            {"bool", PropertyType::Bool|PropertyType::Nullable},
-            {"int", PropertyType::Int|PropertyType::Nullable},
-            {"float", PropertyType::Float|PropertyType::Nullable},
-            {"double", PropertyType::Double|PropertyType::Nullable},
-            {"string", PropertyType::String|PropertyType::Nullable},
-            {"data", PropertyType::Data|PropertyType::Nullable},
-            {"date", PropertyType::Date|PropertyType::Nullable},
-
-            {"bool array", PropertyType::Array|PropertyType::Bool|PropertyType::Nullable},
-            {"int array", PropertyType::Array|PropertyType::Int|PropertyType::Nullable},
-            {"float array", PropertyType::Array|PropertyType::Float|PropertyType::Nullable},
-            {"double array", PropertyType::Array|PropertyType::Double|PropertyType::Nullable},
-            {"string array", PropertyType::Array|PropertyType::String|PropertyType::Nullable},
-            {"data array", PropertyType::Array|PropertyType::Data|PropertyType::Nullable},
-            {"date array", PropertyType::Array|PropertyType::Date|PropertyType::Nullable},
-        }},
-        {"link target", {
-            {"value", PropertyType::Int},
-        }, {
-            {"origin", PropertyType::LinkingObjects|PropertyType::Array, "all types", "object"},
-        }},
-        {"array target", {
-            {"value", PropertyType::Int},
-        }},
-        {"pk after list", {
-            {"array 1", PropertyType::Array|PropertyType::Object, "array target"},
-            {"int 1", PropertyType::Int},
-            {"pk", PropertyType::Int, Property::IsPrimary{true}},
-            {"int 2", PropertyType::Int},
-            {"array 2", PropertyType::Array|PropertyType::Object, "array target"},
-        }},
-        {"nullable int pk", {
-            {"pk", PropertyType::Int|PropertyType::Nullable, Property::IsPrimary{true}},
-        }},
-        {"nullable string pk", {
-            {"pk", PropertyType::String|PropertyType::Nullable, Property::IsPrimary{true}},
-        }},
-        {"person", {
-            {"name", PropertyType::String, Property::IsPrimary{true}},
-            {"age", PropertyType::Int},
-            {"scores", PropertyType::Array|PropertyType::Int},
-            {"assistant", PropertyType::Object|PropertyType::Nullable, "person"},
-            {"team", PropertyType::Array|PropertyType::Object, "person"},
-        }},
-    };
-    config.schema_version = 0;
-    auto r = Realm::get_shared_realm(config);
-    auto& coordinator = *_impl::RealmCoordinator::get_coordinator(config.path);
-
-    SECTION("add_notification_callback()") {
-        auto table = r->read_group().get_table("class_table");
-        auto col_keys = table->get_column_keys();
-        ObjKeys object_keys({3, 4, 7, 9, 10, 21, 24, 34, 42, 50});
-        r->begin_transaction();
-        for (int i = 0; i < 10; ++i)
-            table->create_object(object_keys[i]).set_all(i);
-        r->commit_transaction();
-
-        auto r2 = coordinator.get_realm();
-
-        CollectionChangeSet change;
-        auto obj = *table->begin();
-        Object object(r, obj);
-
-        auto write = [&](auto&& f) {
-            r->begin_transaction();
-            f();
-            r->commit_transaction();
-
-            advance_and_notify(*r);
-        };
-
-        auto require_change = [&] {
-            auto token = object.add_notification_callback([&](CollectionChangeSet c, std::exception_ptr) {
-                change = c;
-            });
-            advance_and_notify(*r);
-            return token;
-        };
-
-        auto require_no_change = [&] {
-            bool first = true;
-            auto token = object.add_notification_callback([&](CollectionChangeSet, std::exception_ptr) {
-                REQUIRE(first);
-                first = false;
-            });
-            advance_and_notify(*r);
-            return token;
-        };
-
-        SECTION("deleting the object sends a change notification") {
-            auto token = require_change();
-            write([&] { obj.remove(); });
-            REQUIRE_INDICES(change.deletions, 0);
-        }
-
-        SECTION("clearing the table sends a change notification") {
-            auto token = require_change();
-            write([&] { table->clear(); });
-            REQUIRE_INDICES(change.deletions, 0);
-        }
-
-        SECTION("clearing the table sends a change notification to the last object") {
-            obj = table->get_object(table->size() - 1);
-            object = Object(r, obj);
-
-            auto token = require_change();
-            write([&] { table->clear(); });
-            REQUIRE_INDICES(change.deletions, 0);
-        }
-
-        SECTION("modifying the object sends a change notification") {
-            auto token = require_change();
-
-            write([&] { obj.set(col_keys[0], 10); });
-            REQUIRE_INDICES(change.modifications, 0);
-            REQUIRE(change.columns.size() == 1);
-            REQUIRE_INDICES(change.columns[col_keys[0].value], 0);
-
-            write([&] { obj.set(col_keys[1], 10); });
-            REQUIRE_INDICES(change.modifications, 0);
-            REQUIRE(change.columns.size() == 1);
-            REQUIRE_INDICES(change.columns[col_keys[1].value], 0);
-        }
-
-        SECTION("modifying a different object") {
-            auto token = require_no_change();
-            write([&] { table->get_object(1).set(col_keys[0], 10); });
-        }
-
-        SECTION("multiple write transactions") {
-            auto token = require_change();
-
-            auto r2row = r2->read_group().get_table("class_table")->get_object(0);
-            r2->begin_transaction();
-            r2row.set(col_keys[0], 1);
-            r2->commit_transaction();
-            r2->begin_transaction();
-            r2row.set(col_keys[1], 2);
-            r2->commit_transaction();
-
-            advance_and_notify(*r);
-            REQUIRE(change.columns.size() == 2);
-            REQUIRE_INDICES(change.columns[col_keys[0].value], 0);
-            REQUIRE_INDICES(change.columns[col_keys[1].value], 0);
-        }
-
-        SECTION("skipping a notification") {
-            auto token = require_no_change();
-            write([&] {
-                obj.set(col_keys[0], 1);
-                token.suppress_next();
-            });
-        }
-
-        SECTION("skipping only effects the current transaction even if no notification would occur anyway") {
-            auto token = require_change();
-
-            // would not produce a notification even if it wasn't skipped because no changes were made
-            write([&] {
-                token.suppress_next();
-            });
-            REQUIRE(change.empty());
-
-            // should now produce a notification
-            write([&] { obj.set(col_keys[0], 1); });
-            REQUIRE_INDICES(change.modifications, 0);
-        }
-
-        SECTION("add notification callback, remove it, then add another notification callback") {
-            {
-                auto token = object.add_notification_callback([&](CollectionChangeSet, std::exception_ptr) {
-                    FAIL("This should never happen");
-                });
-            }
-            auto token = require_change();
-            write([&] { obj.remove(); });
-            REQUIRE_INDICES(change.deletions, 0);
-        }
-
-        SECTION("observing deleted object throws") {
-            write([&] {
-                obj.remove();
-            });
-            REQUIRE_THROWS(require_change());
-        }
-    }
-
-    TestContext d(r);
-    auto create = [&](util::Any&& value, CreatePolicy policy = CreatePolicy::ForceCreate) {
-        r->begin_transaction();
-        auto obj = Object::create(d, r, *r->schema().find("all types"), value, policy);
-        r->commit_transaction();
-        return obj;
-    };
-    auto create_sub = [&](util::Any&& value, CreatePolicy policy = CreatePolicy::ForceCreate) {
-        r->begin_transaction();
-        auto obj = Object::create(d, r, *r->schema().find("link target"), value, policy);
-        r->commit_transaction();
-        return obj;
-    };
-    auto create_company = [&](util::Any&& value, CreatePolicy policy = CreatePolicy::ForceCreate) {
-        r->begin_transaction();
-        auto obj = Object::create(d, r, *r->schema().find("person"), value, policy);
-        r->commit_transaction();
-        return obj;
-    };
-
-    SECTION("create object") {
-        auto obj = create(AnyDict{
-            {"pk", INT64_C(1)},
-            {"bool", true},
-            {"int", INT64_C(5)},
-            {"float", 2.2f},
-            {"double", 3.3},
-            {"string", "hello"s},
-            {"data", "olleh"s},
-            {"date", Timestamp(10, 20)},
-            {"object", AnyDict{{"value", INT64_C(10)}}},
-
-            {"bool array", AnyVec{true, false}},
-            {"int array", AnyVec{INT64_C(5), INT64_C(6)}},
-            {"float array", AnyVec{1.1f, 2.2f}},
-            {"double array", AnyVec{3.3, 4.4}},
-            {"string array", AnyVec{"a"s, "b"s, "c"s}},
-            {"data array", AnyVec{"d"s, "e"s, "f"s}},
-            {"date array", AnyVec{Timestamp(10, 20), Timestamp(30, 40)}},
-            {"object array", AnyVec{AnyDict{{"value", INT64_C(20)}}}},
-        });
-
-        auto row = obj.obj();
-        auto link_target = *r->read_group().get_table("class_link target")->begin();
-        auto table = row.get_table();
-        auto target_table = link_target.get_table();
-        auto array_target_table = r->read_group().get_table("class_array target");
-        REQUIRE(row.get<Int>(table->get_column_key("pk")) == 1);
-        REQUIRE(row.get<Bool>(table->get_column_key("bool")) == true);
-        REQUIRE(row.get<Int>(table->get_column_key("int")) == 5);
-        REQUIRE(row.get<float>(table->get_column_key("float")) == 2.2f);
-        REQUIRE(row.get<double>(table->get_column_key("double")) == 3.3);
-        REQUIRE(row.get<String>(table->get_column_key("string")) == "hello");
-        REQUIRE(row.get<Binary>(table->get_column_key("data")) == BinaryData("olleh", 5));
-        REQUIRE(row.get<Timestamp>(table->get_column_key("date")) == Timestamp(10, 20));
-        REQUIRE(row.get<ObjKey>(table->get_column_key("object")) == link_target.get_key());
-
-        REQUIRE(link_target.get<Int>(target_table->get_column_key("value")) == 10);
-
-        auto check_array = [&](ColKey col, auto... values) {
-            auto vec = get_vector({values...});
-            using U = typename decltype(vec)::value_type;
-            auto list = row.get_list<U>(col);
-            size_t i = 0;
-            for (const auto& value : vec) {
-                CAPTURE(i);
-                REQUIRE(i < list.size());
-                REQUIRE(value == list.get(i));
-                ++i;
-            }
-        };
-        check_array(table->get_column_key("bool array"), true, false);
-        check_array(table->get_column_key("int array"), INT64_C(5), INT64_C(6));
-        check_array(table->get_column_key("float array"), 1.1f, 2.2f);
-        check_array(table->get_column_key("double array"), 3.3, 4.4);
-        check_array(table->get_column_key("string array"), StringData("a"), StringData("b"), StringData("c"));
-        check_array(table->get_column_key("data array"), BinaryData("d", 1), BinaryData("e", 1), BinaryData("f", 1));
-        check_array(table->get_column_key("date array"), Timestamp(10, 20), Timestamp(30, 40));
-
-        auto list = row.get_linklist_ptr(table->get_column_key("object array"));
-        REQUIRE(list->size() == 1);
-        REQUIRE(list->get_object(0).get<Int>(array_target_table->get_column_key("value")) == 20);
-    }
-
-    SECTION("create uses defaults for missing values") {
-        d.defaults["all types"] = {
-            {"bool", true},
-            {"int", INT64_C(5)},
-            {"float", 2.2f},
-            {"double", 3.3},
-            {"string", "hello"s},
-            {"data", "olleh"s},
-            {"date", Timestamp(10, 20)},
-            {"object", AnyDict{{"value", INT64_C(10)}}},
-
-            {"bool array", AnyVec{true, false}},
-            {"int array", AnyVec{INT64_C(5), INT64_C(6)}},
-            {"float array", AnyVec{1.1f, 2.2f}},
-            {"double array", AnyVec{3.3, 4.4}},
-            {"string array", AnyVec{"a"s, "b"s, "c"s}},
-            {"data array", AnyVec{"d"s, "e"s, "f"s}},
-            {"date array", AnyVec{}},
-            {"object array", AnyVec{AnyDict{{"value", INT64_C(20)}}}},
-        };
-
-        auto obj = create(AnyDict{
-            {"pk", INT64_C(1)},
-            {"float", 6.6f},
-        });
-
-        auto row = obj.obj();
-        auto table = row.get_table();
-        REQUIRE(row.get<Int>(table->get_column_key("pk")) == 1);
-        REQUIRE(row.get<Bool>(table->get_column_key("bool")) == true);
-        REQUIRE(row.get<Int>(table->get_column_key("int")) == 5);
-        REQUIRE(row.get<float>(table->get_column_key("float")) == 6.6f);
-        REQUIRE(row.get<double>(table->get_column_key("double")) == 3.3);
-        REQUIRE(row.get<String>(table->get_column_key("string")) == "hello");
-        REQUIRE(row.get<Binary>(table->get_column_key("data")) == BinaryData("olleh", 5));
-        REQUIRE(row.get<Timestamp>(table->get_column_key("date")) == Timestamp(10, 20));
-
-        REQUIRE(row.get_listbase_ptr(table->get_column_key("bool array"))->size() == 2);
-        REQUIRE(row.get_listbase_ptr(table->get_column_key("int array"))->size() == 2);
-        REQUIRE(row.get_listbase_ptr(table->get_column_key("float array"))->size() == 2);
-        REQUIRE(row.get_listbase_ptr(table->get_column_key("double array"))->size() == 2);
-        REQUIRE(row.get_listbase_ptr(table->get_column_key("string array"))->size() == 3);
-        REQUIRE(row.get_listbase_ptr(table->get_column_key("data array"))->size() == 3);
-        REQUIRE(row.get_listbase_ptr(table->get_column_key("date array"))->size() == 0);
-        REQUIRE(row.get_listbase_ptr(table->get_column_key("object array"))->size() == 1);
-    }
-
-    SECTION("create can use defaults for primary key") {
-        d.defaults["all types"] = {
-            {"pk", INT64_C(10)},
-        };
-        auto obj = create(AnyDict{
-            {"bool", true},
-            {"int", INT64_C(5)},
-            {"float", 2.2f},
-            {"double", 3.3},
-            {"string", "hello"s},
-            {"data", "olleh"s},
-            {"date", Timestamp(10, 20)},
-            {"object", AnyDict{{"value", INT64_C(10)}}},
-            {"array", AnyVector{AnyDict{{"value", INT64_C(20)}}}},
-        });
-
-        auto row = obj.obj();
-        REQUIRE(row.get<Int>(row.get_table()->get_column_key("pk")) == 10);
-    }
-
-    SECTION("create does not complain about missing values for nullable fields") {
-        r->begin_transaction();
-        realm::Object obj;
-        REQUIRE_NOTHROW(obj = Object::create(d, r, *r->schema().find("all optional types"), util::Any(AnyDict{})));
-        r->commit_transaction();
-
-        REQUIRE_FALSE(obj.get_property_value<util::Any>(d, "pk").has_value());
-        REQUIRE_FALSE(obj.get_property_value<util::Any>(d, "bool").has_value());
-        REQUIRE_FALSE(obj.get_property_value<util::Any>(d, "int").has_value());
-        REQUIRE_FALSE(obj.get_property_value<util::Any>(d, "float").has_value());
-        REQUIRE_FALSE(obj.get_property_value<util::Any>(d, "double").has_value());
-        REQUIRE_FALSE(obj.get_property_value<util::Any>(d, "string").has_value());
-        REQUIRE_FALSE(obj.get_property_value<util::Any>(d, "data").has_value());
-        REQUIRE_FALSE(obj.get_property_value<util::Any>(d, "date").has_value());
-
-        REQUIRE(any_cast<List&&>(obj.get_property_value<util::Any>(d, "bool array")).size() == 0);
-        REQUIRE(any_cast<List&&>(obj.get_property_value<util::Any>(d, "int array")).size() == 0);
-        REQUIRE(any_cast<List&&>(obj.get_property_value<util::Any>(d, "float array")).size() == 0);
-        REQUIRE(any_cast<List&&>(obj.get_property_value<util::Any>(d, "double array")).size() == 0);
-        REQUIRE(any_cast<List&&>(obj.get_property_value<util::Any>(d, "string array")).size() == 0);
-        REQUIRE(any_cast<List&&>(obj.get_property_value<util::Any>(d, "data array")).size() == 0);
-        REQUIRE(any_cast<List&&>(obj.get_property_value<util::Any>(d, "date array")).size() == 0);
-    }
-
-    SECTION("create throws for missing values if there is no default") {
-        REQUIRE_THROWS(create(AnyDict{
-            {"pk", INT64_C(1)},
-            {"float", 6.6f},
-        }));
-    }
-
-    SECTION("create always sets the PK first") {
-        AnyDict value{
-            {"array 1", AnyVector{AnyDict{{"value", INT64_C(1)}}}},
-            {"array 2", AnyVector{AnyDict{{"value", INT64_C(2)}}}},
-            {"int 1", INT64_C(0)},
-            {"int 2", INT64_C(0)},
-            {"pk", INT64_C(7)},
-        };
-        // Core will throw if the list is populated before the PK is set
-        r->begin_transaction();
-        REQUIRE_NOTHROW(Object::create(d, r, *r->schema().find("pk after list"), util::Any(value)));
-    }
-
-    SECTION("create with update") {
-        CollectionChangeSet change;
-        bool callback_called;
-        Object obj = create(AnyDict{
-            {"pk", INT64_C(1)},
-            {"bool", true},
-            {"int", INT64_C(5)},
-            {"float", 2.2f},
-            {"double", 3.3},
-            {"string", "hello"s},
-            {"data", "olleh"s},
-            {"date", Timestamp(10, 20)},
-            {"object", AnyDict{{"value", INT64_C(10)}}},
-
-            {"bool array", AnyVec{true, false}},
-            {"int array", AnyVec{INT64_C(5), INT64_C(6)}},
-            {"float array", AnyVec{1.1f, 2.2f}},
-            {"double array", AnyVec{3.3, 4.4}},
-            {"string array", AnyVec{"a"s, "b"s, "c"s}},
-            {"data array", AnyVec{"d"s, "e"s, "f"s}},
-            {"date array", AnyVec{}},
-            {"object array", AnyVec{AnyDict{{"value", INT64_C(20)}}}},
-        });
-
-        auto token = obj.add_notification_callback([&](CollectionChangeSet c, std::exception_ptr) {
-            change = c;
-            callback_called = true;
-        });
-        advance_and_notify(*r);
-
-        create(AnyDict{
-            {"pk", INT64_C(1)},
-            {"int", INT64_C(6)},
-            {"string", "a"s},
-        }, CreatePolicy::UpdateAll);
-
-        callback_called = false;
-        advance_and_notify(*r);
-        REQUIRE(callback_called);
-        REQUIRE_INDICES(change.modifications, 0);
-
-        auto row = obj.obj();
-        auto table = row.get_table();
-        REQUIRE(row.get<Int>(table->get_column_key("pk")) == 1);
-        REQUIRE(row.get<Bool>(table->get_column_key("bool")) == true);
-        REQUIRE(row.get<Int>(table->get_column_key("int")) == 6);
-        REQUIRE(row.get<float>(table->get_column_key("float")) == 2.2f);
-        REQUIRE(row.get<double>(table->get_column_key("double")) == 3.3);
-        REQUIRE(row.get<String>(table->get_column_key("string")) == "a");
-        REQUIRE(row.get<Binary>(table->get_column_key("data")) == BinaryData("olleh", 5));
-        REQUIRE(row.get<Timestamp>(table->get_column_key("date")) == Timestamp(10, 20));
-    }
-
-    SECTION("create with update - only with diffs") {
-        CollectionChangeSet change;
-        bool callback_called;
-        AnyDict adam {
-            {"name", "Adam"s},
-            {"age", INT64_C(32)},
-            {"scores", AnyVec{INT64_C(1), INT64_C(2)}},
-        };
-        AnyDict brian {
-            {"name", "Brian"s},
-            {"age", INT64_C(33)},
-        };
-        AnyDict charley {
-            {"name", "Charley"s},
-            {"age", INT64_C(34)},
-            {"team", AnyVec{adam, brian}}
-        };
-        AnyDict donald {
-            {"name", "Donald"s},
-            {"age", INT64_C(35)},
-        };
-        AnyDict eddie {
-            {"name", "Eddie"s},
-            {"age", INT64_C(36)},
-            {"assistant", donald},
-            {"team", AnyVec{donald, charley}}
-        };
-        Object obj = create_company(eddie, CreatePolicy::UpdateAll);
-
-        auto table = r->read_group().get_table("class_person");
-        REQUIRE(table->size() == 5);
-        Results result(r, table);
-        auto token = result.add_notification_callback([&](CollectionChangeSet c, std::exception_ptr) {
-            change = c;
-            callback_called = true;
-        });
-        advance_and_notify(*r);
-
-        // First update unconditionally
-        create_company(eddie, CreatePolicy::UpdateAll);
-
-        callback_called = false;
-        advance_and_notify(*r);
-        REQUIRE(callback_called);
-        REQUIRE_INDICES(change.modifications, 0, 1, 2, 3, 4);
-
-        // Now, only update where differences (there should not be any diffs - so no update)
-        create_company(eddie, CreatePolicy::UpdateModified);
-
-        REQUIRE(table->size() == 5);
-        callback_called = false;
-        advance_and_notify(*r);
-        REQUIRE(!callback_called);
-
-        // Now, only update sub-object)
-        donald["scores"] = AnyVec{INT64_C(3), INT64_C(4), INT64_C(5)};
-        // Insert the new donald
-        eddie["assistant"] = donald;
-        create_company(eddie, CreatePolicy::UpdateModified);
-
-        REQUIRE(table->size() == 5);
-        callback_called = false;
-        advance_and_notify(*r);
-        REQUIRE(callback_called);
-        REQUIRE_INDICES(change.modifications, 1);
-
-        // Shorten list
-        donald["scores"] = AnyVec{INT64_C(3), INT64_C(4)};
-        eddie["assistant"] = donald;
-        create_company(eddie, CreatePolicy::UpdateModified);
-
-        REQUIRE(table->size() == 5);
-        callback_called = false;
-        advance_and_notify(*r);
-        REQUIRE(callback_called);
-        REQUIRE_INDICES(change.modifications, 1);
-    }
-
-    SECTION("create with update - identical sub-object") {
-        Object sub_obj = create_sub(AnyDict{{"value", INT64_C(10)}});
-        Object obj = create(AnyDict{
-            {"pk", INT64_C(1)},
-            {"bool", true},
-            {"int", INT64_C(5)},
-            {"float", 2.2f},
-            {"double", 3.3},
-            {"string", "hello"s},
-            {"data", "olleh"s},
-            {"date", Timestamp(10, 20)},
-            {"object", sub_obj},
-        });
-
-        auto obj_table = r->read_group().get_table("class_all types");
-        Results result(r, obj_table);
-        bool callback_called;
-        bool results_callback_called;
-        bool sub_callback_called;
-        auto token1 = obj.add_notification_callback([&](CollectionChangeSet, std::exception_ptr) {
-            callback_called = true;
-        });
-        auto token2 = result.add_notification_callback([&](CollectionChangeSet, std::exception_ptr) {
-            results_callback_called = true;
-        });
-        auto token3 = sub_obj.add_notification_callback([&](CollectionChangeSet, std::exception_ptr) {
-            sub_callback_called = true;
-        });
-        advance_and_notify(*r);
-
-        auto table = r->read_group().get_table("class_link target");
-        REQUIRE(table->size() == 1);
-
-        create(AnyDict{
-            {"pk", INT64_C(1)},
-            {"bool", true},
-            {"int", INT64_C(5)},
-            {"float", 2.2f},
-            {"double", 3.3},
-            {"string", "hello"s},
-            {"data", "olleh"s},
-            {"date", Timestamp(10, 20)},
-            {"object", AnyDict{{"value", INT64_C(10)}}},
-        }, CreatePolicy::UpdateModified);
-
-        REQUIRE(table->size() == 1);
-        callback_called = false;
-        results_callback_called = false;
-        sub_callback_called = false;
-        advance_and_notify(*r);
-        REQUIRE(!callback_called);
-        REQUIRE(!results_callback_called);
-        REQUIRE(!sub_callback_called);
-
-        // Now change sub object
-        create(AnyDict{
-            {"pk", INT64_C(1)},
-            {"bool", true},
-            {"int", INT64_C(5)},
-            {"float", 2.2f},
-            {"double", 3.3},
-            {"string", "hello"s},
-            {"data", "olleh"s},
-            {"date", Timestamp(10, 20)},
-            {"object", AnyDict{{"value", INT64_C(11)}}},
-        }, CreatePolicy::UpdateModified);
-
-        callback_called = false;
-        results_callback_called = false;
-        sub_callback_called = false;
-        advance_and_notify(*r);
-        REQUIRE(!callback_called);
-        REQUIRE(results_callback_called);
-        REQUIRE(sub_callback_called);
-    }
-
-    SECTION("create with update - identical array of sub-objects") {
-        bool callback_called;
-        auto dict = AnyDict{
-            {"pk", INT64_C(1)},
-            {"bool", true},
-            {"int", INT64_C(5)},
-            {"float", 2.2f},
-            {"double", 3.3},
-            {"string", "hello"s},
-            {"data", "olleh"s},
-            {"date", Timestamp(10, 20)},
-            {"object array", AnyVec{AnyDict{{"value", INT64_C(20)}}, AnyDict{{"value", INT64_C(21)}}}},
-        };
-        Object obj = create(dict);
-
-        auto obj_table = r->read_group().get_table("class_all types");
-        Results result(r, obj_table);
-        auto token1 = result.add_notification_callback([&](CollectionChangeSet, std::exception_ptr) {
-            callback_called = true;
-        });
-        advance_and_notify(*r);
-
-        create(dict, CreatePolicy::UpdateModified);
-
-        callback_called = false;
-        advance_and_notify(*r);
-        REQUIRE(!callback_called);
-
-        // Now change list
-        dict["object array"] = AnyVec{AnyDict{{"value", INT64_C(23)}}};
-        create(dict, CreatePolicy::UpdateModified);
-
-        callback_called = false;
-        advance_and_notify(*r);
-        REQUIRE(callback_called);
-    }
-
-    for (auto policy : {CreatePolicy::UpdateAll, CreatePolicy::UpdateModified}) {
-        SECTION("set existing fields to null with update "s + (policy == CreatePolicy::UpdateModified ? "(diffed)" : "(all)")) {
-            AnyDict initial_values{
-                {"pk", INT64_C(1)},
-                {"bool", true},
-                {"int", INT64_C(5)},
-                {"float", 2.2f},
-                {"double", 3.3},
-                {"string", "hello"s},
-                {"data", "olleh"s},
-                {"date", Timestamp(10, 20)},
-
-                {"bool array", AnyVec{true, false}},
-                {"int array", AnyVec{INT64_C(5), INT64_C(6)}},
-                {"float array", AnyVec{1.1f, 2.2f}},
-                {"double array", AnyVec{3.3, 4.4}},
-                {"string array", AnyVec{"a"s, "b"s, "c"s}},
-                {"data array", AnyVec{"d"s, "e"s, "f"s}},
-                {"date array", AnyVec{}},
-                {"object array", AnyVec{AnyDict{{"value", INT64_C(20)}}}},
-            };
-            r->begin_transaction();
-            auto obj = Object::create(d, r, *r->schema().find("all optional types"), util::Any(initial_values));
-
-            // Missing fields in dictionary do not update anything
-            Object::create(d, r, *r->schema().find("all optional types"),
-                           util::Any(AnyDict{{"pk", INT64_C(1)}}), policy);
-
-            REQUIRE(any_cast<bool>(obj.get_property_value<util::Any>(d, "bool")) == true);
-            REQUIRE(any_cast<int64_t>(obj.get_property_value<util::Any>(d, "int")) == 5);
-            REQUIRE(any_cast<float>(obj.get_property_value<util::Any>(d, "float")) == 2.2f);
-            REQUIRE(any_cast<double>(obj.get_property_value<util::Any>(d, "double")) == 3.3);
-            REQUIRE(any_cast<std::string>(obj.get_property_value<util::Any>(d, "string")) == "hello");
-            REQUIRE(any_cast<Timestamp>(obj.get_property_value<util::Any>(d, "date")) == Timestamp(10, 20));
-
-            REQUIRE(any_cast<List&&>(obj.get_property_value<util::Any>(d, "bool array")).get<util::Optional<bool>>(0) == true);
-            REQUIRE(any_cast<List&&>(obj.get_property_value<util::Any>(d, "int array")).get<util::Optional<int64_t>>(0) == 5);
-            REQUIRE(any_cast<List&&>(obj.get_property_value<util::Any>(d, "float array")).get<util::Optional<float>>(0) == 1.1f);
-            REQUIRE(any_cast<List&&>(obj.get_property_value<util::Any>(d, "double array")).get<util::Optional<double>>(0) == 3.3);
-            REQUIRE(any_cast<List&&>(obj.get_property_value<util::Any>(d, "string array")).get<StringData>(0) == "a");
-            REQUIRE(any_cast<List&&>(obj.get_property_value<util::Any>(d, "date array")).size() == 0);
-
-            // Set all properties to null
-            AnyDict null_values{
-                {"pk", INT64_C(1)},
-                {"bool", util::Any()},
-                {"int", util::Any()},
-                {"float", util::Any()},
-                {"double", util::Any()},
-                {"string", util::Any()},
-                {"data", util::Any()},
-                {"date", util::Any()},
-
-                {"bool array", AnyVec{util::Any()}},
-                {"int array", AnyVec{util::Any()}},
-                {"float array", AnyVec{util::Any()}},
-                {"double array", AnyVec{util::Any()}},
-                {"string array", AnyVec{util::Any()}},
-                {"data array", AnyVec{util::Any()}},
-                {"date array", AnyVec{Timestamp()}},
-            };
-            Object::create(d, r, *r->schema().find("all optional types"), util::Any(null_values), policy);
-
-            REQUIRE_FALSE(obj.get_property_value<util::Any>(d, "bool").has_value());
-            REQUIRE_FALSE(obj.get_property_value<util::Any>(d, "int").has_value());
-            REQUIRE_FALSE(obj.get_property_value<util::Any>(d, "float").has_value());
-            REQUIRE_FALSE(obj.get_property_value<util::Any>(d, "double").has_value());
-            REQUIRE_FALSE(obj.get_property_value<util::Any>(d, "string").has_value());
-            REQUIRE_FALSE(obj.get_property_value<util::Any>(d, "data").has_value());
-            REQUIRE_FALSE(obj.get_property_value<util::Any>(d, "date").has_value());
-
-            REQUIRE(any_cast<List&&>(obj.get_property_value<util::Any>(d, "bool array")).get<util::Optional<bool>>(0) == util::none);
-            REQUIRE(any_cast<List&&>(obj.get_property_value<util::Any>(d, "int array")).get<util::Optional<int64_t>>(0) == util::none);
-            REQUIRE(any_cast<List&&>(obj.get_property_value<util::Any>(d, "float array")).get<util::Optional<float>>(0) == util::none);
-            REQUIRE(any_cast<List&&>(obj.get_property_value<util::Any>(d, "double array")).get<util::Optional<double>>(0) == util::none);
-            REQUIRE(any_cast<List&&>(obj.get_property_value<util::Any>(d, "string array")).get<StringData>(0) == StringData());
-            REQUIRE(any_cast<List&&>(obj.get_property_value<util::Any>(d, "data array")).get<BinaryData>(0) == BinaryData());
-            REQUIRE(any_cast<List&&>(obj.get_property_value<util::Any>(d, "date array")).get<Timestamp>(0) == Timestamp());
-
-            // Set all properties back to non-null
-            Object::create(d, r, *r->schema().find("all optional types"), util::Any(initial_values), policy);
-            REQUIRE(any_cast<bool>(obj.get_property_value<util::Any>(d, "bool")) == true);
-            REQUIRE(any_cast<int64_t>(obj.get_property_value<util::Any>(d, "int")) == 5);
-            REQUIRE(any_cast<float>(obj.get_property_value<util::Any>(d, "float")) == 2.2f);
-            REQUIRE(any_cast<double>(obj.get_property_value<util::Any>(d, "double")) == 3.3);
-            REQUIRE(any_cast<std::string>(obj.get_property_value<util::Any>(d, "string")) == "hello");
-            REQUIRE(any_cast<Timestamp>(obj.get_property_value<util::Any>(d, "date")) == Timestamp(10, 20));
-
-            REQUIRE(any_cast<List&&>(obj.get_property_value<util::Any>(d, "bool array")).get<util::Optional<bool>>(0) == true);
-            REQUIRE(any_cast<List&&>(obj.get_property_value<util::Any>(d, "int array")).get<util::Optional<int64_t>>(0) == 5);
-            REQUIRE(any_cast<List&&>(obj.get_property_value<util::Any>(d, "float array")).get<util::Optional<float>>(0) == 1.1f);
-            REQUIRE(any_cast<List&&>(obj.get_property_value<util::Any>(d, "double array")).get<util::Optional<double>>(0) == 3.3);
-            REQUIRE(any_cast<List&&>(obj.get_property_value<util::Any>(d, "string array")).get<StringData>(0) == "a");
-            REQUIRE(any_cast<List&&>(obj.get_property_value<util::Any>(d, "date array")).size() == 0);
-        }
-    }
-
-    SECTION("create throws for duplicate pk if update is not specified") {
-        create(AnyDict{
-            {"pk", INT64_C(1)},
-            {"bool", true},
-            {"int", INT64_C(5)},
-            {"float", 2.2f},
-            {"double", 3.3},
-            {"string", "hello"s},
-            {"data", "olleh"s},
-            {"date", Timestamp(10, 20)},
-            {"object", AnyDict{{"value", INT64_C(10)}}},
-            {"array", AnyVector{AnyDict{{"value", INT64_C(20)}}}},
-        });
-        REQUIRE_THROWS(create(AnyDict{
-            {"pk", INT64_C(1)},
-            {"bool", true},
-            {"int", INT64_C(5)},
-            {"float", 2.2f},
-            {"double", 3.3},
-            {"string", "hello"s},
-            {"data", "olleh"s},
-            {"date", Timestamp(10, 20)},
-            {"object", AnyDict{{"value", INT64_C(10)}}},
-            {"array", AnyVector{AnyDict{{"value", INT64_C(20)}}}},
-        }));
-    }
-
-    SECTION("create with explicit null pk does not fall back to default") {
-        d.defaults["nullable int pk"] = {
-            {"pk", INT64_C(10)},
-        };
-        d.defaults["nullable string pk"] = {
-            {"pk", "value"s},
-        };
-        auto create = [&](util::Any&& value, StringData type) {
-            r->begin_transaction();
-            auto obj = Object::create(d, r, *r->schema().find(type), value);
-            r->commit_transaction();
-            return obj;
-        };
-
-        auto obj = create(AnyDict{{"pk", d.null_value()}}, "nullable int pk");
-        auto col_pk_int = r->read_group().get_table("class_nullable int pk")->get_column_key("pk");
-        auto col_pk_str = r->read_group().get_table("class_nullable string pk")->get_column_key("pk");
-        REQUIRE(obj.obj().is_null(col_pk_int));
-        obj = create(AnyDict{{"pk", d.null_value()}}, "nullable string pk");
-        REQUIRE(obj.obj().is_null(col_pk_str));
-
-        obj = create(AnyDict{{}}, "nullable int pk");
-        REQUIRE(obj.obj().get<util::Optional<Int>>(col_pk_int) == 10);
-        obj = create(AnyDict{{}}, "nullable string pk");
-        REQUIRE(obj.obj().get<String>(col_pk_str) == "value");
-    }
-
-    SECTION("getters and setters") {
-        r->begin_transaction();
-
-        auto table = r->read_group().get_table("class_all types");
-        table->create_object();
-        Object obj(r, *r->schema().find("all types"), *table->begin());
-
-        auto link_table = r->read_group().get_table("class_link target");
-        link_table->create_object();
-        Object linkobj(r, *r->schema().find("link target"), *link_table->begin());
-
-        obj.set_property_value(d, "bool", util::Any(true));
-        REQUIRE(any_cast<bool>(obj.get_property_value<util::Any>(d, "bool")) == true);
-
-        obj.set_property_value(d, "int", util::Any(INT64_C(5)));
-        REQUIRE(any_cast<int64_t>(obj.get_property_value<util::Any>(d, "int")) == 5);
-
-        obj.set_property_value(d, "float", util::Any(1.23f));
-        REQUIRE(any_cast<float>(obj.get_property_value<util::Any>(d, "float")) == 1.23f);
-
-        obj.set_property_value(d, "double", util::Any(1.23));
-        REQUIRE(any_cast<double>(obj.get_property_value<util::Any>(d, "double")) == 1.23);
-
-        obj.set_property_value(d, "string", util::Any("abc"s));
-        REQUIRE(any_cast<std::string>(obj.get_property_value<util::Any>(d, "string")) == "abc");
-
-        obj.set_property_value(d, "data", util::Any("abc"s));
-        REQUIRE(any_cast<std::string>(obj.get_property_value<util::Any>(d, "data")) == "abc");
-
-        obj.set_property_value(d, "date", util::Any(Timestamp(1, 2)));
-        REQUIRE(any_cast<Timestamp>(obj.get_property_value<util::Any>(d, "date")) == Timestamp(1, 2));
-
-        REQUIRE_FALSE(obj.get_property_value<util::Any>(d, "object").has_value());
-        obj.set_property_value(d, "object", util::Any(linkobj));
-        REQUIRE(any_cast<Object>(obj.get_property_value<util::Any>(d, "object")).obj().get_key() == linkobj.obj().get_key());
-
-        auto linking = any_cast<Results>(linkobj.get_property_value<util::Any>(d, "origin"));
-        REQUIRE(linking.size() == 1);
-
-        REQUIRE_THROWS(obj.set_property_value(d, "pk", util::Any(INT64_C(5))));
-        REQUIRE_THROWS(obj.set_property_value(d, "not a property", util::Any(INT64_C(5))));
-
-        r->commit_transaction();
-
-        REQUIRE_THROWS(obj.get_property_value<util::Any>(d, "not a property"));
-        REQUIRE_THROWS(obj.set_property_value(d, "int", util::Any(INT64_C(5))));
-    }
-
-    SECTION("list property self-assign is a no-op") {
-        auto obj = create(AnyDict{
-            {"pk", INT64_C(1)},
-            {"bool", true},
-            {"int", INT64_C(5)},
-            {"float", 2.2f},
-            {"double", 3.3},
-            {"string", "hello"s},
-            {"data", "olleh"s},
-            {"date", Timestamp(10, 20)},
-
-            {"bool array", AnyVec{true, false}},
-            {"object array", AnyVec{AnyDict{{"value", INT64_C(20)}}}},
-        });
-
-        REQUIRE(any_cast<List&&>(obj.get_property_value<util::Any>(d, "bool array")).size() == 2);
-        REQUIRE(any_cast<List&&>(obj.get_property_value<util::Any>(d, "object array")).size() == 1);
-
-        r->begin_transaction();
-        obj.set_property_value(d, "bool array", obj.get_property_value<util::Any>(d, "bool array"));
-        obj.set_property_value(d, "object array", obj.get_property_value<util::Any>(d, "object array"));
-        r->commit_transaction();
-
-        REQUIRE(any_cast<List&&>(obj.get_property_value<util::Any>(d, "bool array")).size() == 2);
-        REQUIRE(any_cast<List&&>(obj.get_property_value<util::Any>(d, "object array")).size() == 1);
-    }
-
-#if REALM_ENABLE_SYNC
-    if (!util::EventLoop::has_implementation())
-        return;
-
-    SyncServer server(false);
-    SyncTestFile config1(server, "shared");
-    config1.schema = config.schema;
-    SyncTestFile config2(server, "shared");
-    config2.schema = config.schema;
-
-    SECTION("defaults do not override values explicitly passed to create()") {
-        AnyDict v1{
-            {"pk", INT64_C(7)},
-            {"array 1", AnyVector{AnyDict{{"value", INT64_C(1)}}}},
-            {"array 2", AnyVector{AnyDict{{"value", INT64_C(2)}}}},
-        };
-        auto v2 = v1;
-        v1["int 1"] = INT64_C(1);
-        v2["int 2"] = INT64_C(2);
-
-        auto r1 = Realm::get_shared_realm(config1);
-        auto r2 = Realm::get_shared_realm(config2);
-
-        TestContext c1(r1);
-        TestContext c2(r2);
-
-        c1.defaults["pk after list"] = {
-            {"int 1", INT64_C(10)},
-            {"int 2", INT64_C(10)},
-        };
-        c2.defaults = c1.defaults;
-
-        r1->begin_transaction();
-        r2->begin_transaction();
-        auto object1 = Object::create(c1, r1, *r1->schema().find("pk after list"), util::Any(v1));
-        auto object2 = Object::create(c2, r2, *r2->schema().find("pk after list"), util::Any(v2));
-        r2->commit_transaction();
-        r1->commit_transaction();
-
-        server.start();
-        util::EventLoop::main().run_until([&] {
-            return r1->read_group().get_table("class_array target")->size() == 4;
-        });
-
-        Obj obj = object1.obj();
-        REQUIRE(obj.get<Int>("pk") == 7); // pk
-        REQUIRE(obj.get_linklist("array 1").size() == 2);
-        REQUIRE(obj.get<Int>("int 1") == 1); // non-default from r1
-        REQUIRE(obj.get<Int>("int 2") == 2); // non-default from r2
-        REQUIRE(obj.get_linklist("array 2").size() == 2);
-
-    }
-#endif
-}

+ 0 - 77
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/object_store.cpp

@@ -1,77 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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 "catch2/catch.hpp"
-
-#include "util/test_file.hpp"
-
-#include "object_schema.hpp"
-#include "object_store.hpp"
-#include "property.hpp"
-#include "schema.hpp"
-
-#include <realm/string_data.hpp>
-#include <realm/table.hpp>
-
-using namespace realm;
-
-TEST_CASE("ObjectStore: table_name_for_object_type()") {
-    SECTION("should work with strings that aren't null-terminated") {
-        auto input = StringData("good_no_bad", 4);
-        auto result = ObjectStore::table_name_for_object_type(input);
-        REQUIRE(result == "class_good");
-    }
-}
-
-TEST_CASE("ObjectStore:: property_for_column_index()") {
-    SECTION("Property should match the schema") {
-        Schema schema = {
-            {"object", {
-                {"int", PropertyType::Int},
-                {"boolNullable", PropertyType::Bool | PropertyType::Nullable},
-                {"stringPK", PropertyType::String, true},
-                {"dateNullableIndexed", PropertyType::Date | PropertyType::Nullable, false, true},
-                {"floatNullableArray", PropertyType::Float | PropertyType::Nullable | PropertyType::Array},
-                {"doubleArray", PropertyType::Double | PropertyType::Array},
-                {"object", PropertyType::Object | PropertyType::Nullable, "object"},
-                {"objectArray", PropertyType::Object | PropertyType::Array, "object"},
-            }}
-        };
-
-        TestFile config;
-        config.schema = schema;
-        config.schema_version = 1;
-
-        auto realm = Realm::get_shared_realm(config);
-        ConstTableRef table = ObjectStore::table_for_object_type(realm->read_group(), "object");
-        auto it = realm->schema().find("object");
-        REQUIRE_FALSE(it == realm->schema().end());
-        ObjectSchema object_schema = *it;
-
-        auto all_columns = table->get_column_keys();
-        for (auto col : all_columns) {
-            auto property = ObjectStore::property_for_column_index(table, col);
-            if (!property) {
-                FAIL();
-                continue;
-            }
-            auto actual_property = *object_schema.property_for_name(property->name);
-            REQUIRE(property.value() == actual_property);
-        }
-   }
-}

+ 0 - 857
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/primitive_list.cpp

@@ -1,857 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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 "catch2/catch.hpp"
-
-#include "util/event_loop.hpp"
-#include "util/index_helpers.hpp"
-#include "util/test_file.hpp"
-
-#include "binding_context.hpp"
-#include "list.hpp"
-#include "object.hpp"
-#include "object_schema.hpp"
-#include "property.hpp"
-#include "results.hpp"
-#include "schema.hpp"
-#include "thread_safe_reference.hpp"
-
-#include "impl/realm_coordinator.hpp"
-#include "impl/object_accessor_impl.hpp"
-
-#include <realm/db.hpp>
-#include <realm/query_expression.hpp>
-#include <realm/version.hpp>
-
-#include <numeric>
-
-using namespace realm;
-
-
-template<PropertyType prop_type, typename T>
-struct Base {
-    using Type = T;
-    using Wrapped = T;
-    using Boxed = T;
-    enum { is_optional = false };
-
-    static PropertyType property_type() { return prop_type; }
-    static util::Any to_any(T value) { return value; }
-
-    template<typename Fn>
-    static auto unwrap(T value, Fn&& fn) { return fn(value); }
-
-    static T min() { abort(); }
-    static T max() { abort(); }
-    static T sum() { abort(); }
-    static double average() { abort(); }
-
-    static bool can_sum() { return std::is_arithmetic<T>::value; }
-    static bool can_average() { return std::is_arithmetic<T>::value; }
-    static bool can_minmax() { return std::is_arithmetic<T>::value; }
-};
-
-struct Int : Base<PropertyType::Int, int64_t> {
-    static std::vector<int64_t> values() { return {3, 1, 2}; }
-    static int64_t min() { return 1; }
-    static int64_t max() { return 3; }
-    static int64_t sum() { return 6; }
-    static double average() { return 2.0; }
-};
-
-struct Bool : Base<PropertyType::Bool, bool> {
-    static std::vector<bool> values() { return {true, false}; }
-    static bool can_sum() { return false; }
-    static bool can_average() { return false; }
-    static bool can_minmax() { return false; }
-};
-
-struct Float : Base<PropertyType::Float, float> {
-    static std::vector<float> values() { return {3.3f, 1.1f, 2.2f}; }
-    static float min() { return 1.1f; }
-    static float max() { return 3.3f; }
-    static auto sum() { return Approx(6.6f); }
-    static auto average() { return Approx(2.2f); }
-};
-
-struct Double : Base<PropertyType::Double, double> {
-    static std::vector<double> values() { return {3.3, 1.1, 2.2}; }
-    static double min() { return 1.1; }
-    static double max() { return 3.3; }
-    static auto sum() { return Approx(6.6); }
-    static auto average() { return Approx(2.2); }
-};
-
-struct String : Base<PropertyType::String, StringData> {
-    using Boxed = std::string;
-    static std::vector<StringData> values() { return {"c", "a", "b"}; }
-    static util::Any to_any(StringData value) { return value ? std::string(value) : util::Any(); }
-};
-
-struct Binary : Base<PropertyType::Data, BinaryData> {
-    using Boxed = std::string;
-    static util::Any to_any(BinaryData value) { return value ? std::string(value) : util::Any(); }
-    static std::vector<BinaryData> values()
-    {
-        return {BinaryData("c", 1), BinaryData("a", 1), BinaryData("b", 1)};
-    }
-};
-
-struct Date : Base<PropertyType::Date, Timestamp> {
-    static std::vector<Timestamp> values()
-    {
-        return {Timestamp(3, 3), Timestamp(1, 1), Timestamp(2, 2)};
-    }
-    static bool can_minmax() { return true; }
-    static Timestamp min() { return Timestamp(1, 1); }
-    static Timestamp max() { return Timestamp(3, 3); }
-};
-
-template<typename BaseT>
-struct BoxedOptional : BaseT {
-    using Type = util::Optional<typename BaseT::Type>;
-    using Boxed = Type;
-    enum { is_optional = true };
-
-    static PropertyType property_type() { return BaseT::property_type()|PropertyType::Nullable; }
-    static std::vector<Type> values()
-    {
-        std::vector<Type> ret;
-        for (auto v : BaseT::values())
-            ret.push_back(Type(v));
-        ret.push_back(util::none);
-        return ret;
-    }
-    static auto unwrap(Type value) { return *value; }
-    static util::Any to_any(Type value) { return value ? util::Any(*value) : util::Any(); }
-
-    template<typename Fn>
-    static auto unwrap(Type value, Fn&& fn) { return value ? fn(*value) : fn(null()); }
-};
-
-template<typename BaseT>
-struct UnboxedOptional : BaseT {
-    enum { is_optional = true };
-    static PropertyType property_type() { return BaseT::property_type()|PropertyType::Nullable; }
-    static auto values() -> decltype(BaseT::values())
-    {
-        auto ret = BaseT::values();
-        ret.push_back(typename BaseT::Type());
-        return ret;
-    }
-};
-
-template<typename T>
-T get(Mixed) { abort(); }
-
-template<> int64_t get(Mixed m) { return m.get_int(); }
-template<> float get(Mixed m) { return m.get_type() == type_Float ? m.get_float() : static_cast<float>(m.get_double()); }
-template<> double get(Mixed m) { return m.get_double(); }
-template<> Timestamp get(Mixed m) { return m.get_timestamp(); }
-
-namespace realm {
-template<typename T>
-bool operator==(List const& list, std::vector<T> const& values) {
-    if (list.size() != values.size())
-        return false;
-    for (size_t i = 0; i < values.size(); ++i) {
-        if (list.get<T>(i) != values[i])
-            return false;
-    }
-    return true;
-}
-
-template<typename T>
-bool operator==(Results const& results, std::vector<T> const& values) {
-    // FIXME: this is only necessary because Results::size() and ::get() are not const
-    Results copy{results};
-    if (copy.size() != values.size())
-        return false;
-    for (size_t i = 0; i < values.size(); ++i) {
-        if (copy.get<T>(i) != values[i])
-            return false;
-    }
-    return true;
-}
-
-}
-
-struct StringifyingContext {
-    template<typename T>
-    std::string box(T value)
-    {
-        std::stringstream ss;
-        ss << value;
-        return ss.str();
-    }
-
-    std::string box(Obj obj) { return util::to_string(obj.get_key().value); }
-};
-
-namespace Catch {
-template<>
-struct StringMaker<List> {
-    static std::string convert(List const& list)
-    {
-        std::stringstream ss;
-        auto type = list.get_type();
-        ss << string_for_property_type(type & ~PropertyType::Flags);
-        if (is_nullable(type))
-            ss << "?";
-        ss << "{";
-
-        StringifyingContext ctx;
-        for (size_t i = 0, count = list.size(); i < count; ++i)
-            ss << list.get(ctx, i) << ", ";
-        auto str = ss.str();
-        str.pop_back();
-        str.back() = '}';
-        return str;
-    }
-};
-template<>
-struct StringMaker<Results> {
-    static std::string convert(Results const& r)
-    {
-        auto& results = const_cast<Results&>(r);
-        std::stringstream ss;
-        auto type = results.get_type();
-        ss << string_for_property_type(type & ~PropertyType::Flags);
-        if (is_nullable(type))
-            ss << "?";
-        ss << "{";
-
-        StringifyingContext ctx;
-        for (size_t i = 0, count = results.size(); i < count; ++i)
-            ss << results.get(ctx, i) << ", ";
-        auto str = ss.str();
-        str.pop_back();
-        str.back() = '}';
-        return str;
-    }
-};
-template<>
-struct StringMaker<util::None> {
-    static std::string convert(util::None)
-    {
-        return "[none]";
-    }
-};
-} // namespace Catch
-
-struct less {
-    template<class T, class U>
-    auto operator()(T&& a, U&& b) const noexcept { return a < b; }
-};
-struct greater {
-    template<class T, class U>
-    auto operator()(T&& a, U&& b) const noexcept { return a > b; }
-};
-
-template<>
-auto less::operator()<Timestamp&, Timestamp&>(Timestamp& a, Timestamp& b) const noexcept
-{
-    if (b.is_null())
-        return false;
-    if (a.is_null())
-        return true;
-    return a < b;
-}
-
-template<>
-auto greater::operator()<Timestamp&, Timestamp&>(Timestamp& a, Timestamp& b) const noexcept
-{
-    if (a.is_null())
-        return false;
-    if (b.is_null())
-        return true;
-    return a > b;
-}
-
-TEMPLATE_TEST_CASE("primitive list", "[primitives]", ::Int, ::Bool, ::Float, ::Double, ::String, ::Binary, ::Date,
-                   BoxedOptional<::Int>, BoxedOptional<::Bool>, BoxedOptional<::Float>, BoxedOptional<::Double>,
-                   UnboxedOptional<::String>, UnboxedOptional<::Binary>, UnboxedOptional<::Date>)
-{
-    auto values = TestType::values();
-    using T = typename TestType::Type;
-    using W = typename TestType::Wrapped;
-    using Boxed = typename TestType::Boxed;
-
-    InMemoryTestFile config;
-    config.automatic_change_notifications = false;
-    config.schema = Schema{
-        {"object", {
-            {"value", PropertyType::Array|TestType::property_type()}
-        }},
-    };
-    auto r = Realm::get_shared_realm(config);
-    auto r2 = Realm::get_shared_realm(config);
-
-    auto table = r->read_group().get_table("class_object");
-    auto table2 = r2->read_group().get_table("class_object");
-    r->begin_transaction();
-    Obj obj = table->create_object();
-    ColKey col = table->get_column_key("value");
-
-    List list(r, obj, col);
-    auto results = list.as_results();
-    CppContext ctx(r);
-
-    SECTION("get_realm()") {
-        REQUIRE(list.get_realm() == r);
-        REQUIRE(results.get_realm() == r);
-    }
-#if 0
-    SECTION("get_query()") {
-        REQUIRE(list.get_query().count() == 0);
-        REQUIRE(results.get_query().count() == 0);
-        list.add(static_cast<T>(values[0]));
-        REQUIRE(list.get_query().count() == 1);
-        REQUIRE(results.get_query().count() == 1);
-    }
-#endif
-    SECTION("get_origin_row_index()") {
-        REQUIRE(list.get_parent_object_key() == obj.get_key());
-        table->create_object();
-        REQUIRE(list.get_parent_object_key() == obj.get_key());
-    }
-
-    SECTION("get_type()") {
-        REQUIRE(list.get_type() == TestType::property_type());
-        REQUIRE(results.get_type() == TestType::property_type());
-    }
-
-    SECTION("get_object_type()") {
-        REQUIRE(results.get_object_type() == StringData());
-    }
-
-    SECTION("is_valid()") {
-        REQUIRE(list.is_valid());
-        REQUIRE(results.is_valid());
-
-        SECTION("invalidate") {
-            r->invalidate();
-            REQUIRE_FALSE(list.is_valid());
-            REQUIRE_FALSE(results.is_valid());
-        }
-
-        SECTION("close") {
-            r->close();
-            REQUIRE_FALSE(list.is_valid());
-            REQUIRE_FALSE(results.is_valid());
-        }
-
-        SECTION("delete row") {
-            obj.remove();
-            REQUIRE_FALSE(list.is_valid());
-            REQUIRE_FALSE(results.is_valid());
-        }
-
-        SECTION("rollback transaction creating list") {
-            r->cancel_transaction();
-            REQUIRE_FALSE(list.is_valid());
-            REQUIRE_FALSE(results.is_valid());
-        }
-    }
-
-    SECTION("verify_attached()") {
-        REQUIRE_NOTHROW(list.verify_attached());
-
-        SECTION("invalidate") {
-            r->invalidate();
-            REQUIRE_THROWS(list.verify_attached());
-        }
-
-        SECTION("close") {
-            r->close();
-            REQUIRE_THROWS(list.verify_attached());
-        }
-
-        SECTION("delete row") {
-            obj.remove();
-            REQUIRE_THROWS(list.verify_attached());
-        }
-
-        SECTION("rollback transaction creating list") {
-            r->cancel_transaction();
-            REQUIRE_THROWS(list.verify_attached());
-        }
-    }
-
-    SECTION("verify_in_transaction()") {
-        REQUIRE_NOTHROW(list.verify_in_transaction());
-
-        SECTION("invalidate") {
-            r->invalidate();
-            REQUIRE_THROWS(list.verify_in_transaction());
-        }
-
-        SECTION("close") {
-            r->close();
-            REQUIRE_THROWS(list.verify_in_transaction());
-        }
-
-        SECTION("delete row") {
-            obj.remove();
-            REQUIRE_THROWS(list.verify_in_transaction());
-        }
-
-        SECTION("end write") {
-            r->commit_transaction();
-            REQUIRE_THROWS(list.verify_in_transaction());
-        }
-    }
-
-    if (!list.is_valid() || !r->is_in_transaction())
-        return;
-
-    for (T value : values)
-        list.add(value);
-
-    SECTION("move()") {
-        if (list.size() < 3)
-            return;
-
-        list.move(1, 2);
-        std::swap(values[1], values[2]);
-        REQUIRE(list == values);
-        REQUIRE(results == values);
-
-        list.move(2, 1);
-        std::swap(values[1], values[2]);
-        REQUIRE(list == values);
-        REQUIRE(results == values);
-
-        list.move(0, 2);
-        std::rotate(values.begin(), values.begin() + 1, values.begin() + 3);
-        REQUIRE(list == values);
-        REQUIRE(results == values);
-
-        list.move(2, 0);
-        std::rotate(values.begin(), values.begin() + 2, values.begin() + 3);
-        REQUIRE(list == values);
-        REQUIRE(results == values);
-    }
-
-    SECTION("remove()") {
-        if (list.size() < 3)
-            return;
-
-        list.remove(1);
-        values.erase(values.begin() + 1);
-        REQUIRE(list == values);
-        REQUIRE(results == values);
-    }
-
-    SECTION("remove_all()") {
-        list.remove_all();
-        REQUIRE(list.size() == 0);
-        REQUIRE(results.size() == 0);
-    }
-
-    SECTION("swap()") {
-        if (list.size() < 3)
-            return;
-
-        list.swap(0, 2);
-        std::swap(values[0], values[2]);
-        REQUIRE(list == values);
-        REQUIRE(results == values);
-    }
-
-    SECTION("delete_all()") {
-        list.delete_all();
-        REQUIRE(list.size() == 0);
-        REQUIRE(results.size() == 0);
-    }
-
-    SECTION("clear()") {
-        results.clear();
-        REQUIRE(list.size() == 0);
-        REQUIRE(results.size() == 0);
-    }
-
-    SECTION("get()") {
-        for (size_t i = 0; i < values.size(); ++i) {
-            CAPTURE(i);
-            REQUIRE(list.get<T>(i) == values[i]);
-            REQUIRE(results.get<T>(i) == values[i]);
-            REQUIRE(any_cast<Boxed>(list.get(ctx, i)) == Boxed(values[i]));
-            REQUIRE(any_cast<Boxed>(results.get(ctx, i)) == Boxed(values[i]));
-        }
-        REQUIRE_THROWS(list.get<T>(values.size()));
-        REQUIRE_THROWS(results.get<T>(values.size()));
-        REQUIRE_THROWS(list.get(ctx, values.size()));
-        REQUIRE_THROWS(results.get(ctx, values.size()));
-    }
-
-    SECTION("first()") {
-        REQUIRE(*results.first<T>() == values.front());
-        REQUIRE(any_cast<Boxed>(*results.first(ctx)) == Boxed(values.front()));
-        list.remove_all();
-        REQUIRE(results.first<T>() == util::none);
-    }
-
-    SECTION("last()") {
-        REQUIRE(*results.last<T>() == values.back());
-        list.remove_all();
-        REQUIRE(results.last<T>() == util::none);
-    }
-
-    SECTION("set()") {
-        for (size_t i = 0; i < values.size(); ++i) {
-            CAPTURE(i);
-            auto rev = values.size() - i - 1;
-            list.set(i, static_cast<T>(values[rev]));
-            REQUIRE(list.get<T>(i) == values[rev]);
-            REQUIRE(results.get<T>(i) == values[rev]);
-        }
-        for (size_t i = 0; i < values.size(); ++i) {
-            CAPTURE(i);
-            list.set(ctx, i, TestType::to_any(values[i]));
-            REQUIRE(list.get<T>(i) == values[i]);
-            REQUIRE(results.get<T>(i) == values[i]);
-        }
-
-        REQUIRE_THROWS(list.set(list.size(), static_cast<T>(values[0])));
-    }
-
-    SECTION("find()") {
-        for (size_t i = 0; i < values.size(); ++i) {
-            CAPTURE(i);
-            REQUIRE(list.find<T>(values[i]) == i);
-            REQUIRE(results.index_of<T>(values[i]) == i);
-
-            REQUIRE(list.find(ctx, TestType::to_any(values[i])) == i);
-            REQUIRE(results.index_of(ctx, TestType::to_any(values[i])) == i);
-#if 0
-            auto q = TestType::unwrap(values[i], [&] (auto v) { return table->get_subtable(0, 0)->column<W>(0) == v; });
-            REQUIRE(list.find(Query(q)) == i);
-            REQUIRE(results.index_of(std::move(q)) == i);
-#endif
-        }
-
-        list.remove(0);
-        REQUIRE(list.find(static_cast<T>(values[0])) == npos);
-        REQUIRE(results.index_of(static_cast<T>(values[0])) == npos);
-
-        REQUIRE(list.find(ctx, TestType::to_any(values[0])) == npos);
-        REQUIRE(results.index_of(ctx, TestType::to_any(values[0])) == npos);
-    }
-    SECTION("sorted index_of()") {
-        auto sorted = list.sort({{"self", true}});
-        std::sort(begin(values), end(values), less());
-        for (size_t i = 0; i < values.size(); ++i) {
-            CAPTURE(i);
-            REQUIRE(sorted.index_of<T>(values[i]) == i);
-        }
-
-        sorted = list.sort({{"self", false}});
-        std::sort(begin(values), end(values), greater());
-        for (size_t i = 0; i < values.size(); ++i) {
-            CAPTURE(i);
-            REQUIRE(sorted.index_of<T>(values[i]) == i);
-        }
-    }
-
-#if 0
-    SECTION("filtered index_of()") {
-        REQUIRE_THROWS(results.index_of(table->get(0)));
-        auto q = TestType::unwrap(values[0], [&] (auto v) { return table->get_subtable(0, 0)->column<W>(0) != v; });
-        auto filtered = list.filter(std::move(q));
-        for (size_t i = 1; i < values.size(); ++i) {
-            CAPTURE(i);
-            REQUIRE(filtered.index_of(static_cast<T>(values[i])) == i - 1);
-        }
-    }
-#endif
-    SECTION("sort()") {
-        auto unsorted = list.sort(std::vector<std::pair<std::string, bool>>{});
-        REQUIRE(unsorted == values);
-
-        auto sorted = list.sort(SortDescriptor({{col}}, {true}));
-        auto sorted2 = list.sort({{"self", true}});
-        std::sort(begin(values), end(values), less());
-        REQUIRE(sorted == values);
-        REQUIRE(sorted2 == values);
-
-        sorted = list.sort(SortDescriptor({{col}}, {false}));
-        sorted2 = list.sort({{"self", false}});
-        std::sort(begin(values), end(values), greater());
-        REQUIRE(sorted == values);
-        REQUIRE(sorted2 == values);
-
-        auto execption_string =
-            util::format("Cannot sort on key path 'not self': arrays of '%1' can only be sorted on 'self'",
-                         string_for_property_type(TestType::property_type() & ~PropertyType::Flags));
-        REQUIRE_THROWS_WITH(list.sort({{"not self", true}}), execption_string);
-        REQUIRE_THROWS_WITH(list.sort({{"self", true}, {"self", false}}),
-                            util::format("Cannot sort array of '%1' on more than one key path",
-                                         string_for_property_type(TestType::property_type() & ~PropertyType::Flags)));
-    }
-
-    SECTION("distinct()") {
-        for (T value : values)
-            list.add(value);
-        auto values2 = values;
-        values2.insert(values2.end(), values.begin(), values.end());
-
-        auto undistinct = list.as_results().distinct(std::vector<std::string>{});
-        REQUIRE(undistinct == values2);
-
-        auto distinct = results.distinct(DistinctDescriptor({{col}}));
-        auto distinct2 = results.distinct({"self"});
-        REQUIRE(distinct == values);
-        REQUIRE(distinct2 == values);
-
-        REQUIRE_THROWS_WITH(results.distinct({{"not self"}}),
-                            util::format("Cannot sort on key path 'not self': arrays of '%1' can only be sorted on 'self'",
-                                         string_for_property_type(TestType::property_type() & ~PropertyType::Flags)));
-        REQUIRE_THROWS_WITH(results.distinct({{"self"}, {"self"}}),
-                            util::format("Cannot sort array of '%1' on more than one key path",
-                                         string_for_property_type(TestType::property_type() & ~PropertyType::Flags)));
-    }
-
-#if 0
-    SECTION("filter()") {
-        T v = values.front();
-        values.erase(values.begin());
-
-        auto q = TestType::unwrap(v, [&] (auto v) { return table->get_subtable(0, 0)->column<W>(0) != v; });
-        Results filtered = list.filter(std::move(q));
-        REQUIRE(filtered == values);
-
-        q = TestType::unwrap(v, [&] (auto v) { return table->get_subtable(0, 0)->column<W>(0) == v; });
-        filtered = list.filter(std::move(q));
-        REQUIRE(filtered.size() == 1);
-        REQUIRE(*filtered.first<T>() == v);
-    }
-#endif
-
-    SECTION("min()") {
-        if (!TestType::can_minmax()) {
-            REQUIRE_THROWS(list.min());
-            REQUIRE_THROWS(results.min());
-            return;
-        }
-
-        REQUIRE(get<W>(*list.min()) == TestType::min());
-        REQUIRE(get<W>(*results.min()) == TestType::min());
-        list.remove_all();
-        REQUIRE(list.min() == util::none);
-        REQUIRE(results.min() == util::none);
-    }
-
-    SECTION("max()") {
-        if (!TestType::can_minmax()) {
-            REQUIRE_THROWS(list.max());
-            REQUIRE_THROWS(results.max());
-            return;
-        }
-
-        REQUIRE(get<W>(*list.max()) == TestType::max());
-        REQUIRE(get<W>(*results.max()) == TestType::max());
-        list.remove_all();
-        REQUIRE(list.max() == util::none);
-        REQUIRE(results.max() == util::none);
-    }
-
-    SECTION("sum()") {
-        if (!TestType::can_sum()) {
-            REQUIRE_THROWS(list.sum());
-            return;
-        }
-
-        REQUIRE(get<W>(list.sum()) == TestType::sum());
-        REQUIRE(get<W>(*results.sum()) == TestType::sum());
-        list.remove_all();
-        REQUIRE(get<W>(list.sum()) == W{});
-        REQUIRE(get<W>(*results.sum()) == W{});
-    }
-
-    SECTION("average()") {
-        if (!TestType::can_average()) {
-            REQUIRE_THROWS(list.average());
-            return;
-        }
-
-        REQUIRE(*list.average() == TestType::average());
-        REQUIRE(*results.average() == TestType::average());
-        list.remove_all();
-        REQUIRE(list.average() == util::none);
-        REQUIRE(results.average() == util::none);
-    }
-
-    SECTION("operator==()") {
-        Obj obj1 = table->create_object();
-        REQUIRE(list == List(r, obj, col));
-        REQUIRE_FALSE(list == List(r, obj1, col));
-    }
-
-    SECTION("hash") {
-        Obj obj1 = table->create_object();
-        std::hash<List> h;
-        REQUIRE(h(list) == h(List(r, obj, col)));
-        REQUIRE_FALSE(h(list) == h(List(r, obj1, col)));
-    }
-
-    SECTION("handover") {
-        r->commit_transaction();
-
-        auto list2 = ThreadSafeReference(list).resolve<List>(r);
-        REQUIRE(list == list2);
-        auto results2 = ThreadSafeReference(results).resolve<Results>(r);
-        REQUIRE(results2 == values);
-    }
-
-    SECTION("notifications") {
-        r->commit_transaction();
-
-        auto sorted = results.sort({{"self", true}});
-
-        size_t calls = 0;
-        CollectionChangeSet change, rchange, srchange;
-        auto token = list.add_notification_callback([&](CollectionChangeSet c, std::exception_ptr) {
-            change = c;
-            ++calls;
-        });
-        auto rtoken = results.add_notification_callback([&](CollectionChangeSet c, std::exception_ptr) {
-            rchange = c;
-            ++calls;
-        });
-        auto srtoken = sorted.add_notification_callback([&](CollectionChangeSet c, std::exception_ptr) {
-            srchange = c;
-            ++calls;
-        });
-
-        SECTION("add value to list") {
-            // Remove the existing copy of this value so that the sorted list
-            // doesn't have dupes resulting in an unstable order
-            advance_and_notify(*r);
-            r->begin_transaction();
-            list.remove(0);
-            r->commit_transaction();
-
-            advance_and_notify(*r);
-            r->begin_transaction();
-            list.insert(0, static_cast<T>(values[0]));
-            r->commit_transaction();
-
-            advance_and_notify(*r);
-            REQUIRE_INDICES(change.insertions, 0);
-            REQUIRE_INDICES(rchange.insertions, 0);
-            // values[0] is max(), so it ends up at the end of the sorted list
-            REQUIRE_INDICES(srchange.insertions, values.size() - 1);
-        }
-
-        SECTION("remove value from list") {
-            advance_and_notify(*r);
-            r->begin_transaction();
-            list.remove(1);
-            r->commit_transaction();
-
-            advance_and_notify(*r);
-            REQUIRE_INDICES(change.deletions, 1);
-            REQUIRE_INDICES(rchange.deletions, 1);
-            // values[1] is min(), so it's index 0 for non-optional and 1 for
-            // optional (as nulls sort to the front)
-            REQUIRE_INDICES(srchange.deletions, TestType::is_optional);
-        }
-
-        SECTION("clear list") {
-            advance_and_notify(*r);
-
-            r->begin_transaction();
-            list.remove_all();
-            r->commit_transaction();
-            advance_and_notify(*r);
-            REQUIRE(change.deletions.count() == values.size());
-            REQUIRE(rchange.deletions.count() == values.size());
-            REQUIRE(srchange.deletions.count() == values.size());
-        }
-
-        SECTION("delete containing row") {
-            advance_and_notify(*r);
-            REQUIRE(calls == 3);
-
-            r->begin_transaction();
-            obj.remove();
-            r->commit_transaction();
-            advance_and_notify(*r);
-            REQUIRE(calls == 6);
-            REQUIRE(change.deletions.count() == values.size());
-            REQUIRE(rchange.deletions.count() == values.size());
-            REQUIRE(srchange.deletions.count() == values.size());
-
-            r->begin_transaction();
-            table->create_object();
-            r->commit_transaction();
-            advance_and_notify(*r);
-            REQUIRE(calls == 6);
-        }
-
-        SECTION("deleting containing row before first run of notifier") {
-            r2->begin_transaction();
-            table2->begin()->remove();
-            r2->commit_transaction();
-            advance_and_notify(*r);
-            REQUIRE(change.deletions.count() == values.size());
-        }
-    }
-
-#if REALM_ENABLE_SYNC && REALM_HAVE_SYNC_STABLE_IDS
-    SECTION("sync compatibility") {
-        if (!util::EventLoop::has_implementation())
-            return;
-
-        SyncServer server;
-        SyncTestFile sync_config(server, "shared");
-        sync_config.schema = config.schema;
-        sync_config.schema_version = 0;
-
-        {
-            auto r = Realm::get_shared_realm(sync_config);
-            r->begin_transaction();
-
-            CppContext ctx(r);
-            auto obj = Object::create(ctx, r, *r->schema().find("object"), util::Any(AnyDict{}));
-            auto list = any_cast<List>(obj.get_property_value<util::Any>(ctx, "value"));
-            list.add(static_cast<T>(values[0]));
-
-            r->commit_transaction();
-            wait_for_upload(*r);
-        }
-
-        util::File::remove(sync_config.path);
-
-        {
-            auto r = Realm::get_shared_realm(sync_config);
-            auto table = r->read_group().get_table("class_object");
-
-            util::EventLoop::main().run_until([&] {
-                return table->size() == 1;
-            });
-
-            CppContext ctx(r);
-            Object obj(r, "object", 0);
-            auto list = any_cast<List>(obj.get_property_value<util::Any>(ctx, "value"));
-            REQUIRE(list.get<T>(0) == values[0]);
-        }
-    }
-#endif
-}

+ 0 - 381
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/query.json

@@ -1,381 +0,0 @@
-{
-
-"dateTests" : {
-    "schema" : [{ 
-        "name": "DateObject",
-        "properties": [{ "name": "date", "type": "date" }]
-    }],
-    "objects": [
-        { "type": "DateObject", "value": [10000] },
-        { "type": "DateObject", "value": [10001] },
-        { "type": "DateObject", "value": [10002] }
-    ],
-    "tests": [
-        ["QueryCount", 2, "DateObject", "date <  $0", [2, "date"]],
-        ["QueryCount", 3, "DateObject", "date <= $0", [2, "date"]],
-        ["QueryCount", 2, "DateObject", "date >  $0", [0, "date"]],
-        ["QueryCount", 3, "DateObject", "date >= $0", [0, "date"]],
-        ["QueryCount", 1, "DateObject", "date == $0", [0, "date"]],
-        ["QueryCount", 2, "DateObject", "date != $0", [0, "date"]],
-
-        ["QueryThrows", "DateObject", "date == 'not a date'"],
-        ["QueryThrows", "DateObject", "date == 1"],
-        ["QueryThrows", "DateObject", "date == $0", 1]
-    ]
-},
-
-"boolTests" : {
-      "schema" : [{ 
-        "name": "BoolObject",
-        "properties": [{ "name": "boolCol", "type": "bool" }]
-    }],
-    "objects": [
-        { "type": "BoolObject", "value": [false] },
-        { "type": "BoolObject", "value": [true] },
-        { "type": "BoolObject", "value": [true] }
-    ],
-    "tests": [
-        ["QueryCount", 2, "BoolObject", "boolCol == true"],
-        ["QueryCount", 1, "BoolObject", "boolCol==false"],
-        ["QueryCount", 1, "BoolObject", "boolCol != true"],
-        ["QueryCount", 2, "BoolObject", "true == boolCol"],
-        ["QueryCount", 2, "BoolObject", "boolCol == TRUE"],
-        ["QueryCount", 1, "BoolObject", "boolCol == FALSE"],
-        ["QueryCount", 2, "BoolObject", "boolCol == $0", true],
-        ["QueryCount", 1, "BoolObject", "boolCol == $0", false],
-        ["QueryCount", 0, "BoolObject", "boolCol == true && boolCol == false"],
-        ["QueryCount", 3, "BoolObject", "boolCol == true || boolCol == false"],
-
-        ["QueryThrows", "BoolObject", "boolCol == 0"],
-        ["QueryThrows", "BoolObject", "boolCol == 1"],
-        ["QueryThrows", "BoolObject", "boolCol == 'not a bool'"],
-        ["QueryThrows", "BoolObject", "boolCol == $0", "not a bool"],
-        ["QueryThrows", "BoolObject", "boolCol >  true"],
-        ["QueryThrows", "BoolObject", "boolCol >= true"],
-        ["QueryThrows", "BoolObject", "boolCol <  true"],
-        ["QueryThrows", "BoolObject", "boolCol <= true"],
-        ["QueryThrows", "BoolObject", "boolCol BEGINSWITH true"],
-        ["QueryThrows", "BoolObject", "boolCol CONTAINS true"],
-        ["QueryThrows", "BoolObject", "boolCol ENDSWITH true"]
-    ]  
-},
-
-"intTests" : {
-    "schema" : [{ 
-        "name": "IntObject",
-        "properties": [{ "name": "intCol", "type": "int" }]
-    }],
-    "objects": [
-        { "type": "IntObject", "value": [-1] },
-        { "type": "IntObject", "value": [0] },
-        { "type": "IntObject", "value": [100] }
-    ],
-    "tests": [
-        ["QueryCount", 1, "IntObject", "intCol == -1"],
-        ["QueryCount", 1, "IntObject", "intCol==0"],
-        ["QueryCount", 0, "IntObject", "1 == intCol"],
-        ["QueryCount", 2, "IntObject", "intCol != 0"],
-        ["QueryCount", 2, "IntObject", "intCol > -1"],
-        ["QueryCount", 3, "IntObject", "intCol >= -1"],
-        ["QueryCount", 2, "IntObject", "intCol < 100"],
-        ["QueryCount", 3, "IntObject", "intCol <= 100"],
-        ["QueryCount", 1, "IntObject", "intCol > 0x1F"],
-        ["QueryCount", 1, "IntObject", "intCol == $0", 100],
-
-        ["QueryThrows", "IntObject", "intCol == 'not an int'"],
-        ["QueryThrows", "IntObject", "intCol == true"],
-        ["QueryThrows", "IntObject", "intCol == $0", "not an int"],
-        ["QueryThrows", "IntObject", "intCol BEGINSWITH 1"],
-        ["QueryThrows", "IntObject", "intCol CONTAINS 1"],
-        ["QueryThrows", "IntObject", "intCol ENDSWITH 1"]
-    ]
-},
-
-"floatTests" : {
-    "schema" : [{ 
-        "name": "FloatObject",
-        "properties": [{ "name": "floatCol", "type": "float" }]
-    }],
-    "objects": [
-        { "type": "FloatObject", "value": [-1.001] },
-        { "type": "FloatObject", "value": [0.0] },
-        { "type": "FloatObject", "value": [100.2] }
-    ],
-    "tests": [
-        ["QueryCount", 1, "FloatObject", "floatCol == -1.001"],
-        ["QueryCount", 1, "FloatObject", "floatCol = 0"],
-        ["QueryCount", 0, "FloatObject", "1 == floatCol"],
-        ["QueryCount", 2, "FloatObject", "floatCol != 0"],
-        ["QueryCount", 2, "FloatObject", "floatCol > -1.001"],
-        ["QueryCount", 3, "FloatObject", "floatCol >= -1.001"],
-        ["QueryCount", 2, "FloatObject", "floatCol < 100.2"],
-        ["QueryCount", 3, "FloatObject", "floatCol <= 100.2"],
-        ["QueryCount", 1, "FloatObject", "floatCol > 0x1F"],
-        ["QueryCount", 1, "FloatObject", "floatCol == $0", 100.2],
-
-        ["QueryThrows", "FloatObject", "floatCol == 'not a float'"],
-        ["QueryThrows", "FloatObject", "floatCol == true"],
-        ["QueryThrows", "FloatObject", "floatCol == $0", "not a float"],
-        ["QueryThrows", "FloatObject", "floatCol BEGINSWITH 1"],
-        ["QueryThrows", "FloatObject", "floatCol CONTAINS 1"],
-        ["QueryThrows", "FloatObject", "floatCol ENDSWITH 1"],
-
-        ["Disabled", "QueryThrows", "FloatObject", "floatCol = 3.5e+38"],
-        ["Disabled", "QueryThrows", "FloatObject", "floatCol = -3.5e+38"]
-    ]
-},
-
-"doubleTests" : {
-    "schema" : [{ 
-        "name": "DoubleObject",
-        "properties": [{ "name": "doubleCol", "type": "double" }]
-    }],
-    "objects": [
-        { "type": "DoubleObject", "value": [-1.001] },
-        { "type": "DoubleObject", "value": [0.0] },
-        { "type": "DoubleObject", "value": [100.2] }
-    ],
-    "tests": [
-        ["QueryCount", 1, "DoubleObject", "doubleCol == -1.001"],
-        ["QueryCount", 1, "DoubleObject", "doubleCol == 0"],
-        ["QueryCount", 0, "DoubleObject", "1 == doubleCol"],
-        ["QueryCount", 2, "DoubleObject", "doubleCol != 0"],
-        ["QueryCount", 2, "DoubleObject", "doubleCol > -1.001"],
-        ["QueryCount", 3, "DoubleObject", "doubleCol >= -1.001"],
-        ["QueryCount", 2, "DoubleObject", "doubleCol < 100.2"],
-        ["QueryCount", 3, "DoubleObject", "doubleCol <= 100.2"],
-        ["QueryCount", 1, "DoubleObject", "doubleCol > 0x1F"],
-        ["QueryCount", 1, "DoubleObject", "doubleCol == $0", 100.2],
-
-        ["QueryThrows", "DoubleObject", "doubleCol == 'not a double'"],
-        ["QueryThrows", "DoubleObject", "doubleCol == true"],
-        ["QueryThrows", "DoubleObject", "doubleCol == $0", "not a double"],
-        ["QueryThrows", "DoubleObject", "doubleCol BEGINSWITH 1"],
-        ["QueryThrows", "DoubleObject", "doubleCol CONTAINS 1"],
-        ["QueryThrows", "DoubleObject", "doubleCol ENDSWITH 1"]
-    ]
-},
-
-"stringTests" : {
-    "schema" : [{ 
-        "name": "StringObject",
-        "properties": [{ "name": "stringCol", "type": "string" }]
-    }],
-    "objects": [
-        { "type": "StringObject", "value": ["A"] },
-        { "type": "StringObject", "value": ["a"] },
-        { "type": "StringObject", "value": ["a"] },
-        { "type": "StringObject", "value": ["C"] },
-        { "type": "StringObject", "value": ["c"] },
-        { "type": "StringObject", "value": ["abc"] },
-        { "type": "StringObject", "value": ["ABC"] },
-        { "type": "StringObject", "value": [""] },
-        { "type": "StringObject", "value": ["\\\"\\n\\0\\r\\\\'"] }
-    ],
-    "tests": [
-        ["QueryCount", 2, "StringObject", "stringCol == 'a'"],
-        ["QueryCount", 1, "StringObject", "'c' == stringCol"],
-        ["QueryCount", 2, "StringObject", "stringCol == \"a\""],
-        ["QueryCount", 1, "StringObject", "stringCol=='abc'"],
-        ["QueryCount", 1, "StringObject", "stringCol == ''"],
-        ["QueryCount", 8, "StringObject", "stringCol != ''"],
-        ["QueryCount", 1, "StringObject", "stringCol == \"\\\"\\n\\0\\r\\\\'\""],
-        ["QueryCount", 3, "StringObject", "stringCol BEGINSWITH 'a'"],
-        ["QueryCount", 1, "StringObject", "stringCol beginswith 'ab'"],
-        ["QueryCount", 0, "StringObject", "stringCol BEGINSWITH 'abcd'"],
-        ["QueryCount", 2, "StringObject", "stringCol BEGINSWITH 'A'"],
-        ["QueryCount", 2, "StringObject", "stringCol ENDSWITH 'c'"],
-        ["QueryCount", 1, "StringObject", "stringCol endswith 'bc'"],
-        ["QueryCount", 9, "StringObject", "stringCol ENDSWITH ''"],
-        ["QueryCount", 1, "StringObject", "stringCol CONTAINS 'b'"],
-        ["QueryCount", 2, "StringObject", "stringCol contains 'c'"],
-        ["QueryCount", 9, "StringObject", "stringCol CONTAINS ''"],
-        ["QueryCount", 2, "StringObject", "stringCol == $0", "a"],
-        ["QueryCount", 2, "StringObject", "stringCol ENDSWITH $0", "c"],
-
-        ["QueryThrows", "StringObject", "stringCol == true"],
-        ["QueryThrows", "StringObject", "stringCol == 123"],
-        ["QueryThrows", "StringObject", "stringCol CONTAINS $0", 1],
-
-        ["QueryCount", 3, "StringObject", "stringCol ==[c] 'a'"],
-        ["QueryCount", 5, "StringObject", "stringCol BEGINSWITH[c] 'A'"],
-        ["QueryCount", 4, "StringObject", "stringCol ENDSWITH[c] 'c'"],
-        ["QueryCount", 2, "StringObject", "stringCol CONTAINS[c] 'B'"]
-    ]
-},
-
-"binaryTests" : {
-    "schema" : [{ 
-        "name": "BinaryObject",
-        "properties": [{ "name": "binaryCol", "type": "data" }]
-    }],
-    "objects": [
-        { "type": "BinaryObject", "value": [[1, 100, 233, 255, 0]] },
-        { "type": "BinaryObject", "value": [[1, 100]] },
-        { "type": "BinaryObject", "value": [[100]] },
-        { "type": "BinaryObject", "value": [[]] },
-        { "type": "BinaryObject", "value": [[255, 0]] }
-    ],
-    "tests": [
-        ["QueryCount", 1, "BinaryObject", "binaryCol == $0", [1, "binaryCol"]],
-        ["QueryCount", 1, "BinaryObject", "$0 == binaryCol", [2, "binaryCol"]],
-        ["QueryCount", 4, "BinaryObject", "binaryCol != $0", [0, "binaryCol"]],
-        ["QueryCount", 1, "BinaryObject", "binaryCol BEGINSWITH $0", [0, "binaryCol"]],
-        ["QueryCount", 2, "BinaryObject", "binaryCol BEGINSWITH $0", [1, "binaryCol"]],
-        ["QueryCount", 2, "BinaryObject", "binaryCol ENDSWITH $0", [4, "binaryCol"]],
-        ["QueryCount", 3, "BinaryObject", "binaryCol CONTAINS $0", [2, "binaryCol"]]
-    ]
-},
-
-"objectTests" : {
-    "schema" : [
-        { "name": "IntObject",  "properties": [
-            { "name": "intCol",  "type": "int" }
-        ]},
-        { "name": "LinkObject", "properties": [
-            { "name": "linkCol", "type": "object", "objectType": "IntObject" }
-        ]}
-    ],
-    "objects": [
-        { "type": "LinkObject", "value": [[1]] },
-        { "type": "LinkObject", "value": [[2]] },
-        { "type": "LinkObject", "value": [null] }
-    ],
-    "tests": [
-        ["QueryCount", 1, "LinkObject", "linkCol == $0", [0, "linkCol"]],
-        ["QueryCount", 1, "LinkObject", "$0 == linkCol", [1, "linkCol"]],
-        ["QueryCount", 2, "LinkObject", "linkCol != $0", [0, "linkCol"]],
-        ["QueryCount", 1, "LinkObject", "linkCol = null"],
-        ["QueryCount", 2, "LinkObject", "linkCol != NULL"],
-        ["QueryCount", 1, "LinkObject", "linkCol = $0", null],
-
-        ["QueryThrows", "LinkObject", "linkCol > $0", [0, "linkCol"]],
-        ["QueryThrows", "LinkObject", "intCol = $0", [0, "linkCol"]]
-    ]
-},
-
-"compoundTests" : {
-    "schema" : [
-        { "name": "IntObject",  
-          "properties": [{ "name": "intCol",  "type": "int" }],
-          "primaryKey" : "intCol" }
-    ],
-    "objects": [
-        { "type": "IntObject", "value": [0] },
-        { "type": "IntObject", "value": [1] },
-        { "type": "IntObject", "value": [2] },    
-        { "type": "IntObject", "value": [3] }
-    ],
-    "tests": [
-        ["ObjectSet", [],       "IntObject", "intCol == 0 && intCol == 1"],
-        ["ObjectSet", [0, 1],   "IntObject", "intCol == 0 || intCol == 1"],
-        ["ObjectSet", [0],      "IntObject", "intCol == 0 && intCol != 1"],
-        ["ObjectSet", [2, 3],   "IntObject", "intCol >= 2 && intCol < 4"],
-        ["ObjectSet", [0],      "IntObject", "intCol == 0 && NOT intCol != 0"],
-        ["ObjectSet", [0, 3],   "IntObject", "intCol == 0 || NOT (intCol == 1 || intCol == 2)"],
-        ["ObjectSet", [1],      "IntObject", "(intCol == 0 || intCol == 1) && intCol >= 1"],
-        ["ObjectSet", [1],      "IntObject", "intCol >= 1 && (intCol == 0 || intCol == 1)"],
-        ["ObjectSet", [0, 1],   "IntObject", "intCol == 0 || (intCol == 1 && intCol >= 1)"],
-        ["ObjectSet", [0, 1],   "IntObject", "(intCol == 1 && intCol >= 1) || intCol == 0"],
-        ["ObjectSet", [0, 1],   "IntObject", "intCol == 0 || intCol == 1 && intCol >= 1"],
-        ["ObjectSet", [0, 1, 2],"IntObject", "intCol == 0 || intCol == 1 || intCol <= 2"],
-        ["ObjectSet", [0, 1],   "IntObject", "intCol == 1 && intCol >= 1 || intCol == 0"],
-        ["ObjectSet", [0, 1],   "IntObject", "intCol == 1 || intCol == 0 && intCol <= 0 && intCol >= 0"],
-        ["ObjectSet", [0, 1],   "IntObject", "intCol == 0 || NOT (intCol == 3 && intCol >= 0) && intCol == 1"]   
-    ]
-},
-
-"keyPathTests" : {
-    "schema" : [
-    { 
-        "name": "BasicTypesObject",  
-        "properties": [
-            { "name": "intCol",     "type": "int" },
-            { "name": "floatCol",   "type": "float" },
-            { "name": "doubleCol",  "type": "double" },
-            { "name": "stringCol",  "type": "string" },
-            { "name": "dateCol",    "type": "date" },
-            { "name": "dataCol",    "type": "data" }
-        ]
-    }, 
-    {
-        "name": "LinkTypesObject",
-        "primaryKey": "primaryKey",
-        "properties": [
-            { "name": "primaryKey", "type": "int" },
-            { "name": "basicLink",  "type": "object", "objectType": "BasicTypesObject" },
-            { "name": "linkLink",   "type": "object", "objectType": "LinkTypesObject" }
-        ]
-    }],
-    "objects": [
-        { "type": "LinkTypesObject", "value": [0, [1, 0.1, 0.001, "1", 1, [1, 10, 100]], null] },
-        { "type": "LinkTypesObject", "value": [1, null, [2, [1, 0.1, 0.001, "1", 1, [1, 10, 100]], null]] },
-        { "type": "LinkTypesObject", "value": [3, null, [4, [2, 0.2, 0.002, "2", 2, [2, 20, 200]], null]] }
-    ],
-    "tests": [
-        ["ObjectSet", [0, 2], "LinkTypesObject", "basicLink.intCol == 1"],
-        ["ObjectSet", [1],    "LinkTypesObject", "linkLink.basicLink.intCol == 1"],
-        ["ObjectSet", [1, 3], "LinkTypesObject", "linkLink.basicLink.intCol > 0"],
-        ["ObjectSet", [0, 2], "LinkTypesObject", "basicLink.floatCol == 0.1"],
-        ["ObjectSet", [1],    "LinkTypesObject", "linkLink.basicLink.floatCol == 0.1"],
-        ["ObjectSet", [1, 3], "LinkTypesObject", "linkLink.basicLink.floatCol > 0"]
-    ]
-},
-
-"optionalTests" : {
-    "schema" : [
-    { 
-        "name": "OptionalTypesObject",  
-        "primaryKey": "primaryKey",
-        "properties": [
-            { "name": "primaryKey", "type": "int" },
-            { "name": "intCol",     "type": "int",      "optional": true },
-            { "name": "floatCol",   "type": "float",    "optional": true },
-            { "name": "doubleCol",  "type": "double",   "optional": true },
-            { "name": "stringCol",  "type": "string",   "optional": true },
-            { "name": "dateCol",    "type": "date",     "optional": true },
-            { "name": "dataCol",    "type": "data",     "optional": true }
-        ]
-    }, 
-    {
-        "name": "LinkTypesObject",
-        "primaryKey": "primaryKey",
-        "properties": [
-            { "name": "primaryKey", "type": "int" },
-            { "name": "basicLink",  "type": "object", "objectType": "OptionalTypesObject" }
-        ]
-    }],
-    "objects": [
-        { "type": "LinkTypesObject", "value": [0, [0, 1, 0.1, 0.001, "1", 1, [1, 10, 100]]] },
-        { "type": "LinkTypesObject", "value": [1, [1, null, null, null, null, null, null]] }
-    ],
-    "tests": [
-        ["ObjectSet", [1], "OptionalTypesObject", "intCol == null"],
-        ["ObjectSet", [1], "OptionalTypesObject", "null == intCol"],
-        ["ObjectSet", [0], "OptionalTypesObject", "intCol != null"],
-        ["ObjectSet", [1], "OptionalTypesObject", "floatCol == null"],
-        ["ObjectSet", [0], "OptionalTypesObject", "floatCol != null"],
-        ["ObjectSet", [1], "OptionalTypesObject", "doubleCol == null"],
-        ["ObjectSet", [0], "OptionalTypesObject", "doubleCol != null"],
-        ["ObjectSet", [1], "OptionalTypesObject", "stringCol == null"],
-        ["ObjectSet", [0], "OptionalTypesObject", "stringCol != null"],
-        ["ObjectSet", [1], "OptionalTypesObject", "dateCol == null"],
-        ["ObjectSet", [0], "OptionalTypesObject", "dateCol != null"],
-        ["ObjectSet", [1], "OptionalTypesObject", "dataCol == null"],
-        ["ObjectSet", [0], "OptionalTypesObject", "dataCol != null"],
-
-        ["ObjectSet", [1], "LinkTypesObject", "basicLink.intCol == null"],
-        ["ObjectSet", [0], "LinkTypesObject", "basicLink.intCol != null"],
-        ["ObjectSet", [1], "LinkTypesObject", "basicLink.floatCol == null"],
-        ["ObjectSet", [0], "LinkTypesObject", "basicLink.floatCol != null"],
-        ["ObjectSet", [1], "LinkTypesObject", "basicLink.doubleCol == null"],
-        ["ObjectSet", [0], "LinkTypesObject", "basicLink.doubleCol != null"],
-        ["ObjectSet", [1], "LinkTypesObject", "basicLink.stringCol == null"],
-        ["ObjectSet", [0], "LinkTypesObject", "basicLink.stringCol != null"],
-        ["ObjectSet", [1], "LinkTypesObject", "basicLink.dateCol == null"],
-        ["ObjectSet", [0], "LinkTypesObject", "basicLink.dateCol != null"],
-        ["QueryThrows", "LinkTypesObject", "basicLink.dataCol == null"]
-    ]
-}
-
-}

+ 0 - 1863
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/realm.cpp

@@ -1,1863 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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 "catch2/catch.hpp"
-
-#include "util/event_loop.hpp"
-#include "util/test_file.hpp"
-#include "util/test_utils.hpp"
-
-#include "binding_context.hpp"
-#include "impl/realm_coordinator.hpp"
-#include "object_schema.hpp"
-#include "object_store.hpp"
-#include "property.hpp"
-#include "results.hpp"
-#include "schema.hpp"
-#include "thread_safe_reference.hpp"
-#include "util/scheduler.hpp"
-
-#include <realm/db.hpp>
-
-#if REALM_ENABLE_SYNC
-#include "sync/async_open_task.hpp"
-#endif
-
-#include <realm/util/scope_exit.hpp>
-
-namespace realm {
-class TestHelper {
-public:
-    static DBRef& get_db(SharedRealm const& shared_realm)
-    {
-        return Realm::Internal::get_db(*shared_realm);
-    }
-
-    static void begin_read(SharedRealm const& shared_realm, VersionID version)
-    {
-        Realm::Internal::begin_read(*shared_realm, version);
-    }
-};
-}
-
-using namespace realm;
-
-TEST_CASE("SharedRealm: get_shared_realm()") {
-    TestFile config;
-    config.schema_version = 1;
-    config.schema = Schema{
-        {"object", {
-            {"value", PropertyType::Int}
-        }},
-    };
-
-    SECTION("should validate that the config is sensible") {
-        SECTION("bad encryption key") {
-            config.encryption_key = std::vector<char>(2, 0);
-            REQUIRE_THROWS(Realm::get_shared_realm(config));
-        }
-
-        SECTION("schema without schema version") {
-            config.schema_version = ObjectStore::NotVersioned;
-            REQUIRE_THROWS(Realm::get_shared_realm(config));
-        }
-
-        SECTION("migration function for immutable") {
-            config.schema_mode = SchemaMode::Immutable;
-            config.migration_function = [](auto, auto, auto) { };
-            REQUIRE_THROWS(Realm::get_shared_realm(config));
-        }
-
-        SECTION("migration function for read-only") {
-            config.schema_mode = SchemaMode::ReadOnlyAlternative;
-            config.migration_function = [](auto, auto, auto) { };
-            REQUIRE_THROWS(Realm::get_shared_realm(config));
-        }
-
-        SECTION("migration function for additive-only") {
-            config.schema_mode = SchemaMode::Additive;
-            config.migration_function = [](auto, auto, auto) { };
-            REQUIRE_THROWS(Realm::get_shared_realm(config));
-        }
-
-        SECTION("initialization function for immutable") {
-            config.schema_mode = SchemaMode::Immutable;
-            config.initialization_function = [](auto) { };
-            REQUIRE_THROWS(Realm::get_shared_realm(config));
-        }
-
-        SECTION("initialization function for read-only") {
-            config.schema_mode = SchemaMode::ReadOnlyAlternative;
-            config.initialization_function = [](auto) { };
-            REQUIRE_THROWS(Realm::get_shared_realm(config));
-        }
-    }
-
-    SECTION("should reject mismatched config") {
-        SECTION("schema version") {
-            auto realm = Realm::get_shared_realm(config);
-            config.schema_version = 2;
-            REQUIRE_THROWS(Realm::get_shared_realm(config));
-
-            config.schema = util::none;
-            config.schema_version = ObjectStore::NotVersioned;
-            REQUIRE_NOTHROW(Realm::get_shared_realm(config));
-        }
-
-        SECTION("schema mode") {
-            auto realm = Realm::get_shared_realm(config);
-            config.schema_mode = SchemaMode::Manual;
-            REQUIRE_THROWS(Realm::get_shared_realm(config));
-        }
-
-        SECTION("durability") {
-            auto realm = Realm::get_shared_realm(config);
-            config.in_memory = true;
-            REQUIRE_THROWS(Realm::get_shared_realm(config));
-        }
-
-        SECTION("schema") {
-            auto realm = Realm::get_shared_realm(config);
-            config.schema = Schema{
-                {"object", {
-                    {"value", PropertyType::Int},
-                    {"value2", PropertyType::Int}
-                }},
-            };
-            REQUIRE_THROWS(Realm::get_shared_realm(config));
-        }
-    }
-
-
-// Windows doesn't use fifos
-#ifndef _WIN32
-    SECTION("should be able to set a FIFO fallback path") {
-        std::string fallback_dir = tmp_dir() + "/fallback/";
-        realm::util::try_make_dir(fallback_dir);
-        TestFile config;
-        config.fifo_files_fallback_path = fallback_dir;
-        config.schema_version = 1;
-        config.schema = Schema{
-            {"object", {
-                {"value", PropertyType::Int}
-            }},
-        };
-
-        realm::util::make_dir(config.path + ".note");
-        auto realm = Realm::get_shared_realm(config);
-        auto fallback_file = util::format("%1realm_%2.note", fallback_dir, std::hash<std::string>()(config.path)); // Mirror internal implementation
-        REQUIRE(File::exists(fallback_file));
-        realm::util::remove_dir(config.path + ".note");
-        realm::util::remove_dir_recursive(fallback_dir);
-    }
-
-    SECTION("automatically append dir separator to end of fallback path") {
-        std::string fallback_dir = tmp_dir() + "/fallback";
-        realm::util::try_make_dir(fallback_dir);
-        TestFile config;
-        config.fifo_files_fallback_path = fallback_dir;
-        config.schema_version = 1;
-        config.schema = Schema{
-            {"object", {
-                {"value", PropertyType::Int}
-            }},
-        };
-
-        realm::util::make_dir(config.path + ".note");
-        auto realm = Realm::get_shared_realm(config);
-        auto fallback_file = util::format("%1/realm_%2.note", fallback_dir, std::hash<std::string>()(config.path)); // Mirror internal implementation
-        REQUIRE(File::exists(fallback_file));
-        realm::util::remove_dir(config.path + ".note");
-        realm::util::remove_dir_recursive(fallback_dir);
-    }
-#endif
-
-    SECTION("should verify that the schema is valid") {
-        config.schema = Schema{
-            {"object",
-                {{"value", PropertyType::Int}},
-                {{"invalid backlink", PropertyType::LinkingObjects|PropertyType::Array, "object", "value"}}
-            }
-        };
-        REQUIRE_THROWS_WITH(Realm::get_shared_realm(config),
-                            Catch::Matchers::Contains("origin of linking objects property"));
-    }
-
-    SECTION("should apply the schema if one is supplied") {
-        Realm::get_shared_realm(config);
-
-        {
-            Group g(config.path);
-            auto table = ObjectStore::table_for_object_type(g, "object");
-            REQUIRE(table);
-            REQUIRE(table->get_column_count() == 1);
-            REQUIRE(table->get_column_name(*table->get_column_keys().begin()) == "value");
-        }
-
-        config.schema_version = 2;
-        config.schema = Schema{
-            {"object", {
-                {"value", PropertyType::Int},
-                {"value2", PropertyType::Int}
-            }},
-        };
-        bool migration_called = false;
-        config.migration_function = [&](SharedRealm old_realm, SharedRealm new_realm, Schema&) {
-            migration_called = true;
-            REQUIRE(ObjectStore::table_for_object_type(old_realm->read_group(), "object")->get_column_count() == 1);
-            REQUIRE(ObjectStore::table_for_object_type(new_realm->read_group(), "object")->get_column_count() == 2);
-        };
-        Realm::get_shared_realm(config);
-        REQUIRE(migration_called);
-    }
-
-    SECTION("should properly roll back from migration errors") {
-        Realm::get_shared_realm(config);
-
-        config.schema_version = 2;
-        config.schema = Schema{
-            {"object", {
-                {"value", PropertyType::Int},
-                {"value2", PropertyType::Int}
-            }},
-        };
-        bool migration_called = false;
-        config.migration_function = [&](SharedRealm old_realm, SharedRealm new_realm, Schema&) {
-            REQUIRE(ObjectStore::table_for_object_type(old_realm->read_group(), "object")->get_column_count() == 1);
-            REQUIRE(ObjectStore::table_for_object_type(new_realm->read_group(), "object")->get_column_count() == 2);
-            if (!migration_called) {
-                migration_called = true;
-                throw "error";
-            }
-        };
-        REQUIRE_THROWS_WITH(Realm::get_shared_realm(config), "error");
-        REQUIRE(migration_called);
-        REQUIRE_NOTHROW(Realm::get_shared_realm(config));
-    }
-
-    SECTION("should read the schema from the file if none is supplied") {
-        Realm::get_shared_realm(config);
-
-        config.schema = util::none;
-        auto realm = Realm::get_shared_realm(config);
-        REQUIRE(realm->schema().size() == 1);
-        auto it = realm->schema().find("object");
-        auto table = realm->read_group().get_table("class_object");
-        REQUIRE(it != realm->schema().end());
-        REQUIRE(it->table_key == table->get_key());
-        REQUIRE(it->persisted_properties.size() == 1);
-        REQUIRE(it->persisted_properties[0].name == "value");
-        REQUIRE(it->persisted_properties[0].column_key == table->get_column_key("value"));
-    }
-
-    SECTION("should read the proper schema from the file if a custom version is supplied") {
-        Realm::get_shared_realm(config);
-
-        config.schema = util::none;
-        config.schema_mode = SchemaMode::Additive;
-        config.schema_version = 0;
-
-        auto realm = Realm::get_shared_realm(config);
-        REQUIRE(realm->schema().size() == 1);
-
-        auto& db = TestHelper::get_db(realm);
-        auto rt = db->start_read();
-        VersionID old_version = rt->get_version_of_current_transaction();
-        rt = nullptr;
-        realm->close();
-
-        config.schema = Schema{
-            {"object", {
-                {"value", PropertyType::Int}
-            }},
-            {"object1", {
-                {"value", PropertyType::Int}
-            }},
-        };
-        config.schema_version = 1;
-        realm = Realm::get_shared_realm(config);
-        REQUIRE(realm->schema().size() == 2);
-
-        config.schema = util::none;
-        auto old_realm = Realm::get_shared_realm(config);
-        TestHelper::begin_read(old_realm, old_version);
-        REQUIRE(old_realm->schema().size() == 1);
-    }
-
-    SECTION("should sensibly handle opening an uninitialized file without a schema specified") {
-        // create an empty file
-        File(config.path, File::mode_Write);
-
-        // open the empty file, but don't initialize the schema
-        Realm::Config config_without_schema = config;
-        config_without_schema.schema = util::none;
-        config_without_schema.schema_version = ObjectStore::NotVersioned;
-        auto realm = Realm::get_shared_realm(config_without_schema);
-        REQUIRE(realm->schema().empty());
-        REQUIRE(realm->schema_version() == ObjectStore::NotVersioned);
-        // verify that we can get another Realm instance
-        REQUIRE_NOTHROW(Realm::get_shared_realm(config_without_schema));
-
-        // verify that we can also still open the file with a proper schema
-        auto realm2 = Realm::get_shared_realm(config);
-        REQUIRE_FALSE(realm2->schema().empty());
-        REQUIRE(realm2->schema_version() == 1);
-    }
-
-    SECTION("should populate the table columns in the schema when opening as immutable") {
-        Realm::get_shared_realm(config);
-
-        config.schema_mode = SchemaMode::Immutable;
-        auto realm = Realm::get_shared_realm(config);
-        auto it = realm->schema().find("object");
-        auto table = realm->read_group().get_table("class_object");
-        REQUIRE(it != realm->schema().end());
-        REQUIRE(it->table_key == table->get_key());
-        REQUIRE(it->persisted_properties.size() == 1);
-        REQUIRE(it->persisted_properties[0].name == "value");
-        REQUIRE(it->persisted_properties[0].column_key == table->get_column_key("value"));
-    }
-
-    SECTION("should support using different table subsets on different threads") {
-        auto realm1 = Realm::get_shared_realm(config);
-
-        config.schema = Schema{
-            {"object 2", {
-                {"value", PropertyType::Int}
-            }},
-        };
-        auto realm2 = Realm::get_shared_realm(config);
-
-        config.schema = util::none;
-        auto realm3 = Realm::get_shared_realm(config);
-
-        config.schema = Schema{
-            {"object", {
-                {"value", PropertyType::Int}
-            }},
-        };
-        auto realm4 = Realm::get_shared_realm(config);
-
-        realm1->refresh();
-        realm2->refresh();
-
-        REQUIRE(realm1->schema().size() == 1);
-        REQUIRE(realm1->schema().find("object") != realm1->schema().end());
-        REQUIRE(realm2->schema().size() == 1);
-        REQUIRE(realm2->schema().find("object 2") != realm2->schema().end());
-        REQUIRE(realm3->schema().size() == 2);
-        REQUIRE(realm3->schema().find("object") != realm3->schema().end());
-        REQUIRE(realm3->schema().find("object 2") != realm3->schema().end());
-        REQUIRE(realm4->schema().size() == 1);
-        REQUIRE(realm4->schema().find("object") != realm4->schema().end());
-    }
-
-// The ExternalCommitHelper implementation on Windows doesn't rely on files
-#ifndef _WIN32
-    SECTION("should throw when creating the notification pipe fails") {
-        util::try_make_dir(config.path + ".note");
-        auto sys_fallback_file = util::format("%1realm_%2.note", DBOptions::get_sys_tmp_dir(), std::hash<std::string>()(config.path)); // Mirror internal implementation
-        util::try_make_dir(sys_fallback_file);
-        REQUIRE_THROWS(Realm::get_shared_realm(config));
-        util::remove_dir(config.path + ".note");
-        util::remove_dir(sys_fallback_file);
-    }
-#endif
-
-    SECTION("should detect use of Realm on incorrect thread") {
-        auto realm = Realm::get_shared_realm(config);
-        std::thread([&]{
-            REQUIRE_THROWS_AS(realm->verify_thread(), IncorrectThreadException);
-        }).join();
-    }
-
-    SECTION("should not modify the schema when fetching from the cache") {
-        auto realm = Realm::get_shared_realm(config);
-        auto object_schema = &*realm->schema().find("object");
-        Realm::get_shared_realm(config);
-        REQUIRE(object_schema == &*realm->schema().find("object"));
-    }
-}
-
-#if REALM_ENABLE_SYNC
-TEST_CASE("Get Realm using Async Open", "[asyncOpen]") {
-    TestFile local_config;
-    local_config.schema_version = 1;
-    local_config.schema = Schema{
-        {"object", {
-            {"value", PropertyType::Int}
-        }},
-    };
-
-    if (!util::EventLoop::has_implementation())
-        return;
-
-    TestSyncManager init_sync_manager;
-
-    SyncServer server;
-    SyncTestFile config(server, "default");
-    config.schema = Schema{
-        {"object", {
-            {"value", PropertyType::Int},
-        }},
-    };
-    SyncTestFile config2(server, "default");
-    config2.schema = config.schema;
-
-    std::mutex mutex;
-    SECTION("can open synced Realms that don't already exist") {
-        std::atomic<bool> called{false};
-        auto task = Realm::get_synchronized_realm(config);
-        task->start([&](auto ref, auto error) {
-            std::lock_guard<std::mutex> lock(mutex);
-            REQUIRE(!error);
-            called = true;
-
-            REQUIRE(Realm::get_shared_realm(std::move(ref))->read_group().get_table("class_object"));
-        });
-        util::EventLoop::main().run_until([&]{ return called.load(); });
-        std::lock_guard<std::mutex> lock(mutex);
-        REQUIRE(called);
-    }
-
-    SECTION("downloads Realms which exist on the server") {
-        {
-            auto realm = Realm::get_shared_realm(config2);
-            realm->begin_transaction();
-            realm->read_group().get_table("class_object")->create_object();
-            realm->commit_transaction();
-            wait_for_upload(*realm);
-        }
-
-        std::atomic<bool> called{false};
-        auto task = Realm::get_synchronized_realm(config);
-        task->start([&](auto ref, auto error) {
-            std::lock_guard<std::mutex> lock(mutex);
-            REQUIRE(!error);
-            called = true;
-
-            REQUIRE(Realm::get_shared_realm(std::move(ref))->read_group().get_table("class_object"));
-        });
-        util::EventLoop::main().run_until([&]{ return called.load(); });
-        std::lock_guard<std::mutex> lock(mutex);
-        REQUIRE(called);
-    }
-
-    SECTION("downloads latest state for Realms which already exist locally") {
-        wait_for_upload(*Realm::get_shared_realm(config));
-
-        {
-            auto realm = Realm::get_shared_realm(config2);
-            realm->begin_transaction();
-            realm->read_group().get_table("class_object")->create_object();
-            realm->commit_transaction();
-            wait_for_upload(*realm);
-        }
-
-        std::atomic<bool> called{false};
-        auto task = Realm::get_synchronized_realm(config);
-        task->start([&](auto ref, auto error) {
-            std::lock_guard<std::mutex> lock(mutex);
-            REQUIRE(!error);
-            called = true;
-
-            REQUIRE(Realm::get_shared_realm(std::move(ref))->read_group().get_table("class_object")->size() == 1);
-        });
-        util::EventLoop::main().run_until([&]{ return called.load(); });
-        std::lock_guard<std::mutex> lock(mutex);
-        REQUIRE(called);
-    }
-
-    SECTION("can download partial Realms") {
-        config.sync_config->is_partial = true;
-        config2.sync_config->is_partial = true;
-        {
-            auto realm = Realm::get_shared_realm(config2);
-            realm->begin_transaction();
-            realm->read_group().get_table("class_object")->create_object();
-            realm->commit_transaction();
-            wait_for_upload(*realm);
-        }
-
-        std::atomic<bool> called{false};
-        auto task = Realm::get_synchronized_realm(config);
-        task->start([&](auto, auto error) {
-            std::lock_guard<std::mutex> lock(mutex);
-            REQUIRE(!error);
-            called = true;
-        });
-        util::EventLoop::main().run_until([&]{ return called.load(); });
-        std::lock_guard<std::mutex> lock(mutex);
-        REQUIRE(called);
-
-        // No subscriptions, so no objects
-        REQUIRE(Realm::get_shared_realm(config)->read_group().get_table("class_object")->size() == 0);
-    }
-
-    SECTION("can download multiple Realms at a time") {
-        SyncTestFile config1(server, "realm1");
-        SyncTestFile config2(server, "realm2");
-        SyncTestFile config3(server, "realm3");
-        SyncTestFile config4(server, "realm4");
-
-        std::vector<std::shared_ptr<AsyncOpenTask>> tasks = {
-            Realm::get_synchronized_realm(config1),
-            Realm::get_synchronized_realm(config2),
-            Realm::get_synchronized_realm(config3),
-            Realm::get_synchronized_realm(config4),
-        };
-
-        std::atomic<int> completed{0};
-        for (auto& task : tasks) {
-            task->start([&](auto, auto) {
-                ++completed;
-            });
-        }
-        util::EventLoop::main().run_until([&]{ return completed == 4; });
-    }
-}
-#endif
-
-TEST_CASE("SharedRealm: notifications") {
-    if (!util::EventLoop::has_implementation())
-        return;
-
-    TestFile config;
-    config.schema_version = 0;
-    config.schema = Schema{
-        {"object", {
-            {"value", PropertyType::Int}
-        }},
-    };
-
-    struct Context : BindingContext {
-        size_t* change_count;
-        Context(size_t* out) : change_count(out) { }
-
-        void did_change(std::vector<ObserverState> const&, std::vector<void*> const&, bool) override
-        {
-            ++*change_count;
-        }
-    };
-
-    size_t change_count = 0;
-    auto realm = Realm::get_shared_realm(config);
-    realm->read_group();
-    realm->m_binding_context.reset(new Context{&change_count});
-    realm->m_binding_context->realm = realm;
-
-    SECTION("local notifications are sent synchronously") {
-        realm->begin_transaction();
-        REQUIRE(change_count == 0);
-        realm->commit_transaction();
-        REQUIRE(change_count == 1);
-    }
-
-    SECTION("remote notifications are sent asynchronously") {
-        auto r2 = Realm::get_shared_realm(config);
-        r2->begin_transaction();
-        r2->commit_transaction();
-        REQUIRE(change_count == 0);
-        util::EventLoop::main().run_until([&]{ return change_count > 0; });
-        REQUIRE(change_count == 1);
-    }
-
-    SECTION("refresh() from within changes_available() refreshes") {
-        struct Context : BindingContext {
-            Realm& realm;
-            Context(Realm& realm) : realm(realm) { }
-
-            void changes_available() override
-            {
-                REQUIRE(realm.refresh());
-            }
-        };
-        realm->m_binding_context.reset(new Context{*realm});
-        realm->set_auto_refresh(false);
-
-        auto r2 = Realm::get_shared_realm(config);
-        r2->begin_transaction();
-        r2->commit_transaction();
-        realm->notify();
-        // Should return false as the realm was already advanced
-        REQUIRE_FALSE(realm->refresh());
-    }
-
-    SECTION("refresh() from within did_change() is a no-op") {
-        struct Context : BindingContext {
-            Realm& realm;
-            Context(Realm& realm) : realm(realm) { }
-
-            void did_change(std::vector<ObserverState> const&, std::vector<void*> const&, bool) override
-            {
-                // Create another version so that refresh() could do something
-                auto r2 = Realm::get_shared_realm(realm.config());
-                r2->begin_transaction();
-                r2->commit_transaction();
-
-                // Should be a no-op
-                REQUIRE_FALSE(realm.refresh());
-            }
-        };
-        realm->m_binding_context.reset(new Context{*realm});
-
-        auto r2 = Realm::get_shared_realm(config);
-        r2->begin_transaction();
-        r2->commit_transaction();
-        REQUIRE(realm->refresh());
-
-        auto ver = realm->current_transaction_version();
-        realm->m_binding_context.reset();
-        // Should advance to the version created in the previous did_change()
-        REQUIRE(realm->refresh());
-        auto new_ver = realm->current_transaction_version();
-        REQUIRE(*new_ver > *ver);
-        // No more versions, so returns false
-        REQUIRE_FALSE(realm->refresh());
-    }
-
-    SECTION("begin_write() from within did_change() produces recursive notifications") {
-        struct Context : BindingContext {
-            Realm& realm;
-            size_t calls = 0;
-            Context(Realm& realm) : realm(realm) { }
-
-            void did_change(std::vector<ObserverState> const&, std::vector<void*> const&, bool) override
-            {
-                ++calls;
-                if (realm.is_in_transaction())
-                    return;
-
-                // Create another version so that begin_write() advances the version
-                auto r2 = Realm::get_shared_realm(realm.config());
-                r2->begin_transaction();
-                r2->commit_transaction();
-
-                realm.begin_transaction();
-                realm.cancel_transaction();
-            }
-        };
-        auto context = new Context{*realm};
-        realm->m_binding_context.reset(context);
-
-        auto r2 = Realm::get_shared_realm(config);
-        r2->begin_transaction();
-        r2->commit_transaction();
-        REQUIRE(realm->refresh());
-        REQUIRE(context->calls == 2);
-
-        // Despite not sending a new notification we did advance the version, so
-        // no more versions to refresh to
-        REQUIRE_FALSE(realm->refresh());
-    }
-}
-
-TEST_CASE("SharedRealm: schema updating from external changes") {
-    TestFile config;
-    config.schema_version = 0;
-    config.schema_mode = SchemaMode::Additive;
-    config.schema = Schema{
-        {"object", {
-            {"value", PropertyType::Int, Property::IsPrimary{true}},
-            {"value 2", PropertyType::Int, Property::IsPrimary{false}, Property::IsIndexed{true}},
-        }},
-    };
-
-    SECTION("newly added columns update table columns but are not added to properties") {
-        // Does this test add any value when column keys are stable?
-        auto r1 = Realm::get_shared_realm(config);
-        auto r2 = Realm::get_shared_realm(config);
-        auto test = [&] {
-            r2->begin_transaction();
-            r2->read_group().get_table("class_object")->add_column(type_String, "new col");
-            r2->commit_transaction();
-
-            auto& object_schema = *r1->schema().find("object");
-            REQUIRE(object_schema.persisted_properties.size() == 2);
-            ColKey col = object_schema.persisted_properties[0].column_key;
-            r1->refresh();
-            REQUIRE(object_schema.persisted_properties[0].column_key == col);
-        };
-        SECTION("with an active read transaction") {
-            r1->read_group();
-            test();
-        }
-        SECTION("without an active read transaction") {
-            r1->invalidate();
-            test();
-        }
-    }
-
-    SECTION("beginning a read transaction checks for incompatible changes") {
-        auto r = Realm::get_shared_realm(config);
-        r->invalidate();
-
-        auto& db = TestHelper::get_db(r);
-        WriteTransaction wt(db);
-        auto& table = *wt.get_table("class_object");
-
-        SECTION("removing a property") {
-            table.remove_column(table.get_column_key("value"));
-            wt.commit();
-            REQUIRE_THROWS_WITH(r->refresh(),
-                                Catch::Matchers::Contains("Property 'object.value' has been removed."));
-        }
-
-        SECTION("change property type") {
-            table.remove_column(table.get_column_key("value 2"));
-            table.add_column(type_Float, "value 2");
-            wt.commit();
-            REQUIRE_THROWS_WITH(r->refresh(),
-                                Catch::Matchers::Contains("Property 'object.value 2' has been changed from 'int' to 'float'"));
-        }
-
-        SECTION("make property optional") {
-            table.remove_column(table.get_column_key("value 2"));
-            table.add_column(type_Int, "value 2", true);
-            wt.commit();
-            REQUIRE_THROWS_WITH(r->refresh(),
-                                Catch::Matchers::Contains("Property 'object.value 2' has been made optional"));
-        }
-
-        SECTION("recreate column with no changes") {
-            table.remove_column(table.get_column_key("value 2"));
-            table.add_column(type_Int, "value 2");
-            wt.commit();
-            REQUIRE_NOTHROW(r->refresh());
-        }
-
-        SECTION("remove index from non-PK") {
-            table.remove_search_index(table.get_column_key("value 2"));
-            wt.commit();
-            REQUIRE_NOTHROW(r->refresh());
-        }
-    }
-}
-
-TEST_CASE("SharedRealm: close()") {
-    TestFile config;
-    config.schema_version = 1;
-    config.schema = Schema{
-        {"object", {
-            {"value", PropertyType::Int}
-        }},
-        {"list", {
-            {"list", PropertyType::Object|PropertyType::Array, "object"}
-        }},
-    };
-
-    auto realm = Realm::get_shared_realm(config);
-
-    SECTION("all functions throw ClosedRealmException after close") {
-        realm->close();
-
-        REQUIRE(realm->is_closed());
-
-        REQUIRE_THROWS_AS(realm->read_group(), ClosedRealmException);
-        REQUIRE_THROWS_AS(realm->begin_transaction(), ClosedRealmException);
-        REQUIRE(!realm->is_in_transaction());
-        REQUIRE_THROWS_AS(realm->commit_transaction(), InvalidTransactionException);
-        REQUIRE_THROWS_AS(realm->cancel_transaction(), InvalidTransactionException);
-
-        REQUIRE_THROWS_AS(realm->refresh(), ClosedRealmException);
-        REQUIRE_THROWS_AS(realm->invalidate(), ClosedRealmException);
-        REQUIRE_THROWS_AS(realm->compact(), ClosedRealmException);
-    }
-
-    SECTION("fully closes database file even with live notifiers") {
-        auto& group = realm->read_group();
-        realm->begin_transaction();
-        auto obj = ObjectStore::table_for_object_type(group, "list")->create_object();
-        realm->commit_transaction();
-
-        Results results(realm, ObjectStore::table_for_object_type(group, "object"));
-        List list(realm, obj.get_linklist("list"));
-        Object object(realm, obj);
-
-        auto obj_token = object.add_notification_callback([](CollectionChangeSet, std::exception_ptr) {});
-        auto list_token = list.add_notification_callback([](CollectionChangeSet, std::exception_ptr) {});
-        auto results_token = results.add_notification_callback([](CollectionChangeSet, std::exception_ptr) {});
-
-        // Perform a dummy transaction to ensure the notifiers actually acquire
-        // resources that need to be closed
-        realm->begin_transaction();
-        realm->commit_transaction();
-
-        realm->close();
-
-        // Verify that we're able to acquire an exclusive lock
-        REQUIRE(DB::call_with_lock(config.path, [](auto) {}));
-    }
-}
-
-TEST_CASE("ShareRealm: in-memory mode from buffer") {
-    TestFile config;
-    config.schema_version = 1;
-    config.schema = Schema{
-        {"object", {
-            {"value", PropertyType::Int}
-        }},
-    };
-
-    SECTION("Save and open Realm from in-memory buffer") {
-        // Write in-memory copy of Realm to a buffer
-        auto realm = Realm::get_shared_realm(config);
-        OwnedBinaryData realm_buffer = realm->write_copy();
-
-        // Open the buffer as a new (immutable in-memory) Realm
-        realm::Realm::Config config2;
-        config2.in_memory = true;
-        config2.schema_mode = SchemaMode::Immutable;
-        config2.realm_data = realm_buffer.get();
-
-        auto realm2 = Realm::get_shared_realm(config2);
-
-        // Verify that it can read the schema and that it is the same
-        REQUIRE(realm->schema().size() == 1);
-        auto it = realm->schema().find("object");
-        auto table = realm->read_group().get_table("class_object");
-        REQUIRE(it != realm->schema().end());
-        REQUIRE(it->table_key == table->get_key());
-        REQUIRE(it->persisted_properties.size() == 1);
-        REQUIRE(it->persisted_properties[0].name == "value");
-        REQUIRE(it->persisted_properties[0].column_key == table->get_column_key("value"));
-
-        // Test invalid configs
-        realm::Realm::Config config3;
-        config3.realm_data = realm_buffer.get();
-        REQUIRE_THROWS(Realm::get_shared_realm(config3)); // missing in_memory and immutable
-
-        config3.in_memory = true;
-        config3.schema_mode = SchemaMode::Immutable;
-        config3.path = "path";
-        REQUIRE_THROWS(Realm::get_shared_realm(config3)); // both buffer and path
-
-        config3.path = "";
-        config3.encryption_key = {'a'};
-        REQUIRE_THROWS(Realm::get_shared_realm(config3)); // both buffer and encryption
-    }
-}
-
-TEST_CASE("ShareRealm: realm closed in did_change callback") {
-    TestFile config;
-    config.schema_version = 1;
-    config.schema = Schema{
-        {"object", {
-            {"value", PropertyType::Int}
-        }},
-    };
-    config.automatic_change_notifications = false;
-    auto r1 = Realm::get_shared_realm(config);
-
-    r1->begin_transaction();
-    auto table = r1->read_group().get_table("class_object");
-    table->create_object();
-    r1->commit_transaction();
-
-    // Cannot be a member var of Context since Realm.close will free the context.
-    static SharedRealm* shared_realm;
-    shared_realm = &r1;
-    struct Context : public BindingContext {
-        void did_change(std::vector<ObserverState> const&, std::vector<void*> const&, bool) override
-        {
-            (*shared_realm)->close();
-            (*shared_realm).reset();
-        }
-    };
-
-    SECTION("did_change") {
-        r1->m_binding_context.reset(new Context());
-        r1->invalidate();
-
-        auto r2 = Realm::get_shared_realm(config);
-        r2->begin_transaction();
-        r2->read_group().get_table("class_object")->create_object();
-        r2->commit_transaction();
-        r2.reset();
-
-        r1->notify();
-    }
-
-    SECTION("did_change with async results") {
-        r1->m_binding_context.reset(new Context());
-        Results results(r1, table->where());
-        auto token = results.add_notification_callback([&](CollectionChangeSet, std::exception_ptr) {
-            // Should not be called.
-            REQUIRE(false);
-        });
-
-        auto r2 = Realm::get_shared_realm(config);
-        r2->begin_transaction();
-        r2->read_group().get_table("class_object")->create_object();
-        r2->commit_transaction();
-        r2.reset();
-
-        auto coordinator = _impl::RealmCoordinator::get_coordinator(config.path);
-        coordinator->on_change();
-
-        r1->notify();
-    }
-
-    SECTION("refresh") {
-        r1->m_binding_context.reset(new Context());
-
-        auto r2 = Realm::get_shared_realm(config);
-        r2->begin_transaction();
-        r2->read_group().get_table("class_object")->create_object();
-        r2->commit_transaction();
-        r2.reset();
-
-        REQUIRE_FALSE(r1->refresh());
-    }
-
-    shared_realm = nullptr;
-}
-
-TEST_CASE("RealmCoordinator: schema cache") {
-    TestFile config;
-    auto coordinator = _impl::RealmCoordinator::get_coordinator(config.path);
-
-    Schema cache_schema;
-    uint64_t cache_sv = -1, cache_tv = -1;
-
-    Schema schema{
-        {"object", {
-            {"value", PropertyType::Int}
-        }},
-    };
-    Schema schema2{
-        {"object", {
-            {"value", PropertyType::Int},
-        }},
-        {"object 2", {
-            {"value", PropertyType::Int},
-        }},
-    };
-
-    SECTION("valid initial schema sets cache") {
-        coordinator->cache_schema(schema, 5, 10);
-        REQUIRE(coordinator->get_cached_schema(cache_schema, cache_sv, cache_tv));
-        REQUIRE(cache_schema == schema);
-        REQUIRE(cache_sv == 5);
-        REQUIRE(cache_tv == 10);
-    }
-
-    SECTION("cache can be updated with newer schema") {
-        coordinator->cache_schema(schema, 5, 10);
-        coordinator->cache_schema(schema2, 6, 11);
-        REQUIRE(coordinator->get_cached_schema(cache_schema, cache_sv, cache_tv));
-        REQUIRE(cache_schema == schema2);
-        REQUIRE(cache_sv == 6);
-        REQUIRE(cache_tv == 11);
-    }
-
-    SECTION("empty schema is ignored") {
-        coordinator->cache_schema(Schema{}, 5, 10);
-        REQUIRE_FALSE(coordinator->get_cached_schema(cache_schema, cache_sv, cache_tv));
-
-        coordinator->cache_schema(schema, 5, 10);
-        coordinator->cache_schema(Schema{}, 5, 10);
-        REQUIRE(coordinator->get_cached_schema(cache_schema, cache_sv, cache_tv));
-        REQUIRE(cache_schema == schema);
-        REQUIRE(cache_sv == 5);
-        REQUIRE(cache_tv == 10);
-    }
-
-    SECTION("schema for older transaction is ignored") {
-        coordinator->cache_schema(schema, 5, 10);
-        coordinator->cache_schema(schema2, 4, 8);
-
-        REQUIRE(coordinator->get_cached_schema(cache_schema, cache_sv, cache_tv));
-        REQUIRE(cache_schema == schema);
-        REQUIRE(cache_sv == 5);
-        REQUIRE(cache_tv == 10);
-
-        coordinator->advance_schema_cache(10, 20);
-        coordinator->cache_schema(schema, 6, 15);
-        REQUIRE(coordinator->get_cached_schema(cache_schema, cache_sv, cache_tv));
-        REQUIRE(cache_tv == 20); // should not have dropped to 15
-    }
-
-    SECTION("advance_schema() from transaction version bumps transaction version") {
-        coordinator->cache_schema(schema, 5, 10);
-        coordinator->advance_schema_cache(10, 12);
-        REQUIRE(coordinator->get_cached_schema(cache_schema, cache_sv, cache_tv));
-        REQUIRE(cache_schema == schema);
-        REQUIRE(cache_sv == 5);
-        REQUIRE(cache_tv == 12);
-    }
-
-    SECTION("advance_schema() ending before transaction version does nothing") {
-        coordinator->cache_schema(schema, 5, 10);
-        coordinator->advance_schema_cache(8, 9);
-        REQUIRE(coordinator->get_cached_schema(cache_schema, cache_sv, cache_tv));
-        REQUIRE(cache_schema == schema);
-        REQUIRE(cache_sv == 5);
-        REQUIRE(cache_tv == 10);
-    }
-
-    SECTION("advance_schema() extending over transaction version bumps version") {
-        coordinator->cache_schema(schema, 5, 10);
-        coordinator->advance_schema_cache(3, 15);
-        REQUIRE(coordinator->get_cached_schema(cache_schema, cache_sv, cache_tv));
-        REQUIRE(cache_schema == schema);
-        REQUIRE(cache_sv == 5);
-        REQUIRE(cache_tv == 15);
-    }
-
-    SECTION("advance_schema() with no cahced schema does nothing") {
-        coordinator->advance_schema_cache(3, 15);
-        REQUIRE_FALSE(coordinator->get_cached_schema(cache_schema, cache_sv, cache_tv));
-    }
-}
-
-TEST_CASE("SharedRealm: coordinator schema cache") {
-    TestFile config;
-    auto r = Realm::get_shared_realm(config);
-    auto coordinator = _impl::RealmCoordinator::get_coordinator(config.path);
-
-    Schema cache_schema;
-    uint64_t cache_sv = -1, cache_tv = -1;
-
-    Schema schema{
-        {"object", {
-            {"value", PropertyType::Int}
-        }},
-    };
-    Schema schema2{
-        {"object", {
-            {"value", PropertyType::Int},
-        }},
-        {"object 2", {
-            {"value", PropertyType::Int},
-        }},
-    };
-
-    class ExternalWriter {
-    private:
-        std::shared_ptr<Realm> m_realm;
-    public:
-        WriteTransaction wt;
-        ExternalWriter(Realm::Config const& config)
-        : m_realm([&] {
-            auto c = config;
-            c.scheduler = util::Scheduler::get_frozen();
-            return _impl::RealmCoordinator::get_coordinator(c.path)->get_realm(c, util::none);
-        }())
-        , wt(TestHelper::get_db(m_realm))
-        {
-        }
-    };
-
-    auto external_write = [&](Realm::Config const& config, auto&& fn) {
-        ExternalWriter wt(config);
-        fn(wt.wt);
-        wt.wt.commit();
-    };
-
-    SECTION("is initially empty for uninitialized file") {
-        REQUIRE_FALSE(coordinator->get_cached_schema(cache_schema, cache_sv, cache_tv));
-    }
-    r->update_schema(schema);
-
-    SECTION("is populated after calling update_schema()") {
-        REQUIRE(coordinator->get_cached_schema(cache_schema, cache_sv, cache_tv));
-        REQUIRE(cache_sv == 0);
-        REQUIRE(cache_schema == schema);
-        REQUIRE(cache_schema.begin()->persisted_properties[0].column_key != ColKey{});
-    }
-
-    coordinator = nullptr;
-    r = nullptr;
-    r = Realm::get_shared_realm(config);
-    coordinator = _impl::RealmCoordinator::get_coordinator(config.path);
-    REQUIRE(coordinator->get_cached_schema(cache_schema, cache_sv, cache_tv));
-
-    SECTION("is populated after opening an initialized file") {
-        REQUIRE(cache_sv == 0);
-        REQUIRE(cache_tv == 2); // with in-realm history the version doesn't reset
-        REQUIRE(cache_schema == schema);
-        REQUIRE(cache_schema.begin()->persisted_properties[0].column_key != ColKey{});
-    }
-
-    SECTION("transaction version is bumped after a local write") {
-        auto tv = cache_tv;
-        r->begin_transaction();
-        r->commit_transaction();
-        REQUIRE(coordinator->get_cached_schema(cache_schema, cache_sv, cache_tv));
-        REQUIRE(cache_tv == tv + 1);
-    }
-
-    SECTION("notify() without a read transaction does not bump transaction version") {
-        auto tv = cache_tv;
-
-        SECTION("non-schema change") {
-            external_write(config, [](auto& wt) {
-                wt.get_table("class_object")->create_object();
-            });
-        }
-        SECTION("schema change") {
-            external_write(config, [](auto& wt) {
-                wt.add_table("class_object 2");
-            });
-        }
-
-        r->notify();
-        REQUIRE(coordinator->get_cached_schema(cache_schema, cache_sv, cache_tv));
-        REQUIRE(cache_tv == tv);
-        REQUIRE(cache_schema == schema);
-    }
-
-    SECTION("notify() with a read transaction bumps transaction version") {
-        r->read_group();
-        external_write(config, [](auto& wt) {
-            wt.get_table("class_object")->create_object();
-        });
-
-        r->notify();
-        auto tv = cache_tv;
-        REQUIRE(coordinator->get_cached_schema(cache_schema, cache_sv, cache_tv));
-        REQUIRE(cache_tv == tv + 1);
-    }
-
-    SECTION("notify() with a read transaction updates schema folloing external schema change") {
-        r->read_group();
-        external_write(config, [](auto& wt) {
-            wt.add_table("class_object 2");
-        });
-
-        r->notify();
-        auto tv = cache_tv;
-        REQUIRE(coordinator->get_cached_schema(cache_schema, cache_sv, cache_tv));
-        REQUIRE(cache_tv == tv + 1);
-        REQUIRE(cache_schema.size() == 2);
-        REQUIRE(cache_schema.find("object 2") != cache_schema.end());
-    }
-
-    SECTION("transaction version is bumped after refresh() following external non-schema write") {
-        external_write(config, [](auto& wt) {
-            wt.get_table("class_object")->create_object();
-        });
-
-        r->refresh();
-        auto tv = cache_tv;
-        REQUIRE(coordinator->get_cached_schema(cache_schema, cache_sv, cache_tv));
-        REQUIRE(cache_tv == tv + 1);
-    }
-
-    SECTION("schema is reread following refresh() over external schema change") {
-        external_write(config, [](auto& wt) {
-            wt.add_table("class_object 2");
-        });
-
-        r->refresh();
-        auto tv = cache_tv;
-        REQUIRE(coordinator->get_cached_schema(cache_schema, cache_sv, cache_tv));
-        REQUIRE(cache_tv == tv + 1);
-        REQUIRE(cache_schema.size() == 2);
-        REQUIRE(cache_schema.find("object 2") != cache_schema.end());
-    }
-
-    SECTION("update_schema() to version already on disk updates cache") {
-        r->read_group();
-        external_write(config, [](auto& wt) {
-            auto table = wt.add_table("class_object 2");
-            table->add_column(type_Int, "value");
-        });
-
-        auto tv = cache_tv;
-        r->update_schema(schema2);
-
-        REQUIRE(coordinator->get_cached_schema(cache_schema, cache_sv, cache_tv));
-        REQUIRE(cache_tv == tv + 1); // only +1 because update_schema() did not perform a write
-        REQUIRE(cache_schema.size() == 2);
-        REQUIRE(cache_schema.find("object 2") != cache_schema.end());
-    }
-
-    SECTION("update_schema() to version already on disk updates cache") {
-        r->read_group();
-        external_write(config, [](auto& wt) {
-            auto table = wt.add_table("class_object 2");
-            table->add_column(type_Int, "value");
-        });
-
-        auto tv = cache_tv;
-        r->update_schema(schema2);
-
-        REQUIRE(coordinator->get_cached_schema(cache_schema, cache_sv, cache_tv));
-        REQUIRE(cache_tv == tv + 1); // only +1 because update_schema() did not perform a write
-        REQUIRE(cache_schema.size() == 2);
-        REQUIRE(cache_schema.find("object 2") != cache_schema.end());
-    }
-
-    SECTION("update_schema() to version populated on disk while waiting for the write lock updates cache") {
-        r->read_group();
-
-        // We want to commit the write while we're waiting on the write lock on
-        // this thread, which can't really be done in a properly synchronized manner
-        std::chrono::microseconds wait_time{5000};
-#if REALM_ANDROID
-        // When running on device or in an emulator we need to wait longer due
-        // to them being slow
-        wait_time *= 10;
-#endif
-
-        bool did_run = false;
-        JoiningThread thread([&] {
-            ExternalWriter writer(config);
-            if (writer.wt.get_table("class_object 2"))
-                return;
-            did_run = true;
-
-            auto table = writer.wt.add_table("class_object 2");
-            table->add_column(type_Int, "value");
-            std::this_thread::sleep_for(wait_time * 2);
-            writer.wt.commit();
-        });
-        std::this_thread::sleep_for(wait_time);
-
-        auto tv = cache_tv;
-        r->update_schema(Schema{
-            {"object", {{"value", PropertyType::Int}}},
-            {"object 2", {{"value", PropertyType::Int}}},
-        });
-
-        // just skip the test if the timing was wrong to avoid spurious failures
-        if (!did_run)
-            return;
-
-        REQUIRE(coordinator->get_cached_schema(cache_schema, cache_sv, cache_tv));
-        REQUIRE(cache_tv == tv + 1); // only +1 because update_schema()'s write was rolled back
-        REQUIRE(cache_schema.size() == 2);
-        REQUIRE(cache_schema.find("object 2") != cache_schema.end());
-    }
-}
-
-TEST_CASE("SharedRealm: dynamic schema mode doesn't invalidate object schema pointers when schema hasn't changed") {
-    TestFile config;
-
-    // Prepopulate the Realm with the schema.
-    Realm::Config config_with_schema = config;
-    config_with_schema.schema_version = 1;
-    config_with_schema.schema_mode = SchemaMode::Automatic;
-    config_with_schema.schema = Schema{
-        {"object", {
-            {"value", PropertyType::Int, Property::IsPrimary{true}},
-            {"value 2", PropertyType::Int, Property::IsPrimary{false}, Property::IsIndexed{true}},
-        }}
-    };
-    auto r1 = Realm::get_shared_realm(config_with_schema);
-
-    // Retrieve the object schema in dynamic mode.
-    auto r2 = Realm::get_shared_realm(config);
-    auto* object_schema = &*r2->schema().find("object");
-
-    // Perform an empty write to create a new version, resulting in the other Realm needing to re-read the schema.
-    r1->begin_transaction();
-    r1->commit_transaction();
-
-    // Advance to the latest version, and verify the object schema is at the same location in memory.
-    r2->read_group();
-    REQUIRE(object_schema == &*r2->schema().find("object"));
-}
-
-TEST_CASE("SharedRealm: SchemaChangedFunction") {
-    struct Context : BindingContext {
-        size_t* change_count;
-        Schema* schema;
-        Context(size_t* count_out, Schema* schema_out) : change_count(count_out), schema(schema_out) { }
-
-        void schema_did_change(Schema const& changed_schema) override
-        {
-            ++*change_count;
-            *schema = changed_schema;
-        }
-    };
-
-    size_t schema_changed_called = 0;
-    Schema changed_fixed_schema;
-    TestFile config;
-    auto dynamic_config = config;
-
-    config.schema = Schema{
-        {"object1", {
-            {"value", PropertyType::Int},
-        }},
-        {"object2", {
-            {"value", PropertyType::Int},
-        }}
-    };
-    config.schema_version = 1;
-    auto r1 = Realm::get_shared_realm(config);
-    r1->read_group();
-    r1->m_binding_context.reset(new Context(&schema_changed_called, &changed_fixed_schema));
-
-    SECTION("Fixed schema") {
-        SECTION("update_schema") {
-            auto new_schema = Schema{
-                {"object3", {
-                    {"value", PropertyType::Int},
-                }}
-            };
-            r1->update_schema(new_schema, 2);
-            REQUIRE(schema_changed_called == 1);
-            REQUIRE(changed_fixed_schema.find("object3")->property_for_name("value")->column_key != ColKey{});
-        }
-
-        SECTION("Open a new Realm instance with same config won't trigger") {
-            auto r2 = Realm::get_shared_realm(config);
-            REQUIRE(schema_changed_called == 0);
-        }
-
-        SECTION("Non schema related transaction doesn't trigger") {
-            auto r2 = Realm::get_shared_realm(config);
-            r2->begin_transaction();
-            r2->commit_transaction();
-            r1->refresh();
-            REQUIRE(schema_changed_called == 0);
-        }
-
-        SECTION("Schema is changed by another Realm") {
-            auto r2 = Realm::get_shared_realm(config);
-            r2->begin_transaction();
-            r2->read_group().get_table("class_object1")->add_column(type_String, "new col");
-            r2->commit_transaction();
-            r1->refresh();
-            REQUIRE(schema_changed_called == 1);
-            REQUIRE(changed_fixed_schema.find("object1")->property_for_name("value")->column_key != ColKey{});
-        }
-
-        // This is not a valid use case. m_schema won't be refreshed.
-        SECTION("Schema is changed by this Realm won't trigger") {
-            r1->begin_transaction();
-            r1->read_group().get_table("class_object1")->add_column(type_String, "new col");
-            r1->commit_transaction();
-            REQUIRE(schema_changed_called == 0);
-        }
-    }
-
-    SECTION("Dynamic schema") {
-        size_t dynamic_schema_changed_called = 0;
-        Schema changed_dynamic_schema;
-        auto r2 = Realm::get_shared_realm(dynamic_config);
-        r2->m_binding_context.reset(new Context(&dynamic_schema_changed_called, &changed_dynamic_schema));
-
-        SECTION("set_schema_subset") {
-            auto new_schema = Schema{
-                {"object1", {
-                    {"value", PropertyType::Int},
-                }}
-            };
-            r2->set_schema_subset(new_schema);
-            REQUIRE(schema_changed_called == 0);
-            REQUIRE(dynamic_schema_changed_called == 1);
-            REQUIRE(changed_dynamic_schema.find("object1")->property_for_name("value")->column_key != ColKey{});
-        }
-
-        SECTION("Non schema related transaction will always trigger in dynamic mode") {
-            auto r1 = Realm::get_shared_realm(config);
-            // An empty transaction will trigger the schema changes always in dynamic mode.
-            r1->begin_transaction();
-            r1->commit_transaction();
-            r2->refresh();
-            REQUIRE(dynamic_schema_changed_called == 1);
-            REQUIRE(changed_dynamic_schema.find("object1")->property_for_name("value")->column_key != ColKey{});
-        }
-
-        SECTION("Schema is changed by another Realm") {
-            r1->begin_transaction();
-            r1->read_group().get_table("class_object1")->add_column(type_String, "new col");
-            r1->commit_transaction();
-            r2->refresh();
-            REQUIRE(dynamic_schema_changed_called == 1);
-            REQUIRE(changed_dynamic_schema.find("object1")->property_for_name("value")->column_key != ColKey{});
-        }
-    }
-}
-
-#ifndef _WIN32
-TEST_CASE("SharedRealm: compact on launch") {
-    // Make compactable Realm
-    TestFile config;
-    config.automatic_change_notifications = false;
-    int num_opens = 0;
-    config.should_compact_on_launch_function = [&](size_t total_bytes, size_t used_bytes) {
-        REQUIRE(total_bytes > used_bytes);
-        num_opens++;
-        return num_opens != 2;
-    };
-    config.schema = Schema{
-        {"object", {
-            {"value", PropertyType::String}
-        }},
-    };
-    REQUIRE(num_opens == 0);
-    auto r = Realm::get_shared_realm(config);
-    REQUIRE(num_opens == 1);
-    r->begin_transaction();
-    auto table = r->read_group().get_table("class_object");
-    size_t count = 1000;
-    for (size_t i = 0; i < count; ++i)
-        table->create_object().set_all(util::format("Foo_%1", i % 10).c_str());
-    r->commit_transaction();
-    REQUIRE(table->size() == count);
-    r->close();
-
-    SECTION("compact reduces the file size") {
-        // Confirm expected sizes before and after opening the Realm
-        size_t size_before = size_t(File(config.path).get_size());
-        r = Realm::get_shared_realm(config);
-        REQUIRE(num_opens == 2);
-        r->close();
-        REQUIRE(size_t(File(config.path).get_size()) == size_before); // File size after returning false
-        r = Realm::get_shared_realm(config);
-        REQUIRE(num_opens == 3);
-        REQUIRE(size_t(File(config.path).get_size()) < size_before); // File size after returning true
-
-        // Validate that the file still contains what it should
-        REQUIRE(r->read_group().get_table("class_object")->size() == count);
-
-        // Registering for a collection notification shouldn't crash when compact on launch is used.
-        Results results(r, r->read_group().get_table("class_object"));
-        results.add_notification_callback([](CollectionChangeSet const&, std::exception_ptr) { });
-        r->close();
-    }
-
-    SECTION("compact function does not get invoked if realm is open on another thread") {
-        config.scheduler = util::Scheduler::get_frozen();
-        r = Realm::get_shared_realm(config);
-        REQUIRE(num_opens == 2);
-        std::thread([&]{
-            auto r2 = Realm::get_shared_realm(config);
-            REQUIRE(num_opens == 2);
-        }).join();
-        r->close();
-        std::thread([&]{
-            auto r3 = Realm::get_shared_realm(config);
-            REQUIRE(num_opens == 3);
-        }).join();
-    }
-}
-#endif
-
-struct ModeAutomatic {
-    static SchemaMode mode() { return SchemaMode::Automatic; }
-    static bool should_call_init_on_version_bump() { return false; }
-};
-struct ModeAdditive {
-    static SchemaMode mode() { return SchemaMode::Additive; }
-    static bool should_call_init_on_version_bump() { return false; }
-};
-struct ModeManual {
-    static SchemaMode mode() { return SchemaMode::Manual; }
-    static bool should_call_init_on_version_bump() { return false; }
-};
-struct ModeResetFile {
-    static SchemaMode mode() { return SchemaMode::ResetFile; }
-    static bool should_call_init_on_version_bump() { return true; }
-};
-
-TEMPLATE_TEST_CASE("SharedRealm: update_schema with initialization_function", "[init][update_schema]",
-                   ModeAutomatic, ModeAdditive, ModeManual, ModeResetFile) {
-    TestFile config;
-    config.schema_mode = TestType::mode();
-    bool initialization_function_called = false;
-    uint64_t schema_version_in_callback = -1;
-    Schema schema_in_callback;
-    auto initialization_function = [&initialization_function_called, &schema_version_in_callback,
-                                    &schema_in_callback](auto shared_realm) {
-        REQUIRE(shared_realm->is_in_transaction());
-        initialization_function_called = true;
-        schema_version_in_callback = shared_realm->schema_version();
-        schema_in_callback = shared_realm->schema();
-    };
-
-    Schema schema{
-        {"object", {
-            {"value", PropertyType::String}
-        }},
-    };
-
-    SECTION("call initialization function directly by update_schema") {
-        // Open in dynamic mode with no schema specified
-        auto realm = Realm::get_shared_realm(config);
-        REQUIRE_FALSE(initialization_function_called);
-
-        realm->update_schema(schema, 0, nullptr, initialization_function);
-        REQUIRE(initialization_function_called);
-        REQUIRE(schema_version_in_callback == 0);
-        REQUIRE(schema_in_callback.compare(schema).size() == 0);
-    }
-
-    config.schema_version = 0;
-    config.schema = schema;
-
-    SECTION("initialization function should be called for unversioned realm") {
-        config.initialization_function = initialization_function;
-        Realm::get_shared_realm(config);
-        REQUIRE(initialization_function_called);
-        REQUIRE(schema_version_in_callback == 0);
-        REQUIRE(schema_in_callback.compare(schema).size() == 0);
-    }
-
-    SECTION("initialization function for versioned realm") {
-        // Initialize v0
-        Realm::get_shared_realm(config);
-
-        config.schema_version = 1;
-        config.initialization_function = initialization_function;
-        Realm::get_shared_realm(config);
-        REQUIRE(initialization_function_called == TestType::should_call_init_on_version_bump());
-        if (TestType::should_call_init_on_version_bump()) {
-            REQUIRE(schema_version_in_callback == 1);
-            REQUIRE(schema_in_callback.compare(schema).size() == 0);
-        }
-    }
-}
-
-TEST_CASE("BindingContext is notified about delivery of change notifications") {
-    _impl::RealmCoordinator::assert_no_open_realms();
-
-    InMemoryTestFile config;
-    config.automatic_change_notifications = false;
-
-    auto r = Realm::get_shared_realm(config);
-    r->update_schema({
-        {"object", {
-            {"value", PropertyType::Int}
-        }},
-    });
-
-    auto coordinator = _impl::RealmCoordinator::get_coordinator(config.path);
-    auto table = r->read_group().get_table("class_object");
-
-    SECTION("BindingContext notified even if no callbacks are registered") {
-        static int binding_context_start_notify_calls = 0;
-        static int binding_context_end_notify_calls = 0;
-        struct Context : BindingContext {
-            void will_send_notifications() override
-            {
-                ++binding_context_start_notify_calls;
-            }
-
-            void did_send_notifications() override
-            {
-                ++binding_context_end_notify_calls;
-            }
-        };
-        r->m_binding_context.reset(new Context());
-
-        SECTION("local commit") {
-            binding_context_start_notify_calls = 0;
-            binding_context_end_notify_calls = 0;
-            coordinator->on_change();
-            r->begin_transaction();
-            REQUIRE(binding_context_start_notify_calls == 1);
-            REQUIRE(binding_context_end_notify_calls == 1);
-            r->cancel_transaction();
-        }
-
-        SECTION("remote commit") {
-            binding_context_start_notify_calls = 0;
-            binding_context_end_notify_calls = 0;
-            JoiningThread([&] {
-                auto r2 = coordinator->get_realm(util::Scheduler::get_frozen());
-                r2->begin_transaction();
-                auto table2 = r2->read_group().get_table("class_object");
-                table2->create_object();
-                r2->commit_transaction();
-            });
-            advance_and_notify(*r);
-            REQUIRE(binding_context_start_notify_calls == 1);
-            REQUIRE(binding_context_end_notify_calls == 1);
-        }
-    }
-
-    SECTION("notify BindingContext before and after sending notifications") {
-        static int binding_context_start_notify_calls = 0;
-        static int binding_context_end_notify_calls = 0;
-        static int notification_calls = 0;
-
-        auto col = table->get_column_key("value");
-        Results results1(r, table->where().greater_equal(col, 0));
-        Results results2(r, table->where().less(col, 10));
-
-        auto token1 = results1.add_notification_callback([&](CollectionChangeSet, std::exception_ptr err) {
-            REQUIRE_FALSE(err);
-            ++notification_calls;
-        });
-
-        auto token2 = results2.add_notification_callback([&](CollectionChangeSet, std::exception_ptr err) {
-            REQUIRE_FALSE(err);
-            ++notification_calls;
-        });
-
-        struct Context : BindingContext {
-            void will_send_notifications() override
-            {
-                REQUIRE(notification_calls == 0);
-                REQUIRE(binding_context_end_notify_calls == 0);
-                ++binding_context_start_notify_calls;
-            }
-
-            void did_send_notifications() override
-            {
-                REQUIRE(notification_calls == 2);
-                REQUIRE(binding_context_start_notify_calls == 1);
-                ++binding_context_end_notify_calls;
-            }
-        };
-        r->m_binding_context.reset(new Context());
-
-        SECTION("local commit") {
-            binding_context_start_notify_calls = 0;
-            binding_context_end_notify_calls = 0;
-            notification_calls = 0;
-            coordinator->on_change();
-            r->begin_transaction();
-            table->create_object();
-            r->commit_transaction();
-            REQUIRE(binding_context_start_notify_calls == 1);
-            REQUIRE(binding_context_end_notify_calls == 1);
-        }
-
-        SECTION("remote commit") {
-            binding_context_start_notify_calls = 0;
-            binding_context_end_notify_calls = 0;
-            notification_calls = 0;
-            JoiningThread([&] {
-                auto r2 = coordinator->get_realm(util::Scheduler::get_frozen());
-                r2->begin_transaction();
-                auto table2 = r2->read_group().get_table("class_object");
-                table2->create_object();
-                r2->commit_transaction();
-            });
-            advance_and_notify(*r);
-            REQUIRE(binding_context_start_notify_calls == 1);
-            REQUIRE(binding_context_end_notify_calls == 1);
-        }
-    }
-
-    SECTION("did_send() is skipped if the Realm is closed first") {
-        Results results(r, table->where());
-        bool do_close = true;
-        auto token = results.add_notification_callback([&](CollectionChangeSet, std::exception_ptr) {
-            if (do_close)
-                r->close();
-        });
-
-        struct FailOnDidSend : BindingContext {
-            void did_send_notifications() override
-            {
-                FAIL("did_send_notifications() should not have been called");
-            }
-        };
-        struct CloseOnWillChange : FailOnDidSend {
-            Realm& realm;
-            CloseOnWillChange(Realm& realm) : realm(realm) {}
-
-            void will_send_notifications() override
-            {
-                realm.close();
-            }
-        };
-
-        SECTION("closed in notification callback for notify()") {
-            r->m_binding_context.reset(new FailOnDidSend);
-            coordinator->on_change();
-            r->notify();
-        }
-
-        SECTION("closed in notification callback for refresh()") {
-            do_close = false;
-            coordinator->on_change();
-            r->notify();
-            do_close = true;
-
-            JoiningThread([&] {
-                auto r = coordinator->get_realm(util::Scheduler::get_frozen());
-                r->begin_transaction();
-                r->read_group().get_table("class_object")->create_object();
-                r->commit_transaction();
-            });
-
-            r->m_binding_context.reset(new FailOnDidSend);
-            coordinator->on_change();
-            r->refresh();
-        }
-
-        SECTION("closed in will_send() for notify()") {
-            r->m_binding_context.reset(new CloseOnWillChange(*r));
-            coordinator->on_change();
-            r->notify();
-        }
-
-        SECTION("closed in will_send() for refresh()") {
-            do_close = false;
-            coordinator->on_change();
-            r->notify();
-            do_close = true;
-
-            JoiningThread([&] {
-                auto r = coordinator->get_realm(util::Scheduler::get_frozen());
-                r->begin_transaction();
-                r->read_group().get_table("class_object")->create_object();
-                r->commit_transaction();
-            });
-
-            r->m_binding_context.reset(new CloseOnWillChange(*r));
-            coordinator->on_change();
-            r->refresh();
-        }
-    }
-}
-
-TEST_CASE("Statistics on Realms") {
-    _impl::RealmCoordinator::assert_no_open_realms();
-
-    InMemoryTestFile config;
-    // config.cache = false;
-    config.automatic_change_notifications = false;
-
-    auto r = Realm::get_shared_realm(config);
-    r->update_schema({
-        {"object", {
-            {"value", PropertyType::Int}
-        }},
-    });
-
-    SECTION("compute_size") {
-        auto s = r->read_group().compute_aggregated_byte_size();
-        REQUIRE(s > 0);
-    }
-}
-
-#if REALM_PLATFORM_APPLE && NOTIFIER_BACKGROUND_ERRORS
-TEST_CASE("BindingContext is notified in case of notifier errors") {
-    _impl::RealmCoordinator::assert_no_open_realms();
-
-    class OpenFileLimiter {
-    public:
-        OpenFileLimiter()
-        {
-            // Set the max open files to zero so that opening new files will fail
-            getrlimit(RLIMIT_NOFILE, &m_old);
-            rlimit rl = m_old;
-            rl.rlim_cur = 0;
-            setrlimit(RLIMIT_NOFILE, &rl);
-        }
-
-        ~OpenFileLimiter()
-        {
-            setrlimit(RLIMIT_NOFILE, &m_old);
-        }
-
-    private:
-        rlimit m_old;
-    };
-
-    InMemoryTestFile config;
-    config.automatic_change_notifications = false;
-
-    auto r = Realm::get_shared_realm(config);
-    r->update_schema({
-      {"object", {
-        {"value", PropertyType::Int}
-      }},
-    });
-
-    auto coordinator = _impl::RealmCoordinator::get_coordinator(config.path);
-    auto table = r->read_group().get_table("class_object");
-    Results results(r, *r->read_group().get_table("class_object"));
-    static int binding_context_start_notify_calls = 0;
-    static int binding_context_end_notify_calls = 0;
-    static bool error_called = false;
-    struct Context : BindingContext {
-        void will_send_notifications() override
-        {
-            REQUIRE_FALSE(error_called);
-            ++binding_context_start_notify_calls;
-        }
-
-        void did_send_notifications() override
-        {
-            REQUIRE(error_called);
-            ++binding_context_end_notify_calls;
-        }
-    };
-    r->m_binding_context.reset(new Context());
-
-    SECTION("realm on background thread could not be opened") {
-        OpenFileLimiter limiter;
-
-        auto token = results.add_notification_callback([&](CollectionChangeSet, std::exception_ptr err) {
-            REQUIRE(err);
-            REQUIRE_FALSE(error_called);
-            error_called = true;
-        });
-        advance_and_notify(*r);
-        REQUIRE(error_called);
-        REQUIRE(binding_context_start_notify_calls == 1);
-        REQUIRE(binding_context_end_notify_calls == 1);
-    }
-}
-#endif
-
-TEST_CASE("RealmCoordinator: get_unbound_realm()") {
-    TestFile config;
-    config.schema = Schema{
-        {"object", {
-            {"value", PropertyType::Int}
-        }},
-    };
-
-    ThreadSafeReference ref;
-    std::thread([&] { ref = _impl::RealmCoordinator::get_coordinator(config)->get_unbound_realm(); }).join();
-
-    SECTION("checks thread after being resolved") {
-        auto realm = Realm::get_shared_realm(std::move(ref));
-        REQUIRE_NOTHROW(realm->verify_thread());
-        std::thread([&] {
-            REQUIRE_THROWS(realm->verify_thread());
-        }).join();
-    }
-
-    SECTION("delivers notifications to the thread it is resolved on") {
-        if (!util::EventLoop::has_implementation())
-            return;
-        auto realm = Realm::get_shared_realm(std::move(ref));
-        Results results(realm, ObjectStore::table_for_object_type(realm->read_group(), "object")->where());
-        bool called = false;
-        auto token = results.add_notification_callback([&](CollectionChangeSet, std::exception_ptr) {
-            called = true;
-        });
-        util::EventLoop::main().run_until([&] { return called; });
-    }
-
-    SECTION("resolves to a new Realm if caching is disabled") {
-        auto r1 = Realm::get_shared_realm(config);
-        auto r2 = Realm::get_shared_realm(std::move(ref));
-        REQUIRE(r1 != r2);
-
-        // New unbound with cache disabled
-        std::thread([&] { ref = _impl::RealmCoordinator::get_coordinator(config)->get_unbound_realm(); }).join();
-        auto r3 = Realm::get_shared_realm(std::move(ref));
-        REQUIRE(r1 != r3);
-        REQUIRE(r2 != r3);
-    }
-}

+ 0 - 3261
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/results.cpp

@@ -1,3261 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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 "catch2/catch.hpp"
-
-#include "util/event_loop.hpp"
-#include "util/index_helpers.hpp"
-#include "util/test_file.hpp"
-
-#include "impl/object_accessor_impl.hpp"
-#include "impl/realm_coordinator.hpp"
-#include "binding_context.hpp"
-#include "object_schema.hpp"
-#include "property.hpp"
-#include "results.hpp"
-#include "schema.hpp"
-#include "util/scheduler.hpp"
-
-#include <realm/db.hpp>
-#include <realm/group.hpp>
-#include <realm/query_engine.hpp>
-#include <realm/query_expression.hpp>
-
-#if REALM_ENABLE_SYNC
-#include "sync/sync_manager.hpp"
-#include "sync/sync_session.hpp"
-#endif
-
-namespace realm {
-class TestHelper {
-public:
-    static DBRef& get_shared_group(SharedRealm const& shared_realm)
-    {
-        return Realm::Internal::get_db(*shared_realm);
-    }
-};
-}
-
-using namespace realm;
-using namespace std::string_literals;
-
-namespace {
-    using AnyDict = std::map<std::string, util::Any>;
-    using AnyVec = std::vector<util::Any>;
-}
-
-struct TestContext : CppContext {
-    std::map<std::string, AnyDict> defaults;
-
-    using CppContext::CppContext;
-    TestContext(TestContext& parent, realm::Property const& prop)
-            : CppContext(parent, prop)
-            , defaults(parent.defaults)
-    { }
-
-    void will_change(Object const&, Property const&) {}
-    void did_change() {}
-    std::string print(util::Any) { return "not implemented"; }
-    bool allow_missing(util::Any) { return false; }
-};
-
-
-TEST_CASE("notifications: async delivery") {
-    _impl::RealmCoordinator::assert_no_open_realms();
-
-    InMemoryTestFile config;
-    config.automatic_change_notifications = false;
-
-    auto r = Realm::get_shared_realm(config);
-    r->update_schema({
-        {"object", {
-            {"value", PropertyType::Int}
-        }},
-    });
-
-    auto coordinator = _impl::RealmCoordinator::get_coordinator(config.path);
-    auto table = r->read_group().get_table("class_object");
-    auto col = table->get_column_key("value");
-
-    r->begin_transaction();
-    for (int i = 0; i < 10; ++i)
-        table->create_object().set_all(i * 2);
-    r->commit_transaction();
-
-    Results results(r, table->where().greater(col, 0).less(col, 10));
-
-    int notification_calls = 0;
-    auto token = results.add_notification_callback([&](CollectionChangeSet, std::exception_ptr err) {
-        REQUIRE_FALSE(err);
-        ++notification_calls;
-    });
-
-    auto make_local_change = [&] {
-        r->begin_transaction();
-        table->begin()->set(col, 4);
-        r->commit_transaction();
-    };
-
-    auto make_remote_change = [&] {
-        auto r2 = coordinator->get_realm(util::Scheduler::get_frozen());
-        r2->begin_transaction();
-        r2->read_group().get_table("class_object")->begin()->set(col, 5);
-        r2->commit_transaction();
-    };
-
-    SECTION("initial notification") {
-        SECTION("is delivered on notify()") {
-            REQUIRE(notification_calls == 0);
-            advance_and_notify(*r);
-            REQUIRE(notification_calls == 1);
-        }
-
-        SECTION("is delivered on refresh()") {
-            coordinator->on_change();
-            REQUIRE(notification_calls == 0);
-            r->refresh();
-            REQUIRE(notification_calls == 1);
-        }
-
-        SECTION("is delivered on begin_transaction()") {
-            coordinator->on_change();
-            REQUIRE(notification_calls == 0);
-            r->begin_transaction();
-            REQUIRE(notification_calls == 1);
-            r->cancel_transaction();
-        }
-
-        SECTION("is delivered on notify() even with autorefresh disabled") {
-            r->set_auto_refresh(false);
-            REQUIRE(notification_calls == 0);
-            advance_and_notify(*r);
-            REQUIRE(notification_calls == 1);
-        }
-
-        SECTION("refresh() blocks due to initial results not being ready") {
-            REQUIRE(notification_calls == 0);
-            JoiningThread thread([&] {
-                std::this_thread::sleep_for(std::chrono::microseconds(5000));
-                coordinator->on_change();
-            });
-            r->refresh();
-            REQUIRE(notification_calls == 1);
-        }
-
-        SECTION("begin_transaction() blocks due to initial results not being ready") {
-            REQUIRE(notification_calls == 0);
-            JoiningThread thread([&] {
-                std::this_thread::sleep_for(std::chrono::microseconds(5000));
-                coordinator->on_change();
-            });
-            r->begin_transaction();
-            REQUIRE(notification_calls == 1);
-            r->cancel_transaction();
-        }
-
-        SECTION("notify() does not block due to initial results not being ready") {
-            REQUIRE(notification_calls == 0);
-            r->notify();
-            REQUIRE(notification_calls == 0);
-        }
-
-        SECTION("is delivered after invalidate()") {
-            r->invalidate();
-
-            SECTION("notify()") {
-                coordinator->on_change();
-                REQUIRE_FALSE(r->is_in_read_transaction());
-                r->notify();
-                REQUIRE(notification_calls == 1);
-            }
-
-            SECTION("notify() without autorefresh") {
-                r->set_auto_refresh(false);
-                coordinator->on_change();
-                REQUIRE_FALSE(r->is_in_read_transaction());
-                r->notify();
-                REQUIRE(notification_calls == 1);
-            }
-
-            SECTION("refresh()") {
-                coordinator->on_change();
-                REQUIRE_FALSE(r->is_in_read_transaction());
-                r->refresh();
-                REQUIRE(notification_calls == 1);
-            }
-
-            SECTION("begin_transaction()") {
-                coordinator->on_change();
-                REQUIRE_FALSE(r->is_in_read_transaction());
-                r->begin_transaction();
-                REQUIRE(notification_calls == 1);
-                r->cancel_transaction();
-            }
-        }
-
-        SECTION("is delivered by notify() even if there are later versions") {
-            REQUIRE(notification_calls == 0);
-            coordinator->on_change();
-            make_remote_change();
-            r->notify();
-            REQUIRE(notification_calls == 1);
-        }
-    }
-
-    advance_and_notify(*r);
-
-    SECTION("notifications for local changes") {
-        make_local_change();
-        coordinator->on_change();
-        REQUIRE(notification_calls == 1);
-
-        SECTION("notify()") {
-            r->notify();
-            REQUIRE(notification_calls == 2);
-        }
-
-        SECTION("notify() without autorefresh") {
-            r->set_auto_refresh(false);
-            r->notify();
-            REQUIRE(notification_calls == 2);
-        }
-
-        SECTION("refresh()") {
-            r->refresh();
-            REQUIRE(notification_calls == 2);
-        }
-
-        SECTION("begin_transaction()") {
-            r->begin_transaction();
-            REQUIRE(notification_calls == 2);
-            r->cancel_transaction();
-        }
-    }
-
-    SECTION("notifications for remote changes") {
-        make_remote_change();
-        coordinator->on_change();
-        REQUIRE(notification_calls == 1);
-
-        SECTION("notify()") {
-            r->notify();
-            REQUIRE(notification_calls == 2);
-        }
-
-        SECTION("notify() without autorefresh") {
-            r->set_auto_refresh(false);
-            r->notify();
-            REQUIRE(notification_calls == 1);
-            r->refresh();
-            REQUIRE(notification_calls == 2);
-        }
-
-        SECTION("refresh()") {
-            r->refresh();
-            REQUIRE(notification_calls == 2);
-        }
-
-        SECTION("begin_transaction()") {
-            r->begin_transaction();
-            REQUIRE(notification_calls == 2);
-            r->cancel_transaction();
-        }
-    }
-
-    SECTION("notifications are not delivered when the token is destroyed before they are calculated") {
-        make_remote_change();
-        REQUIRE(notification_calls == 1);
-        token = {};
-        advance_and_notify(*r);
-        REQUIRE(notification_calls == 1);
-    }
-
-    SECTION("notifications are not delivered when the token is destroyed before they are delivered") {
-        make_remote_change();
-        REQUIRE(notification_calls == 1);
-        coordinator->on_change();
-        token = {};
-        r->notify();
-        REQUIRE(notification_calls == 1);
-    }
-
-    SECTION("notifications are delivered on the next cycle when a new callback is added from within a callback") {
-        NotificationToken token2, token3;
-        bool called = false;
-        token2 = results.add_notification_callback([&](CollectionChangeSet, std::exception_ptr) {
-            token2 = {};
-            token3 = results.add_notification_callback([&](CollectionChangeSet, std::exception_ptr) {
-                called = true;
-            });
-        });
-
-        advance_and_notify(*r);
-        REQUIRE_FALSE(called);
-        advance_and_notify(*r);
-        REQUIRE(called);
-    }
-
-    SECTION("notifications are delivered on the next cycle when a new callback is added from within a callback") {
-        auto results2 = results;
-        auto results3 = results;
-        NotificationToken token2, token3, token4;
-
-        bool called = false;
-        auto check = [&](Results& outer, Results& inner) {
-            token2 = outer.add_notification_callback([&](CollectionChangeSet, std::exception_ptr) {
-                token2 = {};
-                token3 = inner.add_notification_callback([&](CollectionChangeSet, std::exception_ptr) {
-                    called = true;
-                });
-            });
-
-            advance_and_notify(*r);
-            REQUIRE_FALSE(called);
-            advance_and_notify(*r);
-            REQUIRE(called);
-        };
-
-        SECTION("same Results") {
-            check(results, results);
-        }
-
-        SECTION("Results which has never had a notifier") {
-            check(results, results2);
-        }
-
-        SECTION("Results which used to have callbacks but no longer does") {
-            SECTION("notifier before active") {
-                token3 = results2.add_notification_callback([&](CollectionChangeSet, std::exception_ptr) {
-                    token3 = {};
-                });
-                check(results3, results2);
-            }
-            SECTION("notifier after active") {
-                token3 = results2.add_notification_callback([&](CollectionChangeSet, std::exception_ptr) {
-                    token3 = {};
-                });
-                check(results, results2);
-            }
-        }
-
-        SECTION("Results which already has callbacks") {
-            SECTION("notifier before active") {
-                token4 = results2.add_notification_callback([&](CollectionChangeSet, std::exception_ptr) { });
-                check(results3, results2);
-            }
-            SECTION("notifier after active") {
-                token4 = results2.add_notification_callback([&](CollectionChangeSet, std::exception_ptr) { });
-                check(results, results2);
-            }
-        }
-    }
-
-    SECTION("remote changes made before adding a callback from within a callback are not reported") {
-        NotificationToken token2, token3;
-        bool called = false;
-        token2 = results.add_notification_callback([&](CollectionChangeSet, std::exception_ptr) {
-            token2 = {};
-            make_remote_change();
-            coordinator->on_change();
-            token3 = results.add_notification_callback([&](CollectionChangeSet c, std::exception_ptr) {
-                called = true;
-                REQUIRE(c.empty());
-                REQUIRE(table->begin()->get<int64_t>(col) == 5);
-            });
-        });
-
-        advance_and_notify(*r);
-        REQUIRE_FALSE(called);
-        advance_and_notify(*r);
-        REQUIRE(called);
-    }
-
-    SECTION("notifications are not delivered when a callback is removed from within a callback") {
-        NotificationToken token2, token3;
-        token2 = results.add_notification_callback([&](CollectionChangeSet, std::exception_ptr) {
-            token3 = {};
-        });
-        token3 = results.add_notification_callback([&](CollectionChangeSet, std::exception_ptr) {
-            REQUIRE(false);
-        });
-
-        advance_and_notify(*r);
-    }
-
-    SECTION("removing the current callback does not stop later ones from being called") {
-        NotificationToken token2, token3;
-        bool called = false;
-        token2 = results.add_notification_callback([&](CollectionChangeSet, std::exception_ptr) {
-            token2 = {};
-        });
-        token3 = results.add_notification_callback([&](CollectionChangeSet, std::exception_ptr) {
-            called = true;
-        });
-
-        advance_and_notify(*r);
-
-        REQUIRE(called);
-    }
-
-    SECTION("the first call of a notification can include changes if it previously ran for a different callback") {
-        r->begin_transaction();
-        auto token2 = results.add_notification_callback([&](CollectionChangeSet c, std::exception_ptr) {
-            REQUIRE(!c.empty());
-        });
-
-        table->create_object().set(col, 5);
-        r->commit_transaction();
-        advance_and_notify(*r);
-    }
-
-    SECTION("handling of results not ready") {
-        make_remote_change();
-
-        SECTION("notify() does nothing") {
-            r->notify();
-            REQUIRE(notification_calls == 1);
-            coordinator->on_change();
-            r->notify();
-            REQUIRE(notification_calls == 2);
-        }
-
-        SECTION("refresh() blocks") {
-            REQUIRE(notification_calls == 1);
-            JoiningThread thread([&] {
-                std::this_thread::sleep_for(std::chrono::microseconds(5000));
-                coordinator->on_change();
-            });
-            r->refresh();
-            REQUIRE(notification_calls == 2);
-        }
-
-        SECTION("refresh() advances to the first version with notifiers ready that is at least a recent as the newest at the time it is called") {
-            JoiningThread thread([&] {
-                std::this_thread::sleep_for(std::chrono::microseconds(5000));
-                make_remote_change();
-                coordinator->on_change();
-                make_remote_change();
-            });
-            // advances to the version after the one it was waiting for, but still
-            // not the latest
-            r->refresh();
-            REQUIRE(notification_calls == 2);
-
-            thread.join();
-            REQUIRE(notification_calls == 2);
-
-            // now advances to the latest
-            coordinator->on_change();
-            r->refresh();
-            REQUIRE(notification_calls == 3);
-        }
-
-        SECTION("begin_transaction() blocks") {
-            REQUIRE(notification_calls == 1);
-            JoiningThread thread([&] {
-                std::this_thread::sleep_for(std::chrono::microseconds(5000));
-                coordinator->on_change();
-            });
-            r->begin_transaction();
-            REQUIRE(notification_calls == 2);
-            r->cancel_transaction();
-        }
-
-        SECTION("refresh() does not block for results without callbacks") {
-            token = {};
-            // this would deadlock if it waits for the notifier to be ready
-            r->refresh();
-        }
-
-        SECTION("begin_transaction() does not block for results without callbacks") {
-            token = {};
-            // this would deadlock if it waits for the notifier to be ready
-            r->begin_transaction();
-            r->cancel_transaction();
-        }
-
-        SECTION("begin_transaction() does not block for Results for different Realms") {
-            // this would deadlock if beginning the write on the secondary Realm
-            // waited for the primary Realm to be ready
-            make_remote_change();
-
-            // sanity check that the notifications never did run
-            r->notify();
-            REQUIRE(notification_calls == 1);
-        }
-    }
-
-    SECTION("handling of stale results") {
-        make_remote_change();
-        coordinator->on_change();
-        make_remote_change();
-
-        SECTION("notify() uses the older version") {
-            r->notify();
-            REQUIRE(notification_calls == 2);
-            coordinator->on_change();
-            r->notify();
-            REQUIRE(notification_calls == 3);
-            r->notify();
-            REQUIRE(notification_calls == 3);
-        }
-
-        SECTION("refresh() blocks") {
-            REQUIRE(notification_calls == 1);
-            JoiningThread thread([&] {
-                std::this_thread::sleep_for(std::chrono::microseconds(5000));
-                coordinator->on_change();
-            });
-            r->refresh();
-            REQUIRE(notification_calls == 2);
-        }
-
-        SECTION("begin_transaction() blocks") {
-            REQUIRE(notification_calls == 1);
-            JoiningThread thread([&] {
-                std::this_thread::sleep_for(std::chrono::microseconds(5000));
-                coordinator->on_change();
-            });
-            r->begin_transaction();
-            REQUIRE(notification_calls == 2);
-            r->cancel_transaction();
-        }
-    }
-
-    SECTION("updates are delivered after invalidate()") {
-        r->invalidate();
-        make_remote_change();
-
-        SECTION("notify()") {
-            coordinator->on_change();
-            REQUIRE_FALSE(r->is_in_read_transaction());
-            r->notify();
-            REQUIRE(notification_calls == 2);
-        }
-
-        SECTION("notify() without autorefresh") {
-            r->set_auto_refresh(false);
-            coordinator->on_change();
-            REQUIRE_FALSE(r->is_in_read_transaction());
-            r->notify();
-            REQUIRE(notification_calls == 1);
-            r->refresh();
-            REQUIRE(notification_calls == 2);
-        }
-
-        SECTION("refresh()") {
-            coordinator->on_change();
-            REQUIRE_FALSE(r->is_in_read_transaction());
-            r->refresh();
-            REQUIRE(notification_calls == 2);
-        }
-
-        SECTION("begin_transaction()") {
-            coordinator->on_change();
-            REQUIRE_FALSE(r->is_in_read_transaction());
-            r->begin_transaction();
-            REQUIRE(notification_calls == 2);
-            r->cancel_transaction();
-        }
-    }
-
-    SECTION("refresh() from within changes_available() do not interfere with notification delivery") {
-        struct Context : BindingContext {
-            Realm& realm;
-            Context(Realm& realm) : realm(realm) { }
-
-            void changes_available() override
-            {
-                REQUIRE(realm.refresh());
-            }
-        };
-
-        make_remote_change();
-        coordinator->on_change();
-
-        r->set_auto_refresh(false);
-        REQUIRE(notification_calls == 1);
-
-        r->notify();
-        REQUIRE(notification_calls == 1);
-
-        r->m_binding_context.reset(new Context(*r));
-        r->notify();
-        REQUIRE(notification_calls == 2);
-    }
-
-    SECTION("refresh() from within a notification is a no-op") {
-        token = results.add_notification_callback([&](CollectionChangeSet, std::exception_ptr err) {
-            REQUIRE_FALSE(err);
-            REQUIRE_FALSE(r->refresh()); // would deadlock if it actually tried to refresh
-        });
-        advance_and_notify(*r);
-        make_remote_change(); // 1
-        coordinator->on_change();
-        make_remote_change(); // 2
-        r->notify(); // advances to version from 1
-        coordinator->on_change();
-        REQUIRE(r->refresh()); // advances to version from 2
-        REQUIRE_FALSE(r->refresh()); // does not advance since it's now up-to-date
-    }
-
-    SECTION("begin_transaction() from within a notification does not send notifications immediately") {
-        bool first = true;
-        auto token2 = results.add_notification_callback([&](CollectionChangeSet, std::exception_ptr err) {
-            REQUIRE_FALSE(err);
-            if (first)
-                first = false;
-            else {
-                // would deadlock if it tried to send notifications as they aren't ready yet
-                r->begin_transaction();
-                r->cancel_transaction();
-            }
-        });
-        advance_and_notify(*r);
-
-        make_remote_change(); // 1
-        coordinator->on_change();
-        make_remote_change(); // 2
-        r->notify(); // advances to version from 1
-        REQUIRE(notification_calls == 2);
-        coordinator->on_change();
-        REQUIRE_FALSE(r->refresh()); // we made the commit locally, so no advancing here
-        REQUIRE(notification_calls == 3);
-    }
-
-    SECTION("begin_transaction() from within a notification does not break delivering additional notifications") {
-        size_t calls = 0;
-        token = results.add_notification_callback([&](CollectionChangeSet, std::exception_ptr err) {
-            REQUIRE_FALSE(err);
-            if (++calls == 1)
-                return;
-
-            // force the read version to advance by beginning a transaction
-            r->begin_transaction();
-            r->cancel_transaction();
-        });
-
-        auto results2 = results;
-        size_t calls2 = 0;
-        auto token2 = results2.add_notification_callback([&](CollectionChangeSet c, std::exception_ptr err) {
-            REQUIRE_FALSE(err);
-            if (++calls2 == 1)
-                return;
-            REQUIRE_INDICES(c.insertions, 0);
-        });
-        advance_and_notify(*r);
-        REQUIRE(calls == 1);
-        REQUIRE(calls2 == 1);
-
-        make_remote_change(); // 1
-        coordinator->on_change();
-        make_remote_change(); // 2
-        r->notify(); // advances to version from 1
-
-        REQUIRE(calls == 2);
-        REQUIRE(calls2 == 2);
-    }
-
-    SECTION("begin_transaction() from within did_change() does not break delivering collection notification") {
-        struct Context : BindingContext {
-            Realm& realm;
-            Context(Realm& realm) : realm(realm) { }
-
-            void did_change(std::vector<ObserverState> const&, std::vector<void*> const&, bool) override
-            {
-                if (!realm.is_in_transaction()) {
-                    // advances to version from 2 (and recursively calls this, hence the check above)
-                    realm.begin_transaction();
-                    realm.cancel_transaction();
-                }
-            }
-        };
-        r->m_binding_context.reset(new Context(*r));
-
-        make_remote_change(); // 1
-        coordinator->on_change();
-        make_remote_change(); // 2
-        r->notify(); // advances to version from 1
-    }
-
-    SECTION("is_in_transaction() is reported correctly within a notification from begin_transaction() and changes can be made") {
-        bool first = true;
-        token = results.add_notification_callback([&](CollectionChangeSet, std::exception_ptr err) {
-            REQUIRE_FALSE(err);
-            if (first) {
-                REQUIRE_FALSE(r->is_in_transaction());
-                first = false;
-            }
-            else {
-                REQUIRE(r->is_in_transaction());
-                table->begin()->set(col, 100);
-            }
-        });
-        advance_and_notify(*r);
-        make_remote_change();
-        coordinator->on_change();
-        r->begin_transaction();
-        REQUIRE(table->begin()->get<int64_t>(col) == 100);
-        r->cancel_transaction();
-        REQUIRE(table->begin()->get<int64_t>(col) != 100);
-    }
-
-    SECTION("invalidate() from within notification is a no-op") {
-        token = results.add_notification_callback([&](CollectionChangeSet, std::exception_ptr err) {
-            REQUIRE_FALSE(err);
-            r->invalidate();
-            REQUIRE(r->is_in_read_transaction());
-        });
-        advance_and_notify(*r);
-        REQUIRE(r->is_in_read_transaction());
-        make_remote_change();
-        coordinator->on_change();
-        r->begin_transaction();
-        REQUIRE(r->is_in_transaction());
-        r->cancel_transaction();
-    }
-
-    SECTION("cancel_transaction() from within notification ends the write transaction started by begin_transaction()") {
-        token = results.add_notification_callback([&](CollectionChangeSet, std::exception_ptr err) {
-            REQUIRE_FALSE(err);
-            if (r->is_in_transaction())
-                r->cancel_transaction();
-        });
-        advance_and_notify(*r);
-        make_remote_change();
-        coordinator->on_change();
-        r->begin_transaction();
-        REQUIRE_FALSE(r->is_in_transaction());
-    }
-}
-
-TEST_CASE("notifications: skip") {
-    _impl::RealmCoordinator::assert_no_open_realms();
-
-    InMemoryTestFile config;
-    config.automatic_change_notifications = false;
-
-    auto r = Realm::get_shared_realm(config);
-    r->update_schema({
-        {"object", {
-            {"value", PropertyType::Int}
-        }},
-    });
-
-    auto coordinator = _impl::RealmCoordinator::get_coordinator(config.path);
-    auto table = r->read_group().get_table("class_object");
-    auto col = table->get_column_key("value");
-
-    r->begin_transaction();
-    for (int i = 0; i < 10; ++i)
-        table->create_object().set(col, i * 2);
-    r->commit_transaction();
-
-    Results results(r, table->where());
-
-    auto add_callback = [](Results& results, int& calls, CollectionChangeSet& changes) {
-        return results.add_notification_callback([&](CollectionChangeSet c, std::exception_ptr err) {
-            REQUIRE_FALSE(err);
-            ++calls;
-            changes = std::move(c);
-        });
-    };
-
-    auto make_local_change = [&](auto& token) {
-        r->begin_transaction();
-        table->create_object();
-        token.suppress_next();
-        r->commit_transaction();
-    };
-
-    auto make_remote_change = [&] {
-        auto r2 = coordinator->get_realm(util::Scheduler::get_frozen());
-        r2->begin_transaction();
-        r2->read_group().get_table("class_object")->create_object();
-        r2->commit_transaction();
-    };
-
-    int calls1 = 0;
-    CollectionChangeSet changes1;
-    auto token1 = add_callback(results, calls1, changes1);
-
-    SECTION("no notification is sent when only callback is skipped") {
-        advance_and_notify(*r);
-        REQUIRE(calls1 == 1);
-
-        make_local_change(token1);
-        advance_and_notify(*r);
-
-        REQUIRE(calls1 == 1);
-        REQUIRE(changes1.empty());
-    }
-
-    SECTION("unskipped tokens for the same Results are still delivered") {
-        int calls2 = 0;
-        CollectionChangeSet changes2;
-        auto token2 = add_callback(results, calls2, changes2);
-
-        advance_and_notify(*r);
-        REQUIRE(calls1 == 1);
-        REQUIRE(calls2 == 1);
-
-        make_local_change(token1);
-        advance_and_notify(*r);
-
-        REQUIRE(calls1 == 1);
-        REQUIRE(changes1.empty());
-        REQUIRE(calls2 == 2);
-        REQUIRE_INDICES(changes2.insertions, 10);
-    }
-
-    SECTION("unskipped tokens for different Results are still delivered") {
-        Results results2(r, table->where());
-        int calls2 = 0;
-        CollectionChangeSet changes2;
-        auto token2 = add_callback(results2, calls2, changes2);
-
-        advance_and_notify(*r);
-        REQUIRE(calls1 == 1);
-        REQUIRE(calls2 == 1);
-
-        make_local_change(token1);
-        advance_and_notify(*r);
-
-        REQUIRE(calls1 == 1);
-        REQUIRE(changes1.empty());
-        REQUIRE(calls2 == 2);
-        REQUIRE_INDICES(changes2.insertions, 10);
-    }
-
-    SECTION("additional commits which occur before calculation are merged in") {
-        int calls2 = 0;
-        CollectionChangeSet changes2;
-        auto token2 = add_callback(results, calls2, changes2);
-
-        advance_and_notify(*r);
-        REQUIRE(calls1 == 1);
-        REQUIRE(calls2 == 1);
-
-        make_local_change(token1);
-        make_remote_change();
-        advance_and_notify(*r);
-
-        REQUIRE(calls1 == 2);
-        REQUIRE_INDICES(changes1.insertions, 11);
-        REQUIRE(calls2 == 2);
-        REQUIRE_INDICES(changes2.insertions, 10, 11);
-    }
-
-    SECTION("additional commits which occur before delivery are merged in") {
-        int calls2 = 0;
-        CollectionChangeSet changes2;
-        auto token2 = add_callback(results, calls2, changes2);
-
-        advance_and_notify(*r);
-        REQUIRE(calls1 == 1);
-        REQUIRE(calls2 == 1);
-
-        make_local_change(token1);
-        coordinator->on_change();
-        make_remote_change();
-        advance_and_notify(*r);
-
-        REQUIRE(calls1 == 2);
-        REQUIRE_INDICES(changes1.insertions, 11);
-        REQUIRE(calls2 == 2);
-        REQUIRE_INDICES(changes2.insertions, 10, 11);
-    }
-
-    SECTION("skipping must be done from within a write transaction") {
-        REQUIRE_THROWS(token1.suppress_next());
-    }
-
-    SECTION("skipping must be done from the Realm's thread") {
-        advance_and_notify(*r);
-        r->begin_transaction();
-        std::thread([&] {
-            REQUIRE_THROWS(token1.suppress_next());
-        }).join();
-        r->cancel_transaction();
-    }
-
-    SECTION("new notifiers do not interfere with skipping") {
-        advance_and_notify(*r);
-        REQUIRE(calls1 == 1);
-
-        CollectionChangeSet changes;
-
-        // new notifier at a version before the skipped one
-        auto r2 = coordinator->get_realm();
-        Results results2(r2, r2->read_group().get_table("class_object")->where());
-        int calls2 = 0;
-        auto token2 = add_callback(results2, calls2, changes);
-
-        make_local_change(token1);
-
-        // new notifier at the skipped version
-        auto r3 = coordinator->get_realm();
-        Results results3(r3, r3->read_group().get_table("class_object")->where());
-        int calls3 = 0;
-        auto token3 = add_callback(results3, calls3, changes);
-
-        make_remote_change();
-
-        // new notifier at version after the skipped one
-        auto r4 = coordinator->get_realm();
-        Results results4(r4, r4->read_group().get_table("class_object")->where());
-        int calls4 = 0;
-        auto token4 = add_callback(results4, calls4, changes);
-
-        coordinator->on_change();
-        r->notify();
-        r2->notify();
-        r3->notify();
-        r4->notify();
-
-        REQUIRE(calls1 == 2);
-        REQUIRE(calls2 == 1);
-        REQUIRE(calls3 == 1);
-        REQUIRE(calls4 == 1);
-    }
-
-    SECTION("skipping only effects the current transaction even if no notification would occur anyway") {
-        advance_and_notify(*r);
-        REQUIRE(calls1 == 1);
-
-        // would not produce a notification even if it wasn't skipped because no changes were made
-        r->begin_transaction();
-        token1.suppress_next();
-        r->commit_transaction();
-        advance_and_notify(*r);
-        REQUIRE(calls1 == 1);
-
-        // should now produce a notification
-        r->begin_transaction();
-        table->create_object();
-        r->commit_transaction();
-        advance_and_notify(*r);
-        REQUIRE(calls1 == 2);
-    }
-
-    SECTION("removing skipped notifier before it gets the chance to run") {
-        advance_and_notify(*r);
-        REQUIRE(calls1 == 1);
-
-        // Set the skip version
-        make_local_change(token1);
-        // Advance the file to a version after the skip version
-        make_remote_change();
-        REQUIRE(calls1 == 1);
-
-        // Remove the skipped notifier and add an entirely new notifier, so that
-        // notifications need to run but the skip logic shouldn't be used
-        token1 = {};
-        results = {};
-        Results results2(r, table->where());
-        auto token2 = add_callback(results2, calls1, changes1);
-
-        advance_and_notify(*r);
-        REQUIRE(calls1 == 2);
-    }
-}
-
-TEST_CASE("notifications: TableView delivery") {
-    _impl::RealmCoordinator::assert_no_open_realms();
-
-    InMemoryTestFile config;
-    config.automatic_change_notifications = false;
-    config.max_number_of_active_versions = 5;
-
-    auto r = Realm::get_shared_realm(config);
-    r->update_schema({
-        {"object", {
-            {"value", PropertyType::Int}
-        }},
-    });
-
-    auto coordinator = _impl::RealmCoordinator::get_coordinator(config.path);
-    auto table = r->read_group().get_table("class_object");
-    auto col = table->get_column_key("value");
-
-    r->begin_transaction();
-    for (int i = 0; i < 10; ++i)
-        table->create_object().set(col, i * 2);
-    r->commit_transaction();
-
-    Results results(r, table->where());
-    results.set_update_policy(Results::UpdatePolicy::AsyncOnly);
-
-    SECTION("Initial run never happens with no callbacks") {
-        advance_and_notify(*r);
-        REQUIRE(results.get_mode() == Results::Mode::Query);
-    }
-
-    results.evaluate_query_if_needed();
-    // Create and immediately remove a callback so that the notifier gets created
-    // even though we have automatic change notifications disabled
-    static_cast<void>(results.add_notification_callback([&](CollectionChangeSet, std::exception_ptr) {}));
-    REQUIRE(results.get_mode() == Results::Mode::TableView);
-    REQUIRE(results.size() == 0);
-
-    auto make_local_change = [&] {
-        r->begin_transaction();
-        table->create_object();
-        r->commit_transaction();
-    };
-
-    auto make_remote_change = [&] {
-        auto r2 = coordinator->get_realm(util::Scheduler::get_frozen());
-        r2->begin_transaction();
-        r2->read_group().get_table("class_object")->create_object();
-        r2->commit_transaction();
-    };
-
-    SECTION("does not update after local change with no on_change") {
-        make_local_change();
-        REQUIRE(results.size() == 0);
-    }
-
-    SECTION("TV is delivered when no commit is made") {
-        advance_and_notify(*r);
-        REQUIRE(results.get_mode() == Results::Mode::TableView);
-        REQUIRE(results.size() == 10);
-    }
-
-    SECTION("TV is not delivered when notifier version > local version") {
-        make_remote_change();
-        r->refresh();
-        REQUIRE(results.size() == 0);
-    }
-
-    SECTION("TV is delivered when notifier version = local version") {
-        make_remote_change();
-        advance_and_notify(*r);
-        REQUIRE(results.size() == 11);
-    }
-
-    SECTION("TV is delivered when previous TV wasn't used due to never refreshing") {
-        // These two generate TVs that never get used
-        make_remote_change();
-        on_change_but_no_notify(*r);
-        make_remote_change();
-        on_change_but_no_notify(*r);
-
-        // But we generate a third one anyway because the main thread never even
-        // got a chance to use them, rather than it not wanting them
-        make_remote_change();
-        advance_and_notify(*r);
-
-        REQUIRE(results.size() == 13);
-    }
-
-    SECTION("TV is not delivered when main thread refreshed but previous TV was not used") {
-        // First run generates a TV that's unused
-        make_remote_change();
-        advance_and_notify(*r);
-
-        // When the second run is delivered we discover first run wasn't used
-        make_remote_change();
-        advance_and_notify(*r);
-
-        // And then third one doesn't run at all
-        make_remote_change();
-        advance_and_notify(*r);
-
-        // And we can't use the old TV because it's out of date
-        REQUIRE(results.size() == 0);
-
-        // We don't start implicitly updating again even after it is used
-        make_remote_change();
-        advance_and_notify(*r);
-        REQUIRE(results.size() == 0);
-    }
-
-    SECTION("TV can be delivered in a write transaction") {
-        make_remote_change();
-        advance_and_notify(*r);
-        r->begin_transaction();
-        REQUIRE(results.size() == 11);
-        r->cancel_transaction();
-    }
-
-    SECTION("unused background TVs do not pin old versions forever") {
-        // This will exceed the maximum active version count (5) if any
-        // transactions are being pinned, resulting in make_remote_change() throwing
-        for (int i = 0; i < 10; ++i) {
-            REQUIRE_NOTHROW(make_remote_change());
-            advance_and_notify(*r);
-        }
-    }
-}
-
-
-#if REALM_PLATFORM_APPLE && NOTIFIER_BACKGROUND_ERRORS
-TEST_CASE("notifications: async error handling") {
-    _impl::RealmCoordinator::assert_no_open_realms();
-
-    InMemoryTestFile config;
-    config.automatic_change_notifications = false;
-
-    auto r = Realm::get_shared_realm(config);
-    r->update_schema({
-        {"object", {
-            {"value", PropertyType::Int},
-        }},
-    });
-
-    auto coordinator = _impl::RealmCoordinator::get_coordinator(config.path);
-    Results results(r, *r->read_group().get_table("class_object"));
-
-    auto r2 = Realm::get_shared_realm(config);
-
-    class OpenFileLimiter {
-    public:
-        OpenFileLimiter()
-        {
-            // Set the max open files to zero so that opening new files will fail
-            getrlimit(RLIMIT_NOFILE, &m_old);
-            rlimit rl = m_old;
-            rl.rlim_cur = 0;
-            setrlimit(RLIMIT_NOFILE, &rl);
-        }
-
-        ~OpenFileLimiter()
-        {
-            setrlimit(RLIMIT_NOFILE, &m_old);
-        }
-
-    private:
-        rlimit m_old;
-    };
-
-    SECTION("error when opening the advancer SG") {
-        OpenFileLimiter limiter;
-
-        bool called = false;
-        auto token = results.add_notification_callback([&](CollectionChangeSet, std::exception_ptr err) {
-            REQUIRE(err);
-            REQUIRE_FALSE(called);
-            called = true;
-        });
-        REQUIRE(!called);
-
-        SECTION("error is delivered on notify() without changes") {
-            coordinator->on_change();
-            REQUIRE(!called);
-            r->notify();
-            REQUIRE(called);
-        }
-
-        SECTION("error is delivered on notify() with changes") {
-            r2->begin_transaction(); r2->commit_transaction();
-            REQUIRE(!called);
-            coordinator->on_change();
-            REQUIRE(!called);
-            r->notify();
-            REQUIRE(called);
-        }
-
-        SECTION("error is delivered on refresh() without changes") {
-            coordinator->on_change();
-            REQUIRE(!called);
-            r->refresh();
-            REQUIRE(called);
-        }
-
-        SECTION("error is delivered on refresh() with changes") {
-            r2->begin_transaction(); r2->commit_transaction();
-            REQUIRE(!called);
-            coordinator->on_change();
-            REQUIRE(!called);
-            r->refresh();
-            REQUIRE(called);
-        }
-
-        SECTION("error is delivered on begin_transaction() without changes") {
-            coordinator->on_change();
-            REQUIRE(!called);
-            r->begin_transaction();
-            REQUIRE(called);
-            r->cancel_transaction();
-        }
-
-        SECTION("error is delivered on begin_transaction() with changes") {
-            r2->begin_transaction(); r2->commit_transaction();
-            REQUIRE(!called);
-            coordinator->on_change();
-            REQUIRE(!called);
-            r->begin_transaction();
-            REQUIRE(called);
-            r->cancel_transaction();
-        }
-
-        SECTION("adding another callback sends the error to only the newly added one") {
-            advance_and_notify(*r);
-            REQUIRE(called);
-
-            bool called2 = false;
-            auto token2 = results.add_notification_callback([&](CollectionChangeSet, std::exception_ptr err) {
-                REQUIRE(err);
-                REQUIRE_FALSE(called2);
-                called2 = true;
-            });
-
-            advance_and_notify(*r);
-            REQUIRE(called2);
-        }
-
-        SECTION("destroying a token from before the error does not remove newly added callbacks") {
-            advance_and_notify(*r);
-
-            bool called = false;
-            auto token2 = results.add_notification_callback([&](CollectionChangeSet, std::exception_ptr err) {
-                REQUIRE(err);
-                REQUIRE_FALSE(called);
-                called = true;
-            });
-            token = {};
-
-            advance_and_notify(*r);
-            REQUIRE(called);
-        }
-
-        SECTION("adding another callback from within an error callback defers delivery") {
-            NotificationToken token2;
-            token = results.add_notification_callback([&](CollectionChangeSet, std::exception_ptr) {
-                token2 = results.add_notification_callback([&](CollectionChangeSet, std::exception_ptr err) {
-                    REQUIRE(err);
-                    REQUIRE_FALSE(called);
-                    called = true;
-                });
-            });
-            advance_and_notify(*r);
-            REQUIRE(!called);
-            advance_and_notify(*r);
-            REQUIRE(called);
-        }
-
-        SECTION("adding a callback to a different collection from within the error callback defers delivery") {
-            auto results2 = results;
-            NotificationToken token2;
-            token = results.add_notification_callback([&](CollectionChangeSet, std::exception_ptr) {
-                token2 = results2.add_notification_callback([&](CollectionChangeSet, std::exception_ptr err) {
-                    REQUIRE(err);
-                    REQUIRE_FALSE(called);
-                    called = true;
-                });
-            });
-            advance_and_notify(*r);
-            REQUIRE(!called);
-            advance_and_notify(*r);
-            REQUIRE(called);
-        }
-    }
-
-    SECTION("error when opening the executor SG") {
-        SECTION("error is delivered asynchronously") {
-            bool called = false;
-            auto token = results.add_notification_callback([&](CollectionChangeSet, std::exception_ptr err) {
-                REQUIRE(err);
-                called = true;
-            });
-            OpenFileLimiter limiter;
-
-            REQUIRE(!called);
-            coordinator->on_change();
-            REQUIRE(!called);
-            r->notify();
-            REQUIRE(called);
-        }
-
-        SECTION("adding another callback only sends the error to the new one") {
-            bool called = false;
-            auto token = results.add_notification_callback([&](CollectionChangeSet, std::exception_ptr err) {
-                REQUIRE(err);
-                REQUIRE_FALSE(called);
-                called = true;
-            });
-            OpenFileLimiter limiter;
-
-            advance_and_notify(*r);
-
-            bool called2 = false;
-            auto token2 = results.add_notification_callback([&](CollectionChangeSet, std::exception_ptr err) {
-                REQUIRE(err);
-                REQUIRE_FALSE(called2);
-                called2 = true;
-            });
-
-            advance_and_notify(*r);
-
-            REQUIRE(called2);
-        }
-    }
-}
-#endif
-
-#if REALM_ENABLE_SYNC
-TEST_CASE("notifications: sync") {
-    _impl::RealmCoordinator::assert_no_open_realms();
-
-    SyncServer server(false);
-    SyncTestFile config(server);
-    config.schema = Schema{
-        {"object", {
-            {"value", PropertyType::Int},
-        }},
-    };
-
-    SECTION("sync progress commits do not distrupt notifications") {
-        auto r = Realm::get_shared_realm(config);
-        auto wait_realm = Realm::get_shared_realm(config);
-
-        Results results(r, r->read_group().get_table("class_object"));
-        Results wait_results(wait_realm, wait_realm->read_group().get_table("class_object"));
-        auto token1 = results.add_notification_callback([&](CollectionChangeSet, std::exception_ptr) { });
-        auto token2 = wait_results.add_notification_callback([&](CollectionChangeSet, std::exception_ptr) { });
-
-        // Add an object to the Realm so that notifications are needed
-        {
-            auto write_realm = Realm::get_shared_realm(config);
-            write_realm->begin_transaction();
-            write_realm->read_group().get_table("class_object")->create_object();
-            write_realm->commit_transaction();
-        }
-
-        // Wait for the notifications to become ready for the new version
-        wait_realm->refresh();
-
-        // Start the server and wait for the Realm to be uploaded so that sync
-        // makes some writes to the Realm and bumps the version
-        server.start();
-        wait_for_upload(*r);
-
-        // Make sure that the notifications still get delivered rather than
-        // waiting forever due to that we don't get a commit notification from
-        // the commits sync makes to store the upload progress
-        r->refresh();
-    }
-}
-#endif
-
-TEST_CASE("notifications: results") {
-    _impl::RealmCoordinator::assert_no_open_realms();
-
-    InMemoryTestFile config;
-    config.automatic_change_notifications = false;
-
-    auto r = Realm::get_shared_realm(config);
-    r->update_schema({
-        {"object", {
-            {"value", PropertyType::Int},
-            {"link", PropertyType::Object|PropertyType::Nullable, "linked to object"}
-        }},
-        {"other object", {
-            {"value", PropertyType::Int}
-        }},
-        {"linking object", {
-            {"link", PropertyType::Object|PropertyType::Nullable, "object"}
-        }},
-        {"linked to object", {
-            {"value", PropertyType::Int}
-        }}
-    });
-
-    auto coordinator = _impl::RealmCoordinator::get_coordinator(config.path);
-    auto table = r->read_group().get_table("class_object");
-    auto col_value = table->get_column_key("value");
-    auto col_link = table->get_column_key("link");
-
-    r->begin_transaction();
-    std::vector<ObjKey> target_keys;
-    r->read_group().get_table("class_linked to object")->create_objects(10, target_keys);
-
-    ObjKeys object_keys({3, 4, 7, 9, 10, 21, 24, 34, 42, 50});
-    for (int i = 0; i < 10; ++i) {
-        table->create_object(object_keys[i]).set_all(i * 2, target_keys[i]);
-    }
-    r->commit_transaction();
-
-    auto r2 = coordinator->get_realm();
-    auto r2_table = r2->read_group().get_table("class_object");
-
-    Results results(r, table->where().greater(col_value, 0).less(col_value, 10));
-
-    SECTION("unsorted notifications") {
-        int notification_calls = 0;
-        CollectionChangeSet change;
-        auto token = results.add_notification_callback([&](CollectionChangeSet c, std::exception_ptr err) {
-            REQUIRE_FALSE(err);
-            change = c;
-            ++notification_calls;
-        });
-
-        advance_and_notify(*r);
-
-        auto write = [&](auto&& f) {
-            r->begin_transaction();
-            f();
-            r->commit_transaction();
-            advance_and_notify(*r);
-        };
-
-        SECTION("modifications to unrelated tables do not send notifications") {
-            write([&] {
-                r->read_group().get_table("class_other object")->create_object();
-            });
-            REQUIRE(notification_calls == 1);
-        }
-
-        SECTION("irrelevant modifications to linked tables do not send notifications") {
-            write([&] {
-                r->read_group().get_table("class_linked to object")->create_object();
-            });
-            REQUIRE(notification_calls == 1);
-        }
-
-        SECTION("irrelevant modifications to linking tables do not send notifications") {
-            write([&] {
-                r->read_group().get_table("class_linking object")->create_object();
-            });
-            REQUIRE(notification_calls == 1);
-        }
-
-        SECTION("modifications that leave a non-matching row non-matching do not send notifications") {
-            write([&] {
-                table->get_object(object_keys[6]).set(col_value, 13);
-            });
-            REQUIRE(notification_calls == 1);
-        }
-
-        SECTION("deleting non-matching rows does not send a notification") {
-            write([&] {
-                table->remove_object(object_keys[0]);
-                table->remove_object(object_keys[6]);
-            });
-            REQUIRE(notification_calls == 1);
-        }
-
-        SECTION("modifying a matching row and leaving it matching marks that row as modified") {
-            write([&] {
-                table->get_object(object_keys[1]).set(col_value, 3);
-            });
-            REQUIRE(notification_calls == 2);
-            REQUIRE_INDICES(change.modifications, 0);
-            REQUIRE_INDICES(change.modifications_new, 0);
-        }
-
-        SECTION("modifying a matching row to no longer match marks that row as deleted") {
-            write([&] {
-                table->get_object(object_keys[2]).set(col_value, 0);
-            });
-            REQUIRE(notification_calls == 2);
-            REQUIRE_INDICES(change.deletions, 1);
-        }
-
-        SECTION("modifying a non-matching row to match marks that row as inserted, but not modified") {
-            write([&] {
-                table->get_object(object_keys[7]).set(col_value, 3);
-            });
-            REQUIRE(notification_calls == 2);
-            REQUIRE_INDICES(change.insertions, 4);
-            REQUIRE(change.modifications.empty());
-            REQUIRE(change.modifications_new.empty());
-        }
-
-        SECTION("deleting a matching row marks that row as deleted") {
-            write([&] {
-                table->remove_object(object_keys[3]);
-            });
-            REQUIRE(notification_calls == 2);
-            REQUIRE_INDICES(change.deletions, 2);
-        }
-
-        SECTION("modifications from multiple transactions are collapsed") {
-            r2->begin_transaction();
-            r2_table->get_object(object_keys[0]).set(col_value, 6);
-            r2->commit_transaction();
-
-            coordinator->on_change();
-
-            r2->begin_transaction();
-            r2_table->get_object(object_keys[1]).set(col_value,03);
-            r2->commit_transaction();
-
-            REQUIRE(notification_calls == 1);
-            coordinator->on_change();
-            r->notify();
-            REQUIRE(notification_calls == 2);
-        }
-
-        SECTION("inserting a row then modifying it in a second transaction does not report it as modified") {
-            r2->begin_transaction();
-            ObjKey k = r2_table->create_object(ObjKey(53)).set(col_value, 6).get_key();
-            r2->commit_transaction();
-
-            coordinator->on_change();
-
-            r2->begin_transaction();
-            r2_table->get_object(k).set(col_value, 7);
-            r2->commit_transaction();
-
-            advance_and_notify(*r);
-
-            REQUIRE(notification_calls == 2);
-            REQUIRE_INDICES(change.insertions, 4);
-            REQUIRE(change.modifications.empty());
-            REQUIRE(change.modifications_new.empty());
-        }
-
-        SECTION("modification indices are pre-insert/delete") {
-            r->begin_transaction();
-            table->get_object(object_keys[2]).set(col_value, 0);
-            table->get_object(object_keys[3]).set(col_value, 6);
-            r->commit_transaction();
-            advance_and_notify(*r);
-
-            REQUIRE(notification_calls == 2);
-            REQUIRE_INDICES(change.deletions, 1);
-            REQUIRE_INDICES(change.modifications, 2);
-            REQUIRE_INDICES(change.modifications_new, 1);
-        }
-
-        SECTION("notifications are not delivered when collapsing transactions results in no net change") {
-            r2->begin_transaction();
-            ObjKey k = r2_table->create_object().set(col_value, 5).get_key();
-            r2->commit_transaction();
-
-            coordinator->on_change();
-
-            r2->begin_transaction();
-            r2_table->remove_object(k);
-            r2->commit_transaction();
-
-            REQUIRE(notification_calls == 1);
-            coordinator->on_change();
-            r->notify();
-            REQUIRE(notification_calls == 1);
-        }
-
-        SECTION("inserting a non-matching row at the beginning does not produce a notification") {
-            write([&] {
-                table->create_object(ObjKey(1));
-            });
-            REQUIRE(notification_calls == 1);
-        }
-
-        SECTION("inserting a matching row at the beginning marks just it as inserted") {
-            write([&] {
-                table->create_object(ObjKey(0)).set(col_value, 5);
-            });
-            REQUIRE(notification_calls == 2);
-            REQUIRE_INDICES(change.insertions, 0);
-        }
-
-        SECTION("modification to related table not included in query") {
-            write([&] {
-                auto table = r->read_group().get_table("class_linked to object");
-                auto col = table->get_column_key("value");
-                auto obj = table->get_object(target_keys[1]);
-                obj.set(col, 42);  // Will affect first entry in results
-            });
-            REQUIRE(notification_calls == 2);
-            REQUIRE_INDICES(change.modifications, 0);
-        }
-    }
-
-    SECTION("before/after change callback") {
-        struct Callback {
-            size_t before_calls = 0;
-            size_t after_calls = 0;
-            CollectionChangeSet before_change;
-            CollectionChangeSet after_change;
-            std::function<void(void)> on_before = []{};
-            std::function<void(void)> on_after = []{};
-
-            void before(CollectionChangeSet c) {
-                before_change = c;
-                ++before_calls;
-                on_before();
-            }
-            void after(CollectionChangeSet c) {
-                after_change = c;
-                ++after_calls;
-                on_after();
-            }
-            void error(std::exception_ptr) {
-                FAIL("error() should not be called");
-            }
-        } callback;
-        auto token = results.add_notification_callback(&callback);
-        advance_and_notify(*r);
-
-        SECTION("only after() is called for initial results") {
-            REQUIRE(callback.before_calls == 0);
-            REQUIRE(callback.after_calls == 1);
-            REQUIRE(callback.after_change.empty());
-        }
-
-        auto write = [&](auto&& func) {
-            r2->begin_transaction();
-            func(*r2_table);
-            r2->commit_transaction();
-            advance_and_notify(*r);
-        };
-
-        SECTION("both are called after a write") {
-            write([&](auto&& t) {
-                t.create_object(ObjKey(53)).set(col_value, 5);
-            });
-            REQUIRE(callback.before_calls == 1);
-            REQUIRE(callback.after_calls == 2);
-            REQUIRE_INDICES(callback.before_change.insertions, 4);
-            REQUIRE_INDICES(callback.after_change.insertions, 4);
-        }
-
-        SECTION("deleted objects are usable in before()") {
-            callback.on_before = [&] {
-                REQUIRE(results.size() == 4);
-                REQUIRE_INDICES(callback.before_change.deletions, 0);
-                REQUIRE(results.get(0).is_valid());
-                REQUIRE(results.get(0).get<int64_t>(col_value) == 2);
-            };
-            write([&](auto&& t) {
-                t.remove_object(results.get(0).get_key());
-            });
-            REQUIRE(callback.before_calls == 1);
-            REQUIRE(callback.after_calls == 2);
-        }
-
-        SECTION("inserted objects are usable in after()") {
-            callback.on_after = [&] {
-                REQUIRE(results.size() == 5);
-                REQUIRE_INDICES(callback.after_change.insertions, 4);
-                REQUIRE(results.last()->get<int64_t>(col_value) == 5);
-            };
-            write([&](auto&& t) {
-                t.create_object(ObjKey(53)).set(col_value, 5);
-            });
-            REQUIRE(callback.before_calls == 1);
-            REQUIRE(callback.after_calls == 2);
-        }
-    }
-
-    SECTION("sorted notifications") {
-        // Sort in descending order
-        results = results.sort({{{col_value}}, {false}});
-
-        int notification_calls = 0;
-        CollectionChangeSet change;
-        auto token = results.add_notification_callback([&](CollectionChangeSet c, std::exception_ptr err) {
-            REQUIRE_FALSE(err);
-            change = c;
-            ++notification_calls;
-        });
-
-        advance_and_notify(*r);
-
-        auto write = [&](auto&& f) {
-            r->begin_transaction();
-            f();
-            r->commit_transaction();
-            advance_and_notify(*r);
-        };
-
-        SECTION("modifications that leave a non-matching row non-matching do not send notifications") {
-            write([&] {
-                table->get_object(object_keys[6]).set(col_value, 13);
-            });
-            REQUIRE(notification_calls == 1);
-        }
-
-        SECTION("deleting non-matching rows does not send a notification") {
-            write([&] {
-                table->remove_object(object_keys[0]);
-                table->remove_object(object_keys[6]);
-            });
-            REQUIRE(notification_calls == 1);
-        }
-
-        SECTION("modifying a matching row and leaving it matching marks that row as modified") {
-            write([&] {
-                table->get_object(object_keys[1]).set(col_value, 3);
-            });
-            REQUIRE(notification_calls == 2);
-            REQUIRE_INDICES(change.modifications, 3);
-            REQUIRE_INDICES(change.modifications_new, 3);
-        }
-
-        SECTION("modifying a matching row to no longer match marks that row as deleted") {
-            write([&] {
-                table->get_object(object_keys[2]).set(col_value, 0);
-            });
-            REQUIRE(notification_calls == 2);
-            REQUIRE_INDICES(change.deletions, 2);
-        }
-
-        SECTION("modifying a non-matching row to match marks that row as inserted") {
-            write([&] {
-                table->get_object(object_keys[7]).set(col_value, 3);
-            });
-            REQUIRE(notification_calls == 2);
-            REQUIRE_INDICES(change.insertions, 3);
-        }
-
-        SECTION("deleting a matching row marks that row as deleted") {
-            write([&] {
-                table->remove_object(object_keys[3]);
-            });
-            REQUIRE(notification_calls == 2);
-            REQUIRE_INDICES(change.deletions, 1);
-        }
-
-        SECTION("clearing the table marks all rows as deleted") {
-            size_t num_expected_deletes = results.size();
-            write([&] {
-                table->clear();
-            });
-            REQUIRE(notification_calls == 2);
-            REQUIRE(change.deletions.count() == num_expected_deletes);
-        }
-
-        SECTION("clear insert clear marks the correct rows as deleted") {
-            size_t num_expected_deletes = results.size();
-            write([&] {
-                table->clear();
-            });
-            REQUIRE(notification_calls == 2);
-            REQUIRE(change.deletions.count() == num_expected_deletes);
-            write([&] {
-                table->create_object().set(col_value, 3);
-                table->create_object().set(col_value, 4);
-                table->create_object().set(col_value, 5);
-            });
-            REQUIRE(notification_calls == 3);
-            REQUIRE_INDICES(change.insertions, 0, 1, 2);
-            REQUIRE(change.deletions.empty());
-            write([&] {
-                table->clear();
-            });
-            REQUIRE(notification_calls == 4);
-            REQUIRE_INDICES(change.deletions, 0, 1, 2);
-            REQUIRE(change.insertions.empty());
-            REQUIRE(change.modifications.empty());
-        }
-
-        SECTION("delete insert clear marks the correct rows as deleted") {
-            size_t num_expected_deletes = results.size();
-            write([&] {
-                results.clear(); // delete all 4 matches
-            });
-            REQUIRE(notification_calls == 2);
-            REQUIRE(change.deletions.count() == num_expected_deletes);
-            write([&] {
-                table->create_object(ObjKey(57)).set(col_value, 3);
-                table->create_object(ObjKey(58)).set(col_value, 4);
-                table->create_object(ObjKey(59)).set(col_value, 5);
-            });
-            REQUIRE(notification_calls == 3);
-            REQUIRE_INDICES(change.insertions, 0, 1, 2);
-            REQUIRE(change.deletions.empty());
-            write([&] {
-                table->clear();
-            });
-            REQUIRE(notification_calls == 4);
-            REQUIRE_INDICES(change.deletions, 0, 1, 2);
-            REQUIRE(change.insertions.empty());
-            REQUIRE(change.modifications.empty());
-        }
-
-        SECTION("modifying a matching row to change its position sends insert+delete") {
-            write([&] {
-                table->get_object(object_keys[2]).set(col_value, 9);
-            });
-            REQUIRE(notification_calls == 2);
-            REQUIRE_INDICES(change.deletions, 2);
-            REQUIRE_INDICES(change.insertions, 0);
-        }
-
-        SECTION("modifications from multiple transactions are collapsed") {
-            r2->begin_transaction();
-            r2_table->get_object(object_keys[0]).set(col_value, 5);
-            r2->commit_transaction();
-
-            r2->begin_transaction();
-            r2_table->get_object(object_keys[1]).set(col_value, 0);
-            r2->commit_transaction();
-
-            REQUIRE(notification_calls == 1);
-            advance_and_notify(*r);
-            REQUIRE(notification_calls == 2);
-        }
-
-        SECTION("moving a matching row by deleting all other rows") {
-            r->begin_transaction();
-            table->clear();
-            ObjKey k0 = table->create_object().set(col_value, 15).get_key();
-            table->create_object().set(col_value, 5);
-            r->commit_transaction();
-            advance_and_notify(*r);
-
-            write([&] {
-                table->remove_object(k0);
-                table->create_object().set(col_value, 3);
-            });
-
-            REQUIRE(notification_calls == 3);
-            REQUIRE(change.deletions.empty());
-            REQUIRE_INDICES(change.insertions, 1);
-        }
-    }
-
-    SECTION("distinct notifications") {
-        results = results.distinct(DistinctDescriptor({{col_value}}));
-
-        int notification_calls = 0;
-        CollectionChangeSet change;
-        auto token = results.add_notification_callback([&](CollectionChangeSet c, std::exception_ptr err) {
-            REQUIRE_FALSE(err);
-            change = c;
-            ++notification_calls;
-        });
-
-        advance_and_notify(*r);
-
-        auto write = [&](auto&& f) {
-            r->begin_transaction();
-            f();
-            r->commit_transaction();
-            advance_and_notify(*r);
-        };
-
-        SECTION("modifications that leave a non-matching row non-matching do not send notifications") {
-            write([&] {
-                table->get_object(object_keys[6]).set(col_value, 13);
-            });
-            REQUIRE(notification_calls == 1);
-        }
-
-        SECTION("deleting non-matching rows does not send a notification") {
-            write([&] {
-                table->remove_object(object_keys[0]);
-                table->remove_object(object_keys[6]);
-            });
-            REQUIRE(notification_calls == 1);
-        }
-
-        SECTION("modifying a matching row and leaving it matching marks that row as modified") {
-            write([&] {
-                table->get_object(object_keys[1]).set(col_value, 3);
-            });
-            REQUIRE(notification_calls == 2);
-            REQUIRE_INDICES(change.modifications, 0);
-            REQUIRE_INDICES(change.modifications_new, 0);
-        }
-
-        SECTION("modifying a non-matching row which is after the distinct results in the table to be a same value \
-                in the distinct results doesn't send notification.") {
-            write([&] {
-                table->get_object(object_keys[6]).set(col_value, 2);
-            });
-            REQUIRE(notification_calls == 1);
-        }
-
-        SECTION("modifying a non-matching row which is before the distinct results in the table to be a same value \
-                in the distinct results send insert + delete.") {
-            write([&] {
-                table->get_object(object_keys[0]).set(col_value, 2);
-            });
-            REQUIRE(notification_calls == 2);
-            REQUIRE_INDICES(change.deletions, 0);
-            REQUIRE_INDICES(change.insertions, 0);
-        }
-
-        SECTION("modifying a matching row to duplicated value in distinct results marks that row as deleted") {
-            write([&] {
-                table->get_object(object_keys[2]).set(col_value, 2);
-            });
-            REQUIRE(notification_calls == 2);
-            REQUIRE_INDICES(change.deletions, 1);
-        }
-
-        SECTION("modifying a non-matching row to match and different value marks that row as inserted") {
-            write([&] {
-                table->get_object(object_keys[0]).set(col_value, 1);
-            });
-            REQUIRE(notification_calls == 2);
-            REQUIRE_INDICES(change.insertions, 0);
-        }
-    }
-
-    SECTION("schema changes") {
-        CollectionChangeSet change;
-        auto token = results.add_notification_callback([&](CollectionChangeSet c, std::exception_ptr err) {
-            REQUIRE_FALSE(err);
-            change = c;
-        });
-        advance_and_notify(*r);
-
-        auto write = [&](auto&& f) {
-            r->begin_transaction();
-            f();
-            r->commit_transaction();
-            advance_and_notify(*r);
-        };
-
-        SECTION("insert table before observed table") {
-            write([&] {
-                table->create_object(ObjKey(53)).set(col_value, 5);
-                r->read_group().add_table("new table");
-                table->create_object(ObjKey(0)).set(col_value, 5);
-            });
-            REQUIRE_INDICES(change.insertions, 0, 5);
-        }
-
-        auto linked_table = table->get_link_target(col_link);
-        auto col = linked_table->get_column_key("value");
-        SECTION("insert new column before link column") {
-            write([&] {
-                linked_table->get_object(target_keys[1]).set(col, 5);
-                table->add_column(type_Int, "new col");
-                linked_table->get_object(target_keys[2]).set(col, 5);
-            });
-            REQUIRE_INDICES(change.modifications, 0, 1);
-        }
-#ifdef UNITTESTS_NOT_PARSING
-        SECTION("insert table before link target") {
-            write([&] {
-                linked_table->get_object(target_keys[1]).set(col, 5);
-                r->read_group().add_table("new table");
-                linked_table->get_object(target_keys[2]).set(col, 5);
-            });
-            REQUIRE_INDICES(change.modifications, 0, 1);
-        }
-#endif
-    }
-}
-
-TEST_CASE("results: notifications after move") {
-    InMemoryTestFile config;
-    config.automatic_change_notifications = false;
-
-    auto r = Realm::get_shared_realm(config);
-    r->update_schema({
-        {"object", {
-            {"value", PropertyType::Int},
-        }},
-    });
-
-    auto table = r->read_group().get_table("class_object");
-    auto results = std::make_unique<Results>(r, table);
-
-    int notification_calls = 0;
-    auto token = results->add_notification_callback([&](CollectionChangeSet, std::exception_ptr err) {
-        REQUIRE_FALSE(err);
-        ++notification_calls;
-    });
-
-    advance_and_notify(*r);
-
-    auto write = [&](auto&& f) {
-        r->begin_transaction();
-        f();
-        r->commit_transaction();
-        advance_and_notify(*r);
-    };
-
-    SECTION("notifications continue to work after Results is moved (move-constructor)") {
-        Results r(std::move(*results));
-        results.reset();
-
-        write([&] {
-            table->create_object().set_all(1);
-        });
-        REQUIRE(notification_calls == 2);
-    }
-
-    SECTION("notifications continue to work after Results is moved (move-assignment)") {
-        Results r;
-        r = std::move(*results);
-        results.reset();
-
-        write([&] {
-            table->create_object().set_all(1);
-        });
-        REQUIRE(notification_calls == 2);
-    }
-}
-
-TEST_CASE("results: notifier with no callbacks") {
-    _impl::RealmCoordinator::assert_no_open_realms();
-
-    InMemoryTestFile config;
-    config.automatic_change_notifications = false;
-
-    auto coordinator = _impl::RealmCoordinator::get_coordinator(config.path);
-    auto r = coordinator->get_realm(std::move(config), none);
-    r->update_schema({
-        {"object", {
-            {"value", PropertyType::Int},
-        }},
-    });
-
-    auto table = r->read_group().get_table("class_object");
-    Results results(r, table->where());
-    results.last(); // force evaluation and creation of TableView
-
-    SECTION("refresh() does not block due to implicit notifier") {
-        // Create and then immediately remove a callback because
-        // `automatic_change_notifications = false` makes Results not implicitly
-        // create a notifier
-        results.add_notification_callback([](CollectionChangeSet const&, std::exception_ptr) {});
-
-        auto r2 = coordinator->get_realm(util::Scheduler::get_frozen());
-        r2->begin_transaction();
-        r2->read_group().get_table("class_object")->create_object();
-        r2->commit_transaction();
-
-        r->refresh(); // would deadlock if there was a callback
-    }
-
-    SECTION("refresh() does not attempt to deliver stale results") {
-        results.add_notification_callback([](CollectionChangeSet const&, std::exception_ptr) {});
-
-        // Create version 1
-        r->begin_transaction();
-        table->create_object();
-        r->commit_transaction();
-
-        r->begin_transaction();
-        // Run async query for version 1
-        coordinator->on_change();
-        // Create version 2 without ever letting 1 be delivered
-        table->create_object();
-        r->commit_transaction();
-
-        // Give it a chance to deliver the async query results (and fail, becuse
-        // they're for version 1 and the realm is at 2)
-        r->refresh();
-    }
-
-    SECTION("should not pin the source version even after the Realm has been closed") {
-        auto r2 = coordinator->get_realm();
-        REQUIRE(r != r2);
-        r->close();
-
-        auto& shared_group = TestHelper::get_shared_group(r2);
-        // There's always at least 2 live versions because the previous version
-        // isn't clean up until the *next* commit
-        REQUIRE(shared_group->get_number_of_versions() == 2);
-
-        auto table = r2->read_group().get_table("class_object");
-
-        r2->begin_transaction();
-        table->create_object();
-        r2->commit_transaction();
-        r2->begin_transaction();
-        table->create_object();
-        r2->commit_transaction();
-
-        // Would now be 3 if the closed Realm is still pinning the version it was at
-        REQUIRE(shared_group->get_number_of_versions() == 2);
-    }
-}
-
-TEST_CASE("results: error messages") {
-    InMemoryTestFile config;
-    config.schema = Schema{
-        {"object", {
-            {"value", PropertyType::String},
-        }},
-    };
-
-    auto r = Realm::get_shared_realm(config);
-    auto table = r->read_group().get_table("class_object");
-    Results results(r, table);
-
-    r->begin_transaction();
-    table->create_object();
-    r->commit_transaction();
-
-    SECTION("out of bounds access") {
-        REQUIRE_THROWS_WITH(results.get(5), "Requested index 5 greater than max 0");
-    }
-
-    SECTION("unsupported aggregate operation") {
-        REQUIRE_THROWS_WITH(results.sum("value"), "Cannot sum property 'value': operation not supported for 'string' properties");
-    }
-}
-
-TEST_CASE("results: snapshots") {
-    InMemoryTestFile config;
-    config.automatic_change_notifications = false;
-    config.schema = Schema{
-        {"object", {
-            {"value", PropertyType::Int},
-            {"array", PropertyType::Array|PropertyType::Object, "linked to object"}
-        }},
-        {"linked to object", {
-            {"value", PropertyType::Int}
-        }}
-    };
-
-    auto r = Realm::get_shared_realm(config);
-
-    SECTION("snapshot of empty Results") {
-        Results results;
-        auto snapshot = results.snapshot();
-        REQUIRE(snapshot.size() == 0);
-    }
-
-    auto write = [&](auto&& f) {
-        r->begin_transaction();
-        f();
-        r->commit_transaction();
-        advance_and_notify(*r);
-    };
-
-    SECTION("snapshot of Results based on Table") {
-        auto table = r->read_group().get_table("class_object");
-        Results results(r, table);
-
-        {
-            // A newly-added row should not appear in the snapshot.
-            auto snapshot = results.snapshot();
-            REQUIRE(results.size() == 0);
-            REQUIRE(snapshot.size() == 0);
-            write([=]{
-                table->create_object();
-            });
-            REQUIRE(results.size() == 1);
-            REQUIRE(snapshot.size() == 0);
-        }
-
-        {
-            // Removing a row present in the snapshot should not affect the size of the snapshot,
-            // but will result in the snapshot returning a detached row accessor.
-            auto snapshot = results.snapshot();
-            REQUIRE(results.size() == 1);
-            REQUIRE(snapshot.size() == 1);
-            write([=]{
-                table->begin()->remove();
-            });
-            REQUIRE(results.size() == 0);
-            REQUIRE(snapshot.size() == 1);
-            REQUIRE(!snapshot.get(0).is_valid());
-
-            // Adding a row at the same index that was formerly present in the snapshot shouldn't
-            // affect the state of the snapshot.
-            write([=]{
-                table->create_object();
-            });
-            REQUIRE(snapshot.size() == 1);
-            REQUIRE(!snapshot.get(0).is_valid());
-        }
-    }
-
-    SECTION("snapshot of Results based on LinkView") {
-        auto object = r->read_group().get_table("class_object");
-        auto col_link = object->get_column_key("array");
-        auto linked_to = r->read_group().get_table("class_linked to object");
-
-        write([=]{
-            object->create_object();
-        });
-
-        std::shared_ptr<LnkLst> lv = object->begin()->get_linklist_ptr(col_link);
-        Results results(r, lv);
-
-        {
-            // A newly-added row should not appear in the snapshot.
-            auto snapshot = results.snapshot();
-            REQUIRE(results.size() == 0);
-            REQUIRE(snapshot.size() == 0);
-            write([&]{
-                lv->add(linked_to->create_object().get_key());
-            });
-            REQUIRE(results.size() == 1);
-            REQUIRE(snapshot.size() == 0);
-        }
-
-        {
-            // Removing a row from the link list should not affect the snapshot.
-            auto snapshot = results.snapshot();
-            REQUIRE(results.size() == 1);
-            REQUIRE(snapshot.size() == 1);
-            write([&]{
-                lv->remove(0);
-            });
-            REQUIRE(results.size() == 0);
-            REQUIRE(snapshot.size() == 1);
-            REQUIRE(snapshot.get(0).is_valid());
-
-            // Removing a row present in the snapshot from its table should result in the snapshot
-            // returning a detached row accessor.
-            write([&]{
-                linked_to->begin()->remove();
-            });
-            REQUIRE(snapshot.size() == 1);
-            REQUIRE(!snapshot.get(0).is_valid());
-
-            // Adding a new row to the link list shouldn't affect the state of the snapshot.
-            write([&]{
-                lv->add(linked_to->create_object().get_key());
-            });
-            REQUIRE(snapshot.size() == 1);
-            REQUIRE(!snapshot.get(0).is_valid());
-        }
-    }
-
-    SECTION("snapshot of Results based on Query") {
-        auto table = r->read_group().get_table("class_object");
-        auto col_value = table->get_column_key("value");
-        Query q = table->column<Int>(col_value) > 0;
-        Results results(r, std::move(q));
-
-        {
-            // A newly-added row should not appear in the snapshot.
-            auto snapshot = results.snapshot();
-            REQUIRE(results.size() == 0);
-            REQUIRE(snapshot.size() == 0);
-            write([=]{
-                table->create_object().set(col_value, 1);
-            });
-            REQUIRE(results.size() == 1);
-            REQUIRE(snapshot.size() == 0);
-        }
-
-        {
-            // Updating a row to no longer match the query criteria should not affect the snapshot.
-            auto snapshot = results.snapshot();
-            REQUIRE(results.size() == 1);
-            REQUIRE(snapshot.size() == 1);
-            write([=]{
-                table->begin()->set(col_value, 0);
-            });
-            REQUIRE(results.size() == 0);
-            REQUIRE(snapshot.size() == 1);
-            REQUIRE(snapshot.get(0).is_valid());
-
-            // Removing a row present in the snapshot from its table should result in the snapshot
-            // returning a detached row accessor.
-            write([=]{
-                table->begin()->remove();
-            });
-            REQUIRE(snapshot.size() == 1);
-            REQUIRE(!snapshot.get(0).is_valid());
-
-            // Adding a new row that matches the query criteria shouldn't affect the state of the snapshot.
-            write([=]{
-                table->create_object().set(col_value, 1);
-            });
-            REQUIRE(snapshot.size() == 1);
-            REQUIRE(!snapshot.get(0).is_valid());
-        }
-    }
-
-    SECTION("snapshot of Results based on TableView from query") {
-        auto table = r->read_group().get_table("class_object");
-        auto col_value = table->get_column_key("value");
-        Query q = table->column<Int>(col_value) > 0;
-        Results results(r, q.find_all());
-
-        {
-            // A newly-added row should not appear in the snapshot.
-            auto snapshot = results.snapshot();
-            REQUIRE(results.size() == 0);
-            REQUIRE(snapshot.size() == 0);
-            write([=]{
-                table->create_object().set(col_value, 1);
-            });
-            REQUIRE(results.size() == 1);
-            REQUIRE(snapshot.size() == 0);
-        }
-
-        {
-            // Updating a row to no longer match the query criteria should not affect the snapshot.
-            auto snapshot = results.snapshot();
-            REQUIRE(results.size() == 1);
-            REQUIRE(snapshot.size() == 1);
-            write([=]{
-                table->begin()->set(col_value, 0);
-            });
-            REQUIRE(results.size() == 0);
-            REQUIRE(snapshot.size() == 1);
-            REQUIRE(snapshot.get(0).is_valid());
-
-            // Removing a row present in the snapshot from its table should result in the snapshot
-            // returning a detached row accessor.
-            write([=]{
-                table->begin()->remove();
-            });
-            REQUIRE(snapshot.size() == 1);
-            REQUIRE(!snapshot.get(0).is_valid());
-
-            // Adding a new row that matches the query criteria shouldn't affect the state of the snapshot.
-            write([=]{
-                table->create_object().set(col_value, 1);
-            });
-            REQUIRE(snapshot.size() == 1);
-            REQUIRE(!snapshot.get(0).is_valid());
-        }
-    }
-
-    SECTION("snapshot of Results based on TableView from backlinks") {
-        auto object = r->read_group().get_table("class_object");
-        auto col_link = object->get_column_key("array");
-        auto linked_to = r->read_group().get_table("class_linked to object");
-
-        write([=]{
-            linked_to->create_object();
-            object->create_object();
-        });
-
-        auto linked_to_obj = *linked_to->begin();
-        auto lv = object->begin()->get_linklist_ptr(col_link);
-
-        TableView backlinks = linked_to_obj.get_backlink_view(object, col_link);
-        Results results(r, std::move(backlinks));
-
-        {
-            // A newly-added row should not appear in the snapshot.
-            auto snapshot = results.snapshot();
-            REQUIRE(results.size() == 0);
-            REQUIRE(snapshot.size() == 0);
-            write([&]{
-                lv->add(linked_to_obj.get_key());
-            });
-            REQUIRE(results.size() == 1);
-            REQUIRE(snapshot.size() == 0);
-        }
-
-        {
-            // Removing the link should not affect the snapshot.
-            auto snapshot = results.snapshot();
-            REQUIRE(results.size() == 1);
-            REQUIRE(snapshot.size() == 1);
-            write([&]{
-                if (lv->size() > 0)
-                    lv->remove(0);
-            });
-            REQUIRE(results.size() == 0);
-            REQUIRE(snapshot.size() == 1);
-            REQUIRE(snapshot.get(0).is_valid());
-
-            // Removing a row present in the snapshot from its table should result in the snapshot
-            // returning a detached row accessor.
-            write([=]{
-                object->begin()->remove();
-            });
-            REQUIRE(snapshot.size() == 1);
-            REQUIRE(!snapshot.get(0).is_valid());
-
-            // Adding a new link shouldn't affect the state of the snapshot.
-            write([=]{
-                object->create_object().get_linklist(col_link).add(linked_to_obj.get_key());
-            });
-            REQUIRE(snapshot.size() == 1);
-            REQUIRE(!snapshot.get(0).is_valid());
-        }
-    }
-
-    SECTION("snapshot of Results with notification callback registered") {
-        auto table = r->read_group().get_table("class_object");
-        auto col_value = table->get_column_key("value");
-        Query q = table->column<Int>(col_value) > 0;
-        Results results(r, q.find_all());
-
-        auto token = results.add_notification_callback([&](CollectionChangeSet, std::exception_ptr err) {
-            REQUIRE_FALSE(err);
-        });
-        advance_and_notify(*r);
-
-        SECTION("snapshot of lvalue") {
-            auto snapshot = results.snapshot();
-            write([=] {
-                table->create_object().set(col_value, 1);
-            });
-            REQUIRE(snapshot.size() == 0);
-        }
-
-        SECTION("snapshot of rvalue") {
-            auto snapshot = std::move(results).snapshot();
-            write([=] {
-                table->create_object().set(col_value, 1);
-            });
-            REQUIRE(snapshot.size() == 0);
-        }
-    }
-
-    SECTION("adding notification callback to snapshot throws") {
-        auto table = r->read_group().get_table("class_object");
-        auto col_value = table->get_column_key("value");
-        Query q = table->column<Int>(col_value) > 0;
-        Results results(r, q.find_all());
-        auto snapshot = results.snapshot();
-        CHECK_THROWS(snapshot.add_notification_callback([](CollectionChangeSet, std::exception_ptr) {}));
-    }
-
-    SECTION("accessors should return none for detached row") {
-        auto table = r->read_group().get_table("class_object");
-        write([=] {
-            table->create_object();
-        });
-        Results results(r, table);
-        auto snapshot = results.snapshot();
-        write([=] {;
-            table->clear();
-        });
-
-        REQUIRE_FALSE(snapshot.get(0).is_valid());
-        REQUIRE_FALSE(snapshot.first()->is_valid());
-        REQUIRE_FALSE(snapshot.last()->is_valid());
-    }
-}
-
-TEST_CASE("results: distinct") {
-    const int N = 10;
-    InMemoryTestFile config;
-    config.automatic_change_notifications = false;
-
-    auto r = Realm::get_shared_realm(config);
-    r->update_schema({
-        {"object", {
-            {"num1", PropertyType::Int},
-            {"string", PropertyType::String},
-            {"num2", PropertyType::Int},
-            {"num3", PropertyType::Int}
-        }},
-    });
-
-    auto table = r->read_group().get_table("class_object");
-
-    r->begin_transaction();
-    for (int i = 0; i < N; ++i) {
-        table->create_object().set_all(i % 3, util::format("Foo_%1", i % 3).c_str(), N - i, i % 2);
-    }
-    // table:
-    //   0, Foo_0, 10,  0
-    //   1, Foo_1,  9,  1
-    //   2, Foo_2,  8,  0
-    //   0, Foo_0,  7,  1
-    //   1, Foo_1,  6,  0
-    //   2, Foo_2,  5,  1
-    //   0, Foo_0,  4,  0
-    //   1, Foo_1,  3,  1
-    //   2, Foo_2,  2,  0
-    //   0, Foo_0,  1,  1
-
-    r->commit_transaction();
-    Results results(r, table->where());
-    ColKey col_num1 = table->get_column_key("num1");
-    ColKey col_string = table->get_column_key("string");
-    ColKey col_num2 = table->get_column_key("num2");
-    ColKey col_num3 = table->get_column_key("num3");
-
-    SECTION("Single integer property") {
-        Results unique = results.distinct(DistinctDescriptor({{col_num1}}));
-        // unique:
-        //  0, Foo_0, 10
-        //  1, Foo_1,  9
-        //  2, Foo_2,  8
-        REQUIRE(unique.size() == 3);
-        REQUIRE(unique.get(0).get<Int>(col_num2) == 10);
-        REQUIRE(unique.get(1).get<Int>(col_num2) == 9);
-        REQUIRE(unique.get(2).get<Int>(col_num2) == 8);
-    }
-
-    SECTION("Single integer via apply_ordering") {
-        DescriptorOrdering ordering;
-        ordering.append_sort(SortDescriptor({{col_num1}}));
-        ordering.append_distinct(DistinctDescriptor({{col_num1}}));
-        Results unique = results.apply_ordering(std::move(ordering));
-        // unique:
-        //  0, Foo_0, 10
-        //  1, Foo_1,  9
-        //  2, Foo_2,  8
-        REQUIRE(unique.size() == 3);
-        REQUIRE(unique.get(0).get<Int>(col_num2) == 10);
-        REQUIRE(unique.get(1).get<Int>(col_num2) == 9);
-        REQUIRE(unique.get(2).get<Int>(col_num2) == 8);
-    }
-
-    SECTION("Single string property") {
-        Results unique = results.distinct(DistinctDescriptor({{col_string}}));
-        // unique:
-        //  0, Foo_0, 10
-        //  1, Foo_1,  9
-        //  2, Foo_2,  8
-        REQUIRE(unique.size() == 3);
-        REQUIRE(unique.get(0).get<Int>(col_num2) == 10);
-        REQUIRE(unique.get(1).get<Int>(col_num2) == 9);
-        REQUIRE(unique.get(2).get<Int>(col_num2) == 8);
-    }
-
-    SECTION("Two integer properties combined") {
-        Results unique = results.distinct(DistinctDescriptor({{col_num1}, {col_num2}}));
-        // unique is the same as the table
-        REQUIRE(unique.size() == N);
-        for (int i = 0; i < N; ++i) {
-            REQUIRE(unique.get(i).get<String>(col_string) == StringData(util::format("Foo_%1", i % 3).c_str()));
-        }
-    }
-
-    SECTION("String and integer combined") {
-        Results unique = results.distinct(DistinctDescriptor({{col_num2}, {col_string}}));
-        // unique is the same as the table
-        REQUIRE(unique.size() == N);
-        for (int i = 0; i < N; ++i) {
-            REQUIRE(unique.get(i).get<String>(col_string) == StringData(util::format("Foo_%1", i % 3).c_str()));
-        }
-    }
-
-    // This section and next section demonstrate that sort().distinct() != distinct().sort()
-    SECTION("Order after sort and distinct") {
-        Results reverse = results.sort(SortDescriptor({{col_num2}}, {true}));
-        // reverse:
-        //   0, Foo_0,  1
-        //  ...
-        //   0, Foo_0, 10
-        REQUIRE(reverse.first()->get<Int>(col_num2) == 1);
-        REQUIRE(reverse.last()->get<Int>(col_num2) == 10);
-
-        // distinct() will be applied to the table, after sorting
-        Results unique = reverse.distinct(DistinctDescriptor({{col_num1}}));
-        // unique:
-        //  0, Foo_0,  1
-        //  2, Foo_2,  2
-        //  1, Foo_1,  3
-        REQUIRE(unique.size() == 3);
-        REQUIRE(unique.get(0).get<Int>(col_num2) == 1);
-        REQUIRE(unique.get(1).get<Int>(col_num2) == 2);
-        REQUIRE(unique.get(2).get<Int>(col_num2) == 3);
-    }
-
-    SECTION("Order after distinct and sort") {
-        Results unique = results.distinct(DistinctDescriptor({{col_num1}}));
-        // unique:
-        //  0, Foo_0, 10
-        //  1, Foo_1,  9
-        //  2, Foo_2,  8
-        REQUIRE(unique.size() == 3);
-        REQUIRE(unique.first()->get<Int>(col_num2) == 10);
-        REQUIRE(unique.last()->get<Int>(col_num2) == 8);
-
-        // sort() is only applied to unique
-        Results reverse = unique.sort(SortDescriptor({{col_num2}}, {true}));
-        // reversed:
-        //  2, Foo_2,  8
-        //  1, Foo_1,  9
-        //  0, Foo_0, 10
-        REQUIRE(reverse.size() == 3);
-        REQUIRE(reverse.get(0).get<Int>(col_num2) == 8);
-        REQUIRE(reverse.get(1).get<Int>(col_num2) == 9);
-        REQUIRE(reverse.get(2).get<Int>(col_num2) == 10);
-    }
-
-    SECTION("Chaining distinct") {
-        Results first = results.distinct(DistinctDescriptor({{col_num1}}));
-        REQUIRE(first.size() == 3);
-
-        // distinct() will not discard the previous applied distinct() calls
-        Results second = first.distinct(DistinctDescriptor({{col_num3}}));
-        REQUIRE(second.size() == 2);
-    }
-
-    SECTION("Chaining sort") {
-        using cols_0_3 = std::pair<int, int>;
-        Results first = results.sort(SortDescriptor({{col_num1}}));
-        Results second = first.sort(SortDescriptor({{col_num3}}));
-
-        REQUIRE(second.size() == 10);
-        // results are ordered first by the last sorted column
-        // if any duplicates exist in that column, they are resolved by sorting the
-        // previously sorted column. Eg. sort(a).sort(b) == sort(b, a)
-        std::vector<cols_0_3> results
-            = {{0, 0}, {0, 0}, {1, 0}, {2, 0}, {2, 0}, {0, 1}, {0, 1}, {1, 1}, {1, 1}, {2, 1}};
-        for (size_t i = 0; i < results.size(); ++i) {
-            REQUIRE(second.get(i).get<Int>(col_num1) == results[i].first);
-            REQUIRE(second.get(i).get<Int>(col_num3) == results[i].second);
-        }
-    }
-
-    SECTION("Distinct is carried over to new queries") {
-        Results unique = results.distinct(DistinctDescriptor({{col_num1}}));
-        // unique:
-        //  0, Foo_0, 10
-        //  1, Foo_1,  9
-        //  2, Foo_2,  8
-        REQUIRE(unique.size() == 3);
-
-        Results filtered = unique.filter(Query(table->where().less(col_num1, 2)));
-        // filtered:
-        //  0, Foo_0, 10
-        //  1, Foo_1,  9
-        REQUIRE(filtered.size() == 2);
-        REQUIRE(filtered.get(0).get<Int>(col_num2) == 10);
-        REQUIRE(filtered.get(1).get<Int>(col_num2) == 9);
-    }
-
-    SECTION("Distinct will not forget previous query") {
-        Results filtered = results.filter(Query(table->where().greater(col_num2, 5)));
-        // filtered:
-        //   0, Foo_0, 10
-        //   1, Foo_1,  9
-        //   2, Foo_2,  8
-        //   0, Foo_0,  7
-        //   1, Foo_1,  6
-        REQUIRE(filtered.size() == 5);
-
-        Results unique = filtered.distinct(DistinctDescriptor({{col_num1}}));
-        // unique:
-        //   0, Foo_0, 10
-        //   1, Foo_1,  9
-        //   2, Foo_2,  8
-        REQUIRE(unique.size() == 3);
-        REQUIRE(unique.get(0).get<Int>(col_num2) == 10);
-        REQUIRE(unique.get(1).get<Int>(col_num2) == 9);
-        REQUIRE(unique.get(2).get<Int>(col_num2) == 8);
-
-        Results further_filtered = unique.filter(Query(table->where().equal(col_num2, 9)));
-        // further_filtered:
-        //   1, Foo_1,  9
-        REQUIRE(further_filtered.size() == 1);
-        REQUIRE(further_filtered.get(0).get<Int>(col_num2) == 9);
-    }
-}
-
-TEST_CASE("results: sort") {
-    InMemoryTestFile config;
-    config.schema = Schema{
-        {"object", {
-            {"value", PropertyType::Int},
-            {"bool", PropertyType::Bool},
-            {"data prop", PropertyType::Data},
-            {"link", PropertyType::Object|PropertyType::Nullable, "object 2"},
-            {"array", PropertyType::Object|PropertyType::Array, "object 2"},
-        }},
-        {"object 2", {
-            {"value", PropertyType::Int},
-            {"link", PropertyType::Object|PropertyType::Nullable, "object"},
-        }},
-    };
-
-    auto realm = Realm::get_shared_realm(config);
-    auto table = realm->read_group().get_table("class_object");
-    auto table2 = realm->read_group().get_table("class_object 2");
-    Results r(realm, table);
-
-    SECTION("invalid keypaths") {
-        SECTION("empty property name") {
-            REQUIRE_THROWS_WITH(r.sort({{"", true}}), "Cannot sort on key path '': missing property name.");
-            REQUIRE_THROWS_WITH(r.sort({{".", true}}), "Cannot sort on key path '.': missing property name.");
-            REQUIRE_THROWS_WITH(r.sort({{"link.", true}}), "Cannot sort on key path 'link.': missing property name.");
-            REQUIRE_THROWS_WITH(r.sort({{".value", true}}), "Cannot sort on key path '.value': missing property name.");
-            REQUIRE_THROWS_WITH(r.sort({{"link..value", true}}), "Cannot sort on key path 'link..value': missing property name.");
-        }
-        SECTION("bad property name") {
-            REQUIRE_THROWS_WITH(r.sort({{"not a property", true}}),
-                                "Cannot sort on key path 'not a property': property 'object.not a property' does not exist.");
-            REQUIRE_THROWS_WITH(r.sort({{"link.not a property", true}}),
-                                "Cannot sort on key path 'link.not a property': property 'object 2.not a property' does not exist.");
-        }
-        SECTION("subscript primitive") {
-            REQUIRE_THROWS_WITH(r.sort({{"value.link", true}}),
-                                "Cannot sort on key path 'value.link': property 'object.value' of type 'int' may only be the final property in the key path.");
-        }
-        SECTION("end in link") {
-            REQUIRE_THROWS_WITH(r.sort({{"link", true}}),
-                                "Cannot sort on key path 'link': property 'object.link' of type 'object' cannot be the final property in the key path.");
-            REQUIRE_THROWS_WITH(r.sort({{"link.link", true}}),
-                                "Cannot sort on key path 'link.link': property 'object 2.link' of type 'object' cannot be the final property in the key path.");
-        }
-        SECTION("sort involving bad property types") {
-            REQUIRE_THROWS_WITH(r.sort({{"array", true}}),
-                                "Cannot sort on key path 'array': property 'object.array' is of unsupported type 'array'.");
-            REQUIRE_THROWS_WITH(r.sort({{"array.value", true}}),
-                                "Cannot sort on key path 'array.value': property 'object.array' is of unsupported type 'array'.");
-            REQUIRE_THROWS_WITH(r.sort({{"link.link.array.value", true}}),
-                                "Cannot sort on key path 'link.link.array.value': property 'object.array' is of unsupported type 'array'.");
-            REQUIRE_THROWS_WITH(r.sort({{"data prop", true}}),
-                                "Cannot sort on key path 'data prop': property 'object.data prop' is of unsupported type 'data'.");
-        }
-    }
-
-    realm->begin_transaction();
-    ObjKeys table_keys;
-    ObjKeys table2_keys;
-    table->create_objects(4, table_keys);
-    table2->create_objects(4, table2_keys);
-    ColKey col_link = table->get_column_key("link");
-    ColKey col_link2 = table2->get_column_key("link");
-    for (int i = 0; i < 4; ++i) {
-        table->get_object(table_keys[i]).set_all((i + 2) % 4, bool(i % 2)).set(col_link, table2_keys[3 - i]);
-        table2->get_object(table2_keys[i]).set_all((i + 1) % 4).set(col_link2, table_keys[i]);
-    }
-    realm->commit_transaction();
-    /*
-     | index | value | bool | link.value | link.link.value |
-     |-------|-------|------|------------|-----------------|
-     | 0     | 2     | 0    | 0          | 1               |
-     | 1     | 3     | 1    | 3          | 0               |
-     | 2     | 0     | 0    | 2          | 3               |
-     | 3     | 1     | 1    | 1          | 2               |
-     */
-
-    #define REQUIRE_ORDER(sort, ...) do { \
-        ObjKeys expected({__VA_ARGS__}); \
-        auto results = sort; \
-        REQUIRE(results.size() == expected.size()); \
-        for (size_t i = 0; i < expected.size(); ++i) \
-            REQUIRE(results.get(i).get_key() == expected[i]); \
-    } while (0)
-
-    SECTION("sort on single property") {
-        REQUIRE_ORDER((r.sort({{"value", true}})),
-                      2, 3, 0, 1);
-        REQUIRE_ORDER((r.sort({{"value", false}})),
-                      1, 0, 3, 2);
-    }
-
-    SECTION("sort on two properties") {
-        REQUIRE_ORDER((r.sort({{"bool", true}, {"value", true}})),
-                      2, 0, 3, 1);
-        REQUIRE_ORDER((r.sort({{"bool", false}, {"value", true}})),
-                      3, 1, 2, 0);
-        REQUIRE_ORDER((r.sort({{"bool", true}, {"value", false}})),
-                      0, 2, 1, 3);
-        REQUIRE_ORDER((r.sort({{"bool", false}, {"value", false}})),
-                      1, 3, 0, 2);
-    }
-    SECTION("sort over link") {
-        REQUIRE_ORDER((r.sort({{"link.value", true}})),
-                      0, 3, 2, 1);
-        REQUIRE_ORDER((r.sort({{"link.value", false}})),
-                      1, 2, 3, 0);
-    }
-    SECTION("sort over two links") {
-        REQUIRE_ORDER((r.sort({{"link.link.value", true}})),
-                      1, 0, 3, 2);
-        REQUIRE_ORDER((r.sort({{"link.link.value", false}})),
-                      2, 3, 0, 1);
-    }
-}
-
-struct ResultsFromTable {
-    static Results call(std::shared_ptr<Realm> r, ConstTableRef table) {
-        return Results(std::move(r), table);
-    }
-};
-struct ResultsFromQuery {
-    static Results call(std::shared_ptr<Realm> r, ConstTableRef table) {
-        return Results(std::move(r), table->where());
-    }
-};
-struct ResultsFromTableView {
-    static Results call(std::shared_ptr<Realm> r, ConstTableRef table) {
-        return Results(std::move(r), table->where().find_all());
-    }
-};
-struct ResultsFromLinkView {
-    static Results call(std::shared_ptr<Realm> r, ConstTableRef table) {
-        r->begin_transaction();
-        auto link_table = r->read_group().get_table("class_linking_object");
-        std::shared_ptr<LnkLst> link_view = link_table->create_object().get_linklist_ptr(link_table->get_column_key("link"));
-        for (auto& o : *table)
-            link_view->add(o.get_key());
-        r->commit_transaction();
-        return Results(r, link_view);
-    }
-};
-
-TEMPLATE_TEST_CASE("results: get()", "", ResultsFromTable, ResultsFromQuery, ResultsFromTableView, ResultsFromLinkView) {
-    InMemoryTestFile config;
-    config.automatic_change_notifications = false;
-
-    auto r = Realm::get_shared_realm(config);
-    r->update_schema({
-        {"object", {
-            {"value", PropertyType::Int},
-        }},
-        {"linking_object", {
-            {"link", PropertyType::Array|PropertyType::Object, "object"}
-        }},
-    });
-
-    auto table = r->read_group().get_table("class_object");
-    ColKey col_value = table->get_column_key("value");
-
-    r->begin_transaction();
-    for (int i = 0; i < 10; ++i)
-        table->create_object().set_all(i);
-    r->commit_transaction();
-
-    Results results = TestType::call(r, table);
-
-    SECTION("sequential in increasing order") {
-        for (int i = 0; i < 10; ++i)
-            CHECK(results.get<Obj>(i).get<int64_t>(col_value) == i);
-        for (int i = 0; i < 10; ++i)
-            CHECK(results.get<Obj>(i).get<int64_t>(col_value) == i);
-        CHECK_THROWS(results.get(11));
-    }
-    SECTION("sequential in decreasing order") {
-        for (int i = 9; i >= 0; --i)
-            CHECK(results.get<Obj>(i).get<int64_t>(col_value) == i);
-        for (int i = 9; i >= 0; --i)
-            CHECK(results.get<Obj>(i).get<int64_t>(col_value) == i);
-    }
-    SECTION("random order") {
-        int indexes[10];
-        std::iota(std::begin(indexes), std::end(indexes), 0);
-        std::random_device rd;
-        std::mt19937 g(rd());
-        std::shuffle(std::begin(indexes), std::end(indexes), std::mt19937(rd()));
-        for (auto index : indexes)
-            CHECK(results.get<Obj>(index).get<int64_t>(col_value) == index);
-    }
-}
-
-TEMPLATE_TEST_CASE("results: aggregate", "[query][aggregate]", ResultsFromTable, ResultsFromQuery, ResultsFromTableView, ResultsFromLinkView) {
-    InMemoryTestFile config;
-    config.automatic_change_notifications = false;
-
-    auto r = Realm::get_shared_realm(config);
-    r->update_schema({
-        {"object", {
-            {"int", PropertyType::Int|PropertyType::Nullable},
-            {"float", PropertyType::Float|PropertyType::Nullable},
-            {"double", PropertyType::Double|PropertyType::Nullable},
-            {"date", PropertyType::Date|PropertyType::Nullable},
-        }},
-        {"linking_object", {
-            {"link", PropertyType::Array|PropertyType::Object, "object"}
-        }},
-    });
-
-    auto table = r->read_group().get_table("class_object");
-    ColKey col_int = table->get_column_key("int");
-    ColKey col_float = table->get_column_key("float");
-    ColKey col_double = table->get_column_key("double");
-    ColKey col_date = table->get_column_key("date");
-
-    SECTION("one row with null values") {
-        r->begin_transaction();
-        table->create_object();
-        table->create_object().set_all(0, 0.f, 0.0, Timestamp(0, 0));
-        table->create_object().set_all(2, 2.f, 2.0, Timestamp(2, 0));
-        // table:
-        //  null, null, null,  null,
-        //  0,    0,    0,    (0, 0)
-        //  2,    2,    2,    (2, 0)
-        r->commit_transaction();
-
-        Results results = TestType::call(r, table);
-
-        SECTION("max") {
-            REQUIRE(results.max(col_int)->get_int() == 2);
-            REQUIRE(results.max(col_float)->get_float() == 2.f);
-            REQUIRE(results.max(col_double)->get_double() == 2.0);
-            REQUIRE(results.max(col_date)->get_timestamp() == Timestamp(2, 0));
-        }
-
-        SECTION("min") {
-            REQUIRE(results.min(col_int)->get_int() == 0);
-            REQUIRE(results.min(col_float)->get_float() == 0.f);
-            REQUIRE(results.min(col_double)->get_double() == 0.0);
-            REQUIRE(results.min(col_date)->get_timestamp() == Timestamp(0, 0));
-        }
-
-        SECTION("average") {
-            REQUIRE(results.average(col_int) == 1.0);
-            REQUIRE(results.average(col_float) == 1.0);
-            REQUIRE(results.average(col_double) == 1.0);
-            REQUIRE_THROWS_AS(results.average(col_date), Results::UnsupportedColumnTypeException);
-        }
-
-        SECTION("sum") {
-            REQUIRE(results.sum(col_int)->get_int() == 2);
-            REQUIRE(results.sum(col_float)->get_double() == 2.0);
-            REQUIRE(results.sum(col_double)->get_double() == 2.0);
-            REQUIRE_THROWS_AS(results.sum(col_date), Results::UnsupportedColumnTypeException);
-        }
-    }
-
-    SECTION("rows with all null values") {
-        r->begin_transaction();
-        table->create_object();
-        table->create_object();
-        table->create_object();
-        // table:
-        //  null, null, null,  null,  null
-        //  null, null, null,  null,  null
-        //  null, null, null,  null,  null
-        r->commit_transaction();
-
-        Results results = TestType::call(r, table);
-
-        SECTION("max") {
-            REQUIRE(!results.max(col_int));
-            REQUIRE(!results.max(col_float));
-            REQUIRE(!results.max(col_double));
-            REQUIRE(!results.max(col_date));
-        }
-
-        SECTION("min") {
-            REQUIRE(!results.min(col_int));
-            REQUIRE(!results.min(col_float));
-            REQUIRE(!results.min(col_double));
-            REQUIRE(!results.min(col_date));
-        }
-
-        SECTION("average") {
-            REQUIRE(!results.average(col_int));
-            REQUIRE(!results.average(col_float));
-            REQUIRE(!results.average(col_double));
-            REQUIRE_THROWS_AS(results.average(col_date), Results::UnsupportedColumnTypeException);
-        }
-
-        SECTION("sum") {
-            REQUIRE(results.sum(col_int)->get_int() == 0);
-            REQUIRE(results.sum(col_float)->get_double() == 0.0);
-            REQUIRE(results.sum(col_double)->get_double() == 0.0);
-            REQUIRE_THROWS_AS(results.sum(col_date), Results::UnsupportedColumnTypeException);
-        }
-    }
-
-    SECTION("empty") {
-        Results results = TestType::call(r, table);
-
-        SECTION("max") {
-            REQUIRE(!results.max(col_int));
-            REQUIRE(!results.max(col_float));
-            REQUIRE(!results.max(col_double));
-            REQUIRE(!results.max(col_date));
-        }
-
-        SECTION("min") {
-            REQUIRE(!results.min(col_int));
-            REQUIRE(!results.min(col_float));
-            REQUIRE(!results.min(col_double));
-            REQUIRE(!results.min(col_date));
-        }
-
-        SECTION("average") {
-            REQUIRE(!results.average(col_int));
-            REQUIRE(!results.average(col_float));
-            REQUIRE(!results.average(col_double));
-            REQUIRE_THROWS_AS(results.average(col_date), Results::UnsupportedColumnTypeException);
-        }
-
-        SECTION("sum") {
-            REQUIRE(results.sum(col_int)->get_int() == 0);
-            REQUIRE(results.sum(col_float)->get_double() == 0.0);
-            REQUIRE(results.sum(col_double)->get_double() == 0.0);
-            REQUIRE_THROWS_AS(results.sum(col_date), Results::UnsupportedColumnTypeException);
-        }
-    }
-}
-
-TEST_CASE("results: set property value on all objects", "[batch_updates]") {
-
-    InMemoryTestFile config;
-    config.automatic_change_notifications = false;
-    // config.cache = false;
-    config.schema = Schema{
-        {"AllTypes", {
-            {"pk", PropertyType::Int, Property::IsPrimary{true}},
-            {"bool", PropertyType::Bool},
-            {"int", PropertyType::Int},
-            {"float", PropertyType::Float},
-            {"double", PropertyType::Double},
-            {"string", PropertyType::String},
-            {"data", PropertyType::Data},
-            {"date", PropertyType::Date},
-            {"object", PropertyType::Object|PropertyType::Nullable, "AllTypes"},
-            {"list", PropertyType::Array|PropertyType::Object, "AllTypes"},
-
-            {"bool array", PropertyType::Array|PropertyType::Bool},
-            {"int array", PropertyType::Array|PropertyType::Int},
-            {"float array", PropertyType::Array|PropertyType::Float},
-            {"double array", PropertyType::Array|PropertyType::Double},
-            {"string array", PropertyType::Array|PropertyType::String},
-            {"data array", PropertyType::Array|PropertyType::Data},
-            {"date array", PropertyType::Array|PropertyType::Date},
-            {"object array", PropertyType::Array|PropertyType::Object, "AllTypes"},
-        }, {
-           {"parents", PropertyType::LinkingObjects|PropertyType::Array, "AllTypes", "object"},
-        }}
-    };
-    config.schema_version = 0;
-    auto realm = Realm::get_shared_realm(config);
-    auto table = realm->read_group().get_table("class_AllTypes");
-    realm->begin_transaction();
-    table->create_object();
-    table->create_object();
-    realm->commit_transaction();
-    Results r(realm, table);
-
-    TestContext ctx(realm);
-
-    SECTION("non-existing property name") {
-        realm->begin_transaction();
-        REQUIRE_THROWS_AS(r.set_property_value(ctx, "i dont exist", util::Any(false)), Results::InvalidPropertyException);
-        realm->cancel_transaction();
-    }
-
-    SECTION("readonly property") {
-        realm->begin_transaction();
-        REQUIRE_THROWS_AS(r.set_property_value(ctx, "parents", util::Any(false)), ReadOnlyPropertyException);
-        realm->cancel_transaction();
-    }
-
-    SECTION("primarykey property") {
-        realm->begin_transaction();
-        REQUIRE_THROWS_AS(r.set_property_value(ctx, "pk", util::Any(1)), std::logic_error);
-        realm->cancel_transaction();
-    }
-
-    SECTION("set property values removes object from Results") {
-        realm->begin_transaction();
-        Results results(realm, table->where().equal(table->get_column_key("int"),0));
-        CHECK(results.size() == 2);
-        r.set_property_value(ctx, "int", util::Any(INT64_C(42)));
-        CHECK(results.size() == 0);
-        realm->cancel_transaction();
-    }
-
-    SECTION("set property value") {
-        realm->begin_transaction();
-
-        r.set_property_value<util::Any>(ctx, "bool", util::Any(true));
-        for (size_t i = 0; i < r.size(); i++) {
-            CHECK(r.get(i).get<Bool>("bool") == true);
-        }
-
-        r.set_property_value(ctx, "int", util::Any(INT64_C(42)));
-        for (size_t i = 0; i < r.size(); i++) {
-            CHECK(r.get(i).get<Int>("int") == 42);
-        }
-
-        r.set_property_value(ctx, "float", util::Any(1.23f));
-        for (size_t i = 0; i < r.size(); i++) {
-            CHECK(r.get(i).get<float>("float") == 1.23f);
-        }
-
-        r.set_property_value(ctx, "double", util::Any(1.234));
-        for (size_t i = 0; i < r.size(); i++) {
-            CHECK(r.get(i).get<double>("double") == 1.234);
-        }
-
-        r.set_property_value(ctx, "string", util::Any(std::string("abc")));
-        for (size_t i = 0; i < r.size(); i++) {
-            CHECK(r.get(i).get<String>("string") == "abc");
-        }
-
-        r.set_property_value(ctx, "data", util::Any(std::string("abc")));
-        for (size_t i = 0; i < r.size(); i++) {
-            CHECK(r.get(i).get<Binary>("data") == BinaryData("abc", 3));
-        }
-
-        util::Any timestamp = Timestamp(1, 2);
-        r.set_property_value(ctx, "date", timestamp);
-        for (size_t i = 0; i < r.size(); i++) {
-            CHECK(r.get(i).get<Timestamp>("date") == any_cast<Timestamp>(timestamp));
-        }
-
-        ObjKey object_key = table->create_object().get_key();
-        Object linked_obj(realm, "AllTypes", object_key);
-        r.set_property_value(ctx, "object", util::Any(linked_obj));
-        for (size_t i = 0; i < r.size(); i++) {
-            CHECK(r.get(i).get<ObjKey>("object") == object_key);
-        }
-
-        ObjKey list_object_key = table->create_object().get_key();
-        Object list_object(realm, "AllTypes", list_object_key);
-        r.set_property_value(ctx, "list", util::Any(AnyVector{list_object, list_object}));
-        for (size_t i = 0; i < r.size(); i++) {
-            auto list = r.get(i).get_linklist("list");
-            CHECK(list.size() == 2);
-            CHECK(list.get(0) == list_object_key);
-            CHECK(list.get(1) == list_object_key);
-        }
-
-        auto check_array = [&](ColKey col, auto val0, auto... values) {
-            size_t rows = r.size();
-            for (size_t i = 0; i < rows; ++i) {
-                Obj row = r.get(i);
-                auto array = row.get_list<decltype(val0)>(col);
-                CAPTURE(0);
-                REQUIRE(val0 == array.get(0));
-                size_t j = 1;
-                for (auto& value : {values...}) {
-                    CAPTURE(j);
-                    REQUIRE(j < array.size());
-                    REQUIRE(value == array.get(j));
-                    ++j;
-                }
-            }
-        };
-
-        r.set_property_value(ctx, "bool array", util::Any(AnyVec{true, false}));
-        check_array(table->get_column_key("bool array"), true, false);
-
-        r.set_property_value(ctx, "int array", util::Any(AnyVec{INT64_C(5), INT64_C(6)}));
-        check_array(table->get_column_key("int array"), INT64_C(5), INT64_C(6));
-
-        r.set_property_value(ctx, "float array", util::Any(AnyVec{1.1f, 2.2f}));
-        check_array(table->get_column_key("float array"), 1.1f, 2.2f);
-
-        r.set_property_value(ctx, "double array", util::Any(AnyVec{3.3, 4.4}));
-        check_array(table->get_column_key("double array"), 3.3, 4.4);
-
-        r.set_property_value(ctx, "string array", util::Any(AnyVec{"a"s, "b"s, "c"s}));
-        check_array(table->get_column_key("string array"), StringData("a"), StringData("b"), StringData("c"));
- 
-        r.set_property_value(ctx, "data array", util::Any(AnyVec{"d"s, "e"s, "f"s}));
-        check_array(table->get_column_key("data array"), BinaryData("d",1), BinaryData("e",1), BinaryData("f",1));
-
-        r.set_property_value(ctx, "date array", util::Any(AnyVec{Timestamp(10,20), Timestamp(20,30), Timestamp(30,40)}));
-        check_array(table->get_column_key("date array"), Timestamp(10,20), Timestamp(20,30), Timestamp(30,40));
-    }
-}
-
-TEST_CASE("results: limit", "[limit]") {
-    InMemoryTestFile config;
-    // config.cache = false;
-    config.automatic_change_notifications = false;
-    config.schema = Schema{
-        {"object", {
-            {"value", PropertyType::Int},
-        }},
-    };
-
-    auto realm = Realm::get_shared_realm(config);
-    auto table = realm->read_group().get_table("class_object");
-    auto col = table->get_column_key("value");
-
-    realm->begin_transaction();
-    for (int i = 0; i < 8; ++i) {
-        table->create_object().set(col, (i + 2) % 4);
-    }
-    realm->commit_transaction();
-    Results r(realm, table);
-
-    SECTION("unsorted") {
-        REQUIRE(r.limit(0).size() == 0);
-        REQUIRE_ORDER(r.limit(1), 0);
-        REQUIRE_ORDER(r.limit(2), 0, 1);
-        REQUIRE_ORDER(r.limit(8), 0, 1, 2, 3, 4, 5, 6, 7);
-        REQUIRE_ORDER(r.limit(100), 0, 1, 2, 3, 4, 5, 6, 7);
-    }
-
-    SECTION("sorted") {
-        auto sorted = r.sort({{"value", true}});
-        REQUIRE(sorted.limit(0).size() == 0);
-        REQUIRE_ORDER(sorted.limit(1), 2);
-        REQUIRE_ORDER(sorted.limit(2), 2, 6);
-        REQUIRE_ORDER(sorted.limit(8), 2, 6, 3, 7, 0, 4, 1, 5);
-        REQUIRE_ORDER(sorted.limit(100), 2, 6, 3, 7, 0, 4, 1, 5);
-    }
-
-    SECTION("sort after limit") {
-        REQUIRE(r.limit(0).sort({{"value", true}}).size() == 0);
-        REQUIRE_ORDER(r.limit(1).sort({{"value", true}}), 0);
-        REQUIRE_ORDER(r.limit(3).sort({{"value", true}}), 2, 0, 1);
-        REQUIRE_ORDER(r.limit(8).sort({{"value", true}}), 2, 6, 3, 7, 0, 4, 1, 5);
-        REQUIRE_ORDER(r.limit(100).sort({{"value", true}}), 2, 6, 3, 7, 0, 4, 1, 5);
-    }
-
-    SECTION("distinct") {
-        auto sorted = r.distinct({"value"});
-        REQUIRE(sorted.limit(0).size() == 0);
-        REQUIRE_ORDER(sorted.limit(1), 0);
-        REQUIRE_ORDER(sorted.limit(2), 0, 1);
-        REQUIRE_ORDER(sorted.limit(8), 0, 1, 2, 3);
-
-        sorted = r.sort({{"value", true}}).distinct({"value"});
-        REQUIRE(sorted.limit(0).size() == 0);
-        REQUIRE_ORDER(sorted.limit(1), 2);
-        REQUIRE_ORDER(sorted.limit(2), 2, 3);
-        REQUIRE_ORDER(sorted.limit(8), 2, 3, 0, 1);
-    }
-
-    SECTION("notifications on results using all descriptor types") {
-        r = r.distinct({"value"}).sort({{"value", false}}).limit(2);
-        int notification_calls = 0;
-        auto token = r.add_notification_callback([&](CollectionChangeSet c, std::exception_ptr err) {
-            REQUIRE_FALSE(err);
-            if (notification_calls == 0) {
-                REQUIRE(c.empty());
-                REQUIRE(r.size() == 2);
-                REQUIRE(r.get(0).get<Int>(col) == 3);
-                REQUIRE(r.get(1).get<Int>(col) == 2);
-            } else if (notification_calls == 1) {
-                REQUIRE(!c.empty());
-                REQUIRE_INDICES(c.insertions, 0);
-                REQUIRE_INDICES(c.deletions, 1);
-                REQUIRE(c.moves.size() == 0);
-                REQUIRE(c.modifications.count() == 0);
-                REQUIRE(r.size() == 2);
-                REQUIRE(r.get(0).get<Int>(col) == 5);
-                REQUIRE(r.get(1).get<Int>(col) == 3);
-            }
-            ++notification_calls;
-        });
-        advance_and_notify(*realm);
-        REQUIRE(notification_calls == 1);
-        realm->begin_transaction();
-        table->create_object().set(col, 5);
-        realm->commit_transaction();
-        advance_and_notify(*realm);
-        REQUIRE(notification_calls == 2);
-    }
-
-    SECTION("notifications on only limited results") {
-        r = r.limit(2);
-        int notification_calls = 0;
-        auto token = r.add_notification_callback([&](CollectionChangeSet c, std::exception_ptr err) {
-            REQUIRE_FALSE(err);
-            if (notification_calls == 0) {
-                REQUIRE(c.empty());
-                REQUIRE(r.size() == 2);
-            } else if (notification_calls == 1) {
-                REQUIRE(!c.empty());
-                REQUIRE(c.insertions.count() == 0);
-                REQUIRE(c.deletions.count() == 0);
-                REQUIRE(c.modifications.count() == 1);
-                REQUIRE_INDICES(c.modifications, 1);
-                REQUIRE(r.size() == 2);
-            }
-            ++notification_calls;
-        });
-        advance_and_notify(*realm);
-        REQUIRE(notification_calls == 1);
-        realm->begin_transaction();
-        table->get_object(1).set(col, 5);
-        realm->commit_transaction();
-        advance_and_notify(*realm);
-        REQUIRE(notification_calls == 2);
-    }
-
-    SECTION("does not support further filtering") {
-        auto limited = r.limit(0);
-        REQUIRE_THROWS_AS(limited.filter(table->where()), Results::UnimplementedOperationException);
-    }
-}

+ 0 - 811
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/schema.cpp

@@ -1,811 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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 "catch2/catch.hpp"
-#include "util/test_file.hpp"
-
-#include "object_schema.hpp"
-#include "object_store.hpp"
-#include "property.hpp"
-#include "schema.hpp"
-
-#include <realm/group.hpp>
-#include <realm/table.hpp>
-
-using namespace realm;
-
-struct SchemaChangePrinter {
-    std::ostream& out;
-
-    template<typename Value>
-    void print(Value value) const
-    {
-        out << value;
-    }
-
-    template<typename Value, typename... Rest>
-    void print(Value value, Rest... rest) const
-    {
-        out << value << ", ";
-        print(rest...);
-    }
-
-#define REALM_SC_PRINT(type, ...) \
-    void operator()(schema_change::type v) const \
-    { \
-        out << #type << "{"; \
-        print(__VA_ARGS__); \
-        out << "}"; \
-    }
-
-    REALM_SC_PRINT(AddIndex, v.object, v.property)
-    REALM_SC_PRINT(AddProperty, v.object, v.property)
-    REALM_SC_PRINT(AddTable, v.object)
-    REALM_SC_PRINT(RemoveTable, v.object)
-    REALM_SC_PRINT(AddInitialProperties, v.object)
-    REALM_SC_PRINT(ChangePrimaryKey, v.object, v.property)
-    REALM_SC_PRINT(ChangePropertyType, v.object, v.old_property, v.new_property)
-    REALM_SC_PRINT(MakePropertyNullable, v.object, v.property)
-    REALM_SC_PRINT(MakePropertyRequired, v.object, v.property)
-    REALM_SC_PRINT(RemoveIndex, v.object, v.property)
-    REALM_SC_PRINT(RemoveProperty, v.object, v.property)
-
-#undef REALM_SC_PRINT
-};
-
-namespace Catch {
-template<>
-struct StringMaker<SchemaChange> {
-    static std::string convert(SchemaChange const& sc)
-    {
-        std::stringstream ss;
-        sc.visit(SchemaChangePrinter{ss});
-        return ss.str();
-    }
-};
-} // namespace Catch
-
-#define REQUIRE_THROWS_CONTAINING(expr, msg) \
-    REQUIRE_THROWS_WITH(expr, Catch::Matchers::Contains(msg))
-
-TEST_CASE("ObjectSchema") {
-
-    SECTION("Aliases are still present in schema returned from the Realm") {
-        TestFile config;
-        config.schema_version = 1;
-        config.schema = Schema{
-                {"object", {
-                   {"value", PropertyType::Int, Property::IsPrimary{false}, Property::IsIndexed{false}, "alias"}
-               }},
-        };
-
-        auto realm = Realm::get_shared_realm(config);
-        REQUIRE(realm->schema().find("object")->property_for_name("value")->public_name == "alias");
-    }
-
-    SECTION("looking up properties by alias matches name if alias is not set") {
-        auto schema = Schema{
-            {"object", {
-               {"value", PropertyType::Int, Property::IsPrimary{false}, Property::IsIndexed{false}, "alias"},
-               {"other_value", PropertyType::Int, Property::IsPrimary{false}, Property::IsIndexed{false}}
-            }},
-        };
-
-        REQUIRE(schema.find("object")->property_for_public_name("value") == nullptr);
-        REQUIRE(schema.find("object")->property_for_public_name("alias")->name == "value");
-        REQUIRE(schema.find("object")->property_for_public_name("other_value")->name == "other_value");
-    }
-
-    SECTION("from a Group") {
-        Group g;
-
-        TableRef table = g.add_table_with_primary_key("class_table", type_Int, "pk");
-        TableRef target = g.add_table("class_target");
-
-        table->add_column(type_Int, "int");
-        table->add_column(type_Bool, "bool");
-        table->add_column(type_Float, "float");
-        table->add_column(type_Double, "double");
-        table->add_column(type_String, "string");
-        table->add_column(type_Binary, "data");
-        table->add_column(type_Timestamp, "date");
-
-        table->add_column_link(type_Link, "object", *target);
-        table->add_column_link(type_LinkList, "array", *target);
-
-        table->add_column(type_Int, "int?", true);
-        table->add_column(type_Bool, "bool?", true);
-        table->add_column(type_Float, "float?", true);
-        table->add_column(type_Double, "double?", true);
-        table->add_column(type_String, "string?", true);
-        table->add_column(type_Binary, "data?", true);
-        table->add_column(type_Timestamp, "date?", true);
-
-        auto add_list = [](TableRef table, DataType type, StringData name, bool nullable) {
-            table->add_column_list(type, name, nullable);
-        };
-
-        add_list(table, type_Int, "int array", false);
-        add_list(table, type_Bool, "bool array", false);
-        add_list(table, type_Float, "float array", false);
-        add_list(table, type_Double, "double array", false);
-        add_list(table, type_String, "string array", false);
-        add_list(table, type_Binary, "data array", false);
-        add_list(table, type_Timestamp, "date array", false);
-        add_list(table, type_Int, "int? array", true);
-        add_list(table, type_Bool, "bool? array", true);
-        add_list(table, type_Float, "float? array", true);
-        add_list(table, type_Double, "double? array", true);
-        add_list(table, type_String, "string? array", true);
-        add_list(table, type_Binary, "data? array", true);
-        add_list(table, type_Timestamp, "date? array", true);
-
-        std::vector<ColKey> indexed_cols;
-        indexed_cols.push_back(table->add_column(type_Int, "indexed int"));
-        indexed_cols.push_back(table->add_column(type_Bool, "indexed bool"));
-        indexed_cols.push_back(table->add_column(type_String, "indexed string"));
-        indexed_cols.push_back(table->add_column(type_Timestamp, "indexed date"));
-
-        indexed_cols.push_back(table->add_column(type_Int, "indexed int?", true));
-        indexed_cols.push_back(table->add_column(type_Bool, "indexed bool?", true));
-        indexed_cols.push_back(table->add_column(type_String, "indexed string?", true));
-        indexed_cols.push_back(table->add_column(type_Timestamp, "indexed date?", true));
-
-        for (auto col : indexed_cols)
-            table->add_search_index(col);
-
-        ObjectSchema os(g, "table", table->get_key());
-        REQUIRE(os.table_key == table->get_key());
-
-#define REQUIRE_PROPERTY(name, type, ...) do { \
-    Property* prop; \
-    REQUIRE((prop = os.property_for_name(name))); \
-    REQUIRE((*prop == Property{name, PropertyType::type, __VA_ARGS__})); \
-    REQUIRE(prop->column_key == *expected_col++); \
-} while (0)
-
-        auto all_column_keys = table->get_column_keys();
-        auto expected_col = all_column_keys.begin();
-
-        REQUIRE(os.property_for_name("nonexistent property") == nullptr);
-
-        REQUIRE_PROPERTY("pk", Int, Property::IsPrimary{true});
-
-        REQUIRE_PROPERTY("int", Int);
-        REQUIRE_PROPERTY("bool", Bool);
-        REQUIRE_PROPERTY("float", Float);
-        REQUIRE_PROPERTY("double", Double);
-        REQUIRE_PROPERTY("string", String);
-        REQUIRE_PROPERTY("data", Data);
-        REQUIRE_PROPERTY("date", Date);
-
-        REQUIRE_PROPERTY("object", Object|PropertyType::Nullable, "target");
-        REQUIRE_PROPERTY("array", Array|PropertyType::Object, "target");
-
-        REQUIRE_PROPERTY("int?", Int|PropertyType::Nullable);
-        REQUIRE_PROPERTY("bool?", Bool|PropertyType::Nullable);
-        REQUIRE_PROPERTY("float?", Float|PropertyType::Nullable);
-        REQUIRE_PROPERTY("double?", Double|PropertyType::Nullable);
-        REQUIRE_PROPERTY("string?", String|PropertyType::Nullable);
-        REQUIRE_PROPERTY("data?", Data|PropertyType::Nullable);
-        REQUIRE_PROPERTY("date?", Date|PropertyType::Nullable);
-
-        REQUIRE_PROPERTY("int array", Int|PropertyType::Array);
-        REQUIRE_PROPERTY("bool array", Bool|PropertyType::Array);
-        REQUIRE_PROPERTY("float array", Float|PropertyType::Array);
-        REQUIRE_PROPERTY("double array", Double|PropertyType::Array);
-        REQUIRE_PROPERTY("string array", String|PropertyType::Array);
-        REQUIRE_PROPERTY("data array", Data|PropertyType::Array);
-        REQUIRE_PROPERTY("date array", Date|PropertyType::Array);
-        REQUIRE_PROPERTY("int? array", Int|PropertyType::Array|PropertyType::Nullable);
-        REQUIRE_PROPERTY("bool? array", Bool|PropertyType::Array|PropertyType::Nullable);
-        REQUIRE_PROPERTY("float? array", Float|PropertyType::Array|PropertyType::Nullable);
-        REQUIRE_PROPERTY("double? array", Double|PropertyType::Array|PropertyType::Nullable);
-        REQUIRE_PROPERTY("string? array", String|PropertyType::Array|PropertyType::Nullable);
-        REQUIRE_PROPERTY("data? array", Data|PropertyType::Array|PropertyType::Nullable);
-        REQUIRE_PROPERTY("date? array", Date|PropertyType::Array|PropertyType::Nullable);
-
-        REQUIRE_PROPERTY("indexed int", Int, Property::IsPrimary{false}, Property::IsIndexed{true});
-        REQUIRE_PROPERTY("indexed bool", Bool, Property::IsPrimary{false}, Property::IsIndexed{true});
-        REQUIRE_PROPERTY("indexed string", String, Property::IsPrimary{false}, Property::IsIndexed{true});
-        REQUIRE_PROPERTY("indexed date", Date, Property::IsPrimary{false}, Property::IsIndexed{true});
-
-        REQUIRE_PROPERTY("indexed int?", Int|PropertyType::Nullable, Property::IsPrimary{false}, Property::IsIndexed{true});
-        REQUIRE_PROPERTY("indexed bool?", Bool|PropertyType::Nullable, Property::IsPrimary{false}, Property::IsIndexed{true});
-        REQUIRE_PROPERTY("indexed string?", String|PropertyType::Nullable, Property::IsPrimary{false}, Property::IsIndexed{true});
-        REQUIRE_PROPERTY("indexed date?", Date|PropertyType::Nullable, Property::IsPrimary{false}, Property::IsIndexed{true});
-    }
-}
-
-TEST_CASE("Schema") {
-    SECTION("validate()") {
-        SECTION("rejects link properties with no target object") {
-            Schema schema = {
-                {"object", {
-                    {"link", PropertyType::Object|PropertyType::Nullable}
-                }},
-            };
-            REQUIRE_THROWS_CONTAINING(schema.validate(), "Property 'object.link' of type 'object' has unknown object type ''");
-        }
-
-        SECTION("rejects array properties with no target object") {
-            Schema schema = {
-                {"object", {
-                    {"array", PropertyType::Array|PropertyType::Object}
-                }},
-            };
-            REQUIRE_THROWS_CONTAINING(schema.validate(), "Property 'object.array' of type 'array' has unknown object type ''");
-        }
-
-        SECTION("rejects link properties with a target not in the schema") {
-            Schema schema = {
-                {"object", {
-                    {"link", PropertyType::Object|PropertyType::Nullable, "invalid target"}
-                }}
-            };
-            REQUIRE_THROWS_CONTAINING(schema.validate(), "Property 'object.link' of type 'object' has unknown object type 'invalid target'");
-        }
-
-        SECTION("rejects array properties with a target not in the schema") {
-            Schema schema = {
-                {"object", {
-                    {"array", PropertyType::Array|PropertyType::Object, "invalid target"}
-                }}
-            };
-            REQUIRE_THROWS_CONTAINING(schema.validate(), "Property 'object.array' of type 'array' has unknown object type 'invalid target'");
-        }
-
-        SECTION("rejects linking objects without a source object") {
-            Schema schema = {
-                {"object", {
-                    {"value", PropertyType::Int},
-                }, {
-                    {"incoming", PropertyType::Array|PropertyType::LinkingObjects, "", ""}
-                }}
-            };
-            REQUIRE_THROWS_CONTAINING(schema.validate(), "Property 'object.incoming' of type 'linking objects' has unknown object type ''");
-        }
-
-        SECTION("rejects linking objects without a source property") {
-            Schema schema = {
-                {"object", {
-                    {"value", PropertyType::Int},
-                }, {
-                    {"incoming", PropertyType::Array|PropertyType::LinkingObjects, "object", ""}
-                }}
-            };
-            REQUIRE_THROWS_CONTAINING(schema.validate(), "Property 'object.incoming' of type 'linking objects' must have an origin property name.");
-        }
-
-        SECTION("rejects linking objects with invalid source object") {
-            Schema schema = {
-                {"object", {
-                    {"value", PropertyType::Int},
-                }, {
-                    {"incoming", PropertyType::Array|PropertyType::LinkingObjects, "not an object type", ""}
-                }}
-            };
-            REQUIRE_THROWS_CONTAINING(schema.validate(), "Property 'object.incoming' of type 'linking objects' has unknown object type 'not an object type'");
-        }
-
-        SECTION("rejects linking objects with invalid source property") {
-            Schema schema = {
-                {"object", {
-                    {"value", PropertyType::Int},
-                }, {
-                    {"incoming", PropertyType::Array|PropertyType::LinkingObjects, "object", "value"}
-                }}
-            };
-            REQUIRE_THROWS_CONTAINING(schema.validate(), "Property 'object.value' declared as origin of linking objects property 'object.incoming' is not a link");
-
-            schema = {
-                {"object", {
-                    {"value", PropertyType::Int},
-                    {"link", PropertyType::Object|PropertyType::Nullable, "object 2"},
-                }, {
-                    {"incoming", PropertyType::Array|PropertyType::LinkingObjects, "object", "link"}
-                }},
-                {"object 2", {
-                    {"value", PropertyType::Int},
-                }}
-            };
-            REQUIRE_THROWS_CONTAINING(schema.validate(), "Property 'object.link' declared as origin of linking objects property 'object.incoming' links to type 'object 2'");
-
-        }
-
-        SECTION("rejects non-array linking objects") {
-            Schema schema = {
-                {"object", {
-                    {"link", PropertyType::Object|PropertyType::Nullable, "object"},
-                }, {
-                    {"incoming", PropertyType::LinkingObjects, "object", "link"}
-                }}
-            };
-            REQUIRE_THROWS_CONTAINING(schema.validate(), "Linking Objects property 'object.incoming' must be an array.");
-        }
-
-        SECTION("rejects target object types for non-link properties") {
-            Schema schema = {
-                {"object", {
-                    {"int", PropertyType::Int},
-                    {"bool", PropertyType::Bool},
-                    {"float", PropertyType::Float},
-                    {"double", PropertyType::Double},
-                    {"string", PropertyType::String},
-                    {"date", PropertyType::Date},
-                }}
-            };
-            for (auto& prop : schema.begin()->persisted_properties) {
-                REQUIRE_NOTHROW(schema.validate());
-                prop.object_type = "object";
-                REQUIRE_THROWS_CONTAINING(schema.validate(), "cannot have an object type.");
-                prop.object_type = "";
-            }
-        }
-
-        SECTION("rejects source property name for non-linking objects properties") {
-            Schema schema = {
-                {"object", {
-                    {"int", PropertyType::Int},
-                    {"bool", PropertyType::Bool},
-                    {"float", PropertyType::Float},
-                    {"double", PropertyType::Double},
-                    {"string", PropertyType::String},
-                    {"data", PropertyType::Data},
-                    {"date", PropertyType::Date},
-                    {"object", PropertyType::Object|PropertyType::Nullable, "object"},
-                    {"array", PropertyType::Object|PropertyType::Array, "object"},
-                }}
-            };
-            for (auto& prop : schema.begin()->persisted_properties) {
-                REQUIRE_NOTHROW(schema.validate());
-                prop.link_origin_property_name = "source";
-                auto expected = util::format("Property 'object.%1' of type '%1' cannot have an origin property name.", prop.name, prop.name);
-                REQUIRE_THROWS_CONTAINING(schema.validate(), expected);
-                prop.link_origin_property_name = "";
-            }
-        }
-
-        SECTION("rejects non-nullable link properties") {
-            Schema schema = {
-                {"object", {
-                    {"link", PropertyType::Object, "target"}
-                }},
-                {"target", {
-                    {"value", PropertyType::Int}
-                }}
-            };
-            REQUIRE_THROWS_CONTAINING(schema.validate(), "Property 'object.link' of type 'object' must be nullable.");
-        }
-
-        SECTION("rejects nullable array properties") {
-            Schema schema = {
-                {"object", {
-                    {"array", PropertyType::Array|PropertyType::Object|PropertyType::Nullable, "target"}
-                }},
-                {"target", {
-                    {"value", PropertyType::Int}
-                }}
-            };
-            REQUIRE_THROWS_CONTAINING(schema.validate(), "Property 'object.array' of type 'array' cannot be nullable.");
-        }
-
-        SECTION("rejects nullable linking objects") {
-            Schema schema = {
-                {"object", {
-                    {"link", PropertyType::Object|PropertyType::Nullable, "object"},
-                }, {
-                    {"incoming", PropertyType::LinkingObjects|PropertyType::Array|PropertyType::Nullable, "object", "link"}
-                }}
-            };
-            REQUIRE_THROWS_CONTAINING(schema.validate(), "Property 'object.incoming' of type 'linking objects' cannot be nullable.");
-        }
-
-        SECTION("rejects duplicate primary keys") {
-            Schema schema = {
-                {"object", {
-                    {"pk1", PropertyType::Int, Property::IsPrimary{true}},
-                    {"pk2", PropertyType::Int, Property::IsPrimary{true}},
-                }}
-            };
-            REQUIRE_THROWS_CONTAINING(schema.validate(), "Properties 'pk2' and 'pk1' are both marked as the primary key of 'object'.");
-        }
-
-        SECTION("rejects invalid primary key types") {
-            Schema schema = {
-                {"object", {
-                    {"pk", PropertyType::Float, Property::IsPrimary{true}},
-                }}
-            };
-
-            schema.begin()->primary_key_property()->type = PropertyType::Any;
-            REQUIRE_THROWS_CONTAINING(schema.validate(), "Property 'object.pk' of type 'any' cannot be made the primary key.");
-
-            schema.begin()->primary_key_property()->type = PropertyType::Bool;
-            REQUIRE_THROWS_CONTAINING(schema.validate(), "Property 'object.pk' of type 'bool' cannot be made the primary key.");
-
-            schema.begin()->primary_key_property()->type = PropertyType::Float;
-            REQUIRE_THROWS_CONTAINING(schema.validate(), "Property 'object.pk' of type 'float' cannot be made the primary key.");
-
-            schema.begin()->primary_key_property()->type = PropertyType::Double;
-            REQUIRE_THROWS_CONTAINING(schema.validate(), "Property 'object.pk' of type 'double' cannot be made the primary key.");
-
-            schema.begin()->primary_key_property()->type = PropertyType::Object;
-            REQUIRE_THROWS_CONTAINING(schema.validate(), "Property 'object.pk' of type 'object' cannot be made the primary key.");
-
-            schema.begin()->primary_key_property()->type = PropertyType::LinkingObjects;
-            REQUIRE_THROWS_CONTAINING(schema.validate(), "Property 'object.pk' of type 'linking objects' cannot be made the primary key.");
-
-            schema.begin()->primary_key_property()->type = PropertyType::Data;
-            REQUIRE_THROWS_CONTAINING(schema.validate(), "Property 'object.pk' of type 'data' cannot be made the primary key.");
-
-            schema.begin()->primary_key_property()->type = PropertyType::Date;
-            REQUIRE_THROWS_CONTAINING(schema.validate(), "Property 'object.pk' of type 'date' cannot be made the primary key.");
-        }
-
-        SECTION("allows valid primary key types") {
-            Schema schema = {
-                {"object", {
-                    {"pk", PropertyType::Int, Property::IsPrimary{true}},
-                }}
-            };
-
-            REQUIRE_NOTHROW(schema.validate());
-
-            schema.begin()->primary_key_property()->type = PropertyType::Int|PropertyType::Nullable;
-            REQUIRE_NOTHROW(schema.validate());
-            schema.begin()->primary_key_property()->type = PropertyType::String;
-            REQUIRE_NOTHROW(schema.validate());
-            schema.begin()->primary_key_property()->type = PropertyType::String|PropertyType::Nullable;
-            REQUIRE_NOTHROW(schema.validate());
-        }
-
-        SECTION("rejects nonexistent primary key") {
-            Schema schema = {
-                {"object", {
-                    {"value", PropertyType::Int},
-                }}
-            };
-            schema.begin()->primary_key = "nonexistent";
-            REQUIRE_THROWS_CONTAINING(schema.validate(), "Specified primary key 'object.nonexistent' does not exist.");
-        }
-
-        SECTION("rejects indexes for types that cannot be indexed") {
-            Schema schema = {
-                {"object", {
-                    {"float", PropertyType::Float},
-                    {"double", PropertyType::Double},
-                    {"data", PropertyType::Data},
-                    {"object", PropertyType::Object|PropertyType::Nullable, "object"},
-                    {"array", PropertyType::Array|PropertyType::Object, "object"},
-                }}
-            };
-            for (auto& prop : schema.begin()->persisted_properties) {
-                REQUIRE_NOTHROW(schema.validate());
-                prop.is_indexed = true;
-                auto expected = util::format("Property 'object.%1' of type '%1' cannot be indexed.", prop.name);
-                REQUIRE_THROWS_CONTAINING(schema.validate(), expected);
-                prop.is_indexed = false;
-            }
-        }
-
-        SECTION("allows indexing types that can be indexed") {
-            Schema schema = {
-                {"object", {
-                    {"int", PropertyType::Int, Property::IsPrimary{false}, Property::IsIndexed{true}},
-                    {"bool", PropertyType::Bool, Property::IsPrimary{false}, Property::IsIndexed{true}},
-                    {"string", PropertyType::String, Property::IsPrimary{false}, Property::IsIndexed{true}},
-                    {"date", PropertyType::Date, Property::IsPrimary{false}, Property::IsIndexed{true}},
-                }}
-            };
-            REQUIRE_NOTHROW(schema.validate());
-        }
-
-        SECTION("rejects duplicate types with the same name") {
-            Schema schema = {
-                {"object1", {
-                    {"int", PropertyType::Int},
-                }},
-                {"object2", {
-                    {"int", PropertyType::Int},
-                }},
-                {"object3", {
-                    {"int", PropertyType::Int},
-                }},
-                {"object2", {
-                    {"int", PropertyType::Int},
-                }},
-                {"object1", {
-                    {"int", PropertyType::Int},
-                }}
-            };
-
-            REQUIRE_THROWS_CONTAINING(schema.validate(),
-                "- Type 'object1' appears more than once in the schema.\n"
-                "- Type 'object2' appears more than once in the schema.");
-        }
-
-        SECTION("rejects properties with the same name") {
-            Schema schema = {
-                {"object", {
-                    {"child", PropertyType::Object|PropertyType::Nullable, "object"},
-                    {"parent", PropertyType::Int},
-                    {"field1", PropertyType::Int},
-                    {"field2", PropertyType::String},
-                    {"field1", PropertyType::String},
-                    {"field2", PropertyType::String},
-                    {"field1", PropertyType::Int},
-                }, {
-                    {"parent", PropertyType::Array|PropertyType::LinkingObjects, "object", "child"}
-                }}
-            };
-
-            REQUIRE_THROWS_CONTAINING(schema.validate(),
-                  "- Property 'field1' appears more than once in the schema for type 'object'.\n"
-                  "- Property 'field2' appears more than once in the schema for type 'object'.\n"
-                  "- Property 'parent' appears more than once in the schema for type 'object'.");
-        }
-
-        SECTION("rejects schema if all properties have the same name") {
-            Schema schema = {
-                {"object", {
-                    {"field", PropertyType::Int},
-                    {"otherField", PropertyType::Int},
-                    {"field", PropertyType::Int},
-                    {"otherField", PropertyType::Int},
-                    {"field", PropertyType::Int},
-                    {"otherField", PropertyType::Int},
-                    {"field", PropertyType::Int},
-                    {"otherField", PropertyType::Int},
-                    {"field", PropertyType::Int},
-                    {"otherField", PropertyType::Int},
-                }}
-            };
-
-            REQUIRE_THROWS_CONTAINING(schema.validate(),
-                    "- Property 'field' appears more than once in the schema for type 'object'.\n"
-                    "- Property 'otherField' appears more than once in the schema for type 'object'.");
-        }
-
-        SECTION("rejects properties with the same alias") {
-            Schema schema = {
-                {"object", {
-                    {"child", PropertyType::Object|PropertyType::Nullable, "object"},
-
-                    // Alias == Name on computed property
-                    {"parentA", PropertyType::Int, Property::IsPrimary{false}, Property::IsIndexed{false}, "_parent"},
-
-                    // Name == Alias on other property
-                    {"fieldA", PropertyType::Int, Property::IsPrimary{false}, Property::IsIndexed{false}, "_field1"},
-                    {"fieldB", PropertyType::String, Property::IsPrimary{false}, Property::IsIndexed{false}, "_field2"},
-                    {"fieldC", PropertyType::String, Property::IsPrimary{false}, Property::IsIndexed{false}, "_field1"},
-                    {"fieldD", PropertyType::String, Property::IsPrimary{false}, Property::IsIndexed{false}, "_field2"},
-                    {"fieldE", PropertyType::Int, Property::IsPrimary{false}, Property::IsIndexed{false}, "_field1"},
-
-                    // Name == Alias
-                    {"fieldF", PropertyType::Int, Property::IsPrimary{false}, Property::IsIndexed{false}, "fieldF"},
-                }, {
-                    // Computed property alias == name on persisted property
-                    {"parentB", PropertyType::Array|PropertyType::LinkingObjects, "object", "child", "_parent"}
-                }}
-            };
-
-            REQUIRE_THROWS_CONTAINING(schema.validate(),
-                  "- Alias '_field1' appears more than once in the schema for type 'object'.\n"
-                  "- Alias '_field2' appears more than once in the schema for type 'object'.\n"
-                  "- Alias '_parent' appears more than once in the schema for type 'object'.");
-        }
-
-        SECTION("rejects properties whose name conflicts with an alias for another property") {
-            Schema schema = {
-                {"object", {
-                    {"child", PropertyType::Object|PropertyType::Nullable, "object"},
-                    {"field1", PropertyType::Int, Property::IsPrimary{false}, Property::IsIndexed{false}, "field2"},
-                    {"field2", PropertyType::Int, Property::IsPrimary{false}, Property::IsIndexed{false}, "parent"},
-                }, {
-                    {"parent", PropertyType::Array|PropertyType::LinkingObjects, "object", "child", "field1"}
-                }}
-            };
-
-            REQUIRE_THROWS_CONTAINING(schema.validate(),
-                  "- Property 'object.parent' has an alias 'field1' that conflicts with a property of the same name.\n"
-                  "- Property 'object.field1' has an alias 'field2' that conflicts with a property of the same name.\n"
-                  "- Property 'object.field2' has an alias 'parent' that conflicts with a property of the same name.");
-        }
-    }
-
-    SECTION("compare()") {
-        using namespace schema_change;
-        using vec = std::vector<SchemaChange>;
-        SECTION("add table") {
-            Schema schema1 = {
-                {"object 1", {
-                    {"int", PropertyType::Int},
-                }}
-            };
-            Schema schema2 = {
-                {"object 1", {
-                    {"int", PropertyType::Int},
-                }},
-                {"object 2", {
-                    {"int", PropertyType::Int},
-                }}
-            };
-            auto obj = &*schema2.find("object 2");
-            auto expected = vec{AddTable{obj}, AddInitialProperties{obj}};
-            REQUIRE(schema1.compare(schema2) == expected);
-        }
-
-        SECTION("add property") {
-            Schema schema1 = {
-                {"object", {
-                    {"int 1", PropertyType::Int},
-                }}
-            };
-            Schema schema2 = {
-                {"object", {
-                    {"int 1", PropertyType::Int},
-                    {"int 2", PropertyType::Int},
-                }}
-            };
-            REQUIRE(schema1.compare(schema2) == vec{(AddProperty{&*schema1.find("object"), &schema2.find("object")->persisted_properties[1]})});
-        }
-
-        SECTION("remove property") {
-            Schema schema1 = {
-                {"object", {
-                    {"int 1", PropertyType::Int},
-                    {"int 2", PropertyType::Int},
-                }}
-            };
-            Schema schema2 = {
-                {"object", {
-                    {"int 1", PropertyType::Int},
-                }}
-            };
-            REQUIRE(schema1.compare(schema2) == vec{(RemoveProperty{&*schema1.find("object"), &schema1.find("object")->persisted_properties[1]})});
-        }
-
-        SECTION("change property type") {
-            Schema schema1 = {
-                {"object", {
-                    {"value", PropertyType::Int},
-                }}
-            };
-            Schema schema2 = {
-                {"object", {
-                    {"value", PropertyType::Double},
-                }}
-            };
-            REQUIRE(schema1.compare(schema2) == vec{(ChangePropertyType{
-                &*schema1.find("object"),
-                &schema1.find("object")->persisted_properties[0],
-                &schema2.find("object")->persisted_properties[0]})});
-        };
-
-        SECTION("change link target") {
-            Schema schema1 = {
-                {"object", {
-                    {"value", PropertyType::Object, "target 1"},
-                }},
-                {"target 1", {
-                    {"value", PropertyType::Int},
-                }},
-                {"target 2", {
-                    {"value", PropertyType::Int},
-                }},
-            };
-            Schema schema2 = {
-                {"object", {
-                    {"value", PropertyType::Object, "target 2"},
-                }},
-                {"target 1", {
-                    {"value", PropertyType::Int},
-                }},
-                {"target 2", {
-                    {"value", PropertyType::Int},
-                }},
-            };
-            REQUIRE(schema1.compare(schema2) == vec{(ChangePropertyType{
-                &*schema1.find("object"),
-                &schema1.find("object")->persisted_properties[0],
-                &schema2.find("object")->persisted_properties[0]})});
-        }
-
-        SECTION("add index") {
-            Schema schema1 = {
-                {"object", {
-                    {"int", PropertyType::Int},
-                }}
-            };
-            Schema schema2 = {
-                {"object", {
-                    {"int", PropertyType::Int, Property::IsPrimary{false}, Property::IsIndexed{true}},
-                }}
-            };
-            auto object_schema = &*schema1.find("object");
-            REQUIRE(schema1.compare(schema2) == vec{(AddIndex{object_schema, &object_schema->persisted_properties[0]})});
-        }
-
-        SECTION("remove index") {
-            Schema schema1 = {
-                {"object", {
-                    {"int", PropertyType::Int, Property::IsPrimary{false}, Property::IsIndexed{true}},
-                }}
-            };
-            Schema schema2 = {
-                {"object", {
-                    {"int", PropertyType::Int},
-                }}
-            };
-            auto object_schema = &*schema1.find("object");
-            REQUIRE(schema1.compare(schema2) == vec{(RemoveIndex{object_schema, &object_schema->persisted_properties[0]})});
-        }
-
-        SECTION("add index and make nullable") {
-            Schema schema1 = {
-                {"object", {
-                    {"int", PropertyType::Int},
-                }}
-            };
-            Schema schema2 = {
-                {"object", {
-                    {"int", PropertyType::Int|PropertyType::Nullable, Property::IsPrimary{false}, Property::IsIndexed{true}},
-                }}
-            };
-            auto object_schema = &*schema1.find("object");
-            REQUIRE(schema1.compare(schema2) == (vec{
-                MakePropertyNullable{object_schema, &object_schema->persisted_properties[0]},
-                AddIndex{object_schema, &object_schema->persisted_properties[0]}}));
-        }
-
-        SECTION("add index and change type") {
-            Schema schema1 = {
-                {"object", {
-                    {"value", PropertyType::Int},
-                }}
-            };
-            Schema schema2 = {
-                {"object", {
-                    {"value", PropertyType::Double, Property::IsPrimary{false}, Property::IsIndexed{true}},
-                }}
-            };
-            REQUIRE(schema1.compare(schema2) == vec{(ChangePropertyType{
-                &*schema1.find("object"),
-                &schema1.find("object")->persisted_properties[0],
-                &schema2.find("object")->persisted_properties[0]})});
-        }
-
-        SECTION("make nullable and change type") {
-            Schema schema1 = {
-                {"object", {
-                    {"value", PropertyType::Int},
-                }}
-            };
-            Schema schema2 = {
-                {"object", {
-                    {"value", PropertyType::Double|PropertyType::Nullable},
-                }}
-            };
-            REQUIRE(schema1.compare(schema2) == vec{(ChangePropertyType{
-                &*schema1.find("object"),
-                &schema1.find("object")->persisted_properties[0],
-                &schema2.find("object")->persisted_properties[0]})});
-        }
-    }
-}

+ 0 - 896
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/thread_safe_reference.cpp

@@ -1,896 +0,0 @@
-////////////////////////////////////////////////////////////////////////////
-//
-// 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 "catch2/catch.hpp"
-
-#include "util/test_file.hpp"
-#include "util/test_utils.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 "impl/object_accessor_impl.hpp"
-#include "impl/realm_coordinator.hpp"
-
-#include <realm/db.hpp>
-#include <realm/history.hpp>
-#include <realm/string_data.hpp>
-#include <realm/util/optional.hpp>
-
-using namespace realm;
-
-static TableRef get_table(Realm& realm, StringData object_name) {
-    return ObjectStore::table_for_object_type(realm.read_group(), object_name);
-}
-
-static Object create_object(SharedRealm const& realm, StringData object_type, AnyDict value) {
-    CppContext ctx(realm);
-    return Object::create(ctx, realm, object_type, util::Any(value));
-}
-
-TEST_CASE("thread safe reference") {
-    using namespace std::string_literals;
-
-    Schema schema{
-        {"foo object", {
-            {"ignore me", PropertyType::Int}, // Used in tests cases that don't care about the value.
-        }},
-        {"string object", {
-            {"value", PropertyType::String|PropertyType::Nullable},
-        }},
-        {"int object", {
-            {"value", PropertyType::Int},
-        }},
-        {"int array object", {
-            {"value", PropertyType::Array|PropertyType::Object, "int object"}
-        }},
-        {"int array", {
-            {"value", PropertyType::Array|PropertyType::Int}
-        }},
-    };
-
-    InMemoryTestFile config;
-    config.automatic_change_notifications = false;
-    SharedRealm r = Realm::get_shared_realm(config);
-    r->update_schema(schema);
-
-    // Convenience object
-    r->begin_transaction();
-    auto foo = create_object(r, "foo object", {{"ignore me", INT64_C(0)}});
-    r->commit_transaction();
-
-    const auto int_obj_col = r->schema().find("int object")->persisted_properties[0].column_key;
-
-    SECTION("allowed during write transactions") {
-        SECTION("obtain") {
-            r->begin_transaction();
-            REQUIRE_NOTHROW(ThreadSafeReference(foo));
-        }
-        SECTION("resolve") {
-            auto ref = ThreadSafeReference(foo);
-            r->begin_transaction();
-            REQUIRE_NOTHROW(ref.resolve<Object>(r));
-        }
-    }
-
-    SECTION("cleanup properly unpins version") {
-        auto history = make_in_realm_history(config.path);
-        auto shared_group = DB::create(*history, config.options());
-
-        auto get_current_version = [&]() -> VersionID {
-            auto rt = shared_group->start_read();
-            auto version = rt->get_version_of_current_transaction();
-            return version;
-        };
-
-        auto reference_version = get_current_version();
-        auto ref = util::make_optional(ThreadSafeReference(foo));
-        r->begin_transaction(); r->commit_transaction(); // Advance version
-
-        REQUIRE(get_current_version() != reference_version); // Ensure advanced
-        REQUIRE_NOTHROW(shared_group->start_read(reference_version)); // Ensure pinned
-
-        ref = {}; // Destroy thread safe reference, unpinning version
-        r->begin_transaction(); r->commit_transaction(); // Clean up old versions
-        REQUIRE_THROWS(shared_group->start_read(reference_version)); // Verify unpinned
-    }
-
-    SECTION("version mismatch") {
-        SECTION("resolves at older version") {
-            r->begin_transaction();
-            Object num = create_object(r, "int object", {{"value", INT64_C(7)}});
-            r->commit_transaction();
-
-            ColKey col = num.get_object_schema().property_for_name("value")->column_key;
-            ObjKey k = num.obj().get_key();
-
-            REQUIRE(num.obj().get<Int>(col) == 7);
-            ThreadSafeReference ref;
-            {
-                SharedRealm r2 = Realm::get_shared_realm(config);
-                Object num = Object(r2, "int object", k);
-                REQUIRE(num.obj().get<Int>(col) == 7);
-
-                r2->begin_transaction();
-                num.obj().set(col, 9);
-                r2->commit_transaction();
-
-                ref = num;
-            };
-
-            REQUIRE(num.obj().get<Int>(col) == 7);
-            Object num_prime = ref.resolve<Object>(r);
-            REQUIRE(num_prime.obj().get<Int>(col) == 9);
-            REQUIRE(num.obj().get<Int>(col) == 9);
-
-            r->begin_transaction();
-            num.obj().set(col, 11);
-            r->commit_transaction();
-
-            REQUIRE(num_prime.obj().get<Int>(col) == 11);
-            REQUIRE(num.obj().get<Int>(col) == 11);
-        }
-
-        SECTION("resolve at newer version") {
-            r->begin_transaction();
-            Object num = create_object(r, "int object", {{"value", INT64_C(7)}});
-            r->commit_transaction();
-
-            ColKey col = num.get_object_schema().property_for_name("value")->column_key;
-            ObjKey k = num.obj().get_key();
-
-            REQUIRE(num.obj().get<Int>(col) == 7);
-            auto ref = ThreadSafeReference(num);
-            {
-                SharedRealm r2 = Realm::get_shared_realm(config);
-                Object num = Object(r2, "int object", k);
-
-                r2->begin_transaction();
-                num.obj().set(col, 9);
-                r2->commit_transaction();
-                REQUIRE(num.obj().get<Int>(col) == 9);
-
-                Object num_prime = ref.resolve<Object>(r2);
-                REQUIRE(num_prime.obj().get<Int>(col) == 9);
-
-                r2->begin_transaction();
-                num_prime.obj().set(col, 11);
-                r2->commit_transaction();
-
-                REQUIRE(num.obj().get<Int>(col) == 11);
-                REQUIRE(num_prime.obj().get<Int>(col) == 11);
-            }
-
-            REQUIRE(num.obj().get<Int>(col) == 7);
-            r->refresh();
-            REQUIRE(num.obj().get<Int>(col) == 11);
-        }
-
-        SECTION("resolve at newer version when schema is specified") {
-            r->close();
-            config.schema = schema;
-            SharedRealm r = Realm::get_shared_realm(config);
-            r->begin_transaction();
-            Object num = create_object(r, "int object", {{"value", INT64_C(7)}});
-            r->commit_transaction();
-
-            ColKey col = num.get_object_schema().property_for_name("value")->column_key;
-            auto ref = ThreadSafeReference(num);
-
-            r->begin_transaction();
-            num.obj().set(col, 9);
-            r->commit_transaction();
-
-            REQUIRE_NOTHROW(ref.resolve<Object>(r));
-        }
-
-        SECTION("resolve references at multiple versions") {
-            auto commit_new_num = [&](int64_t value) -> Object {
-                r->begin_transaction();
-                Object num = create_object(r, "int object", {{"value", value}});
-                r->commit_transaction();
-                return num;
-            };
-
-            auto ref1 = ThreadSafeReference(commit_new_num(1));
-            auto ref2 = ThreadSafeReference(commit_new_num(2));
-            {
-                SharedRealm r2 = Realm::get_shared_realm(config);
-                Object num1 = ref1.resolve<Object>(r2);
-                Object num2 = ref2.resolve<Object>(r2);
-
-                ColKey col = num1.get_object_schema().property_for_name("value")->column_key;
-                REQUIRE(num1.obj().get<Int>(col) == 1);
-                REQUIRE(num2.obj().get<Int>(col) == 2);
-            }
-        }
-    }
-
-    SECTION("same thread") {
-        r->begin_transaction();
-        Object num = create_object(r, "int object", {{"value", INT64_C(7)}});
-        r->commit_transaction();
-
-        ColKey col = num.get_object_schema().property_for_name("value")->column_key;
-        REQUIRE(num.obj().get<Int>(col) == 7);
-        auto ref = ThreadSafeReference(num);
-        bool did_run_section = false;
-
-        SECTION("same realm") {
-            did_run_section = true;
-            {
-                Object num = ref.resolve<Object>(r);
-                REQUIRE(num.obj().get<Int>(col) == 7);
-                r->begin_transaction();
-                num.obj().set(col, 9);
-                r->commit_transaction();
-                REQUIRE(num.obj().get<Int>(col) == 9);
-            }
-            REQUIRE(num.obj().get<Int>(col) == 9);
-        }
-        SECTION("different realm") {
-            did_run_section = true;
-            {
-                SharedRealm r = Realm::get_shared_realm(config);
-                Object num = ref.resolve<Object>(r);
-                REQUIRE(num.obj().get<Int>(col) == 7);
-                r->begin_transaction();
-                num.obj().set(col, 9);
-                r->commit_transaction();
-                REQUIRE(num.obj().get<Int>(col) == 9);
-            }
-            REQUIRE(num.obj().get<Int>(col) == 7);
-        }
-        catch2_ensure_section_run_workaround(did_run_section, "same thread", [&](){
-            r->begin_transaction(); // advance to latest version by starting a write
-            REQUIRE(num.obj().get<Int>(col) == 9);
-            r->cancel_transaction();
-        });
-    }
-
-    SECTION("passing over") {
-        SECTION("objects") {
-            r->begin_transaction();
-            auto str = create_object(r, "string object", {});
-            auto num = create_object(r, "int object", {{"value", INT64_C(0)}});
-            r->commit_transaction();
-
-            ColKey col_num = num.get_object_schema().property_for_name("value")->column_key;
-            ColKey col_str = str.get_object_schema().property_for_name("value")->column_key;
-            auto ref_str = ThreadSafeReference(str);
-            auto ref_num = ThreadSafeReference(num);
-            {
-                SharedRealm r2 = Realm::get_shared_realm(config);
-                Object str = ref_str.resolve<Object>(r2);
-                Object num = ref_num.resolve<Object>(r2);
-
-                REQUIRE(str.obj().get<String>(col_str).is_null());
-                REQUIRE(num.obj().get<Int>(col_num) == 0);
-
-                r2->begin_transaction();
-                str.obj().set(col_str, "the meaning of life");
-                num.obj().set(col_num, 42);
-                r2->commit_transaction();
-            }
-
-            REQUIRE(str.obj().get<String>(col_str).is_null());
-            REQUIRE(num.obj().get<Int>(col_num) == 0);
-
-            r->refresh();
-
-            REQUIRE(str.obj().get<String>(col_str) == "the meaning of life");
-            REQUIRE(num.obj().get<Int>(col_num) == 42);
-        }
-
-        SECTION("object list") {
-            r->begin_transaction();
-            auto zero = create_object(r, "int object", {{"value", INT64_C(0)}});
-            auto obj = create_object(r, "int array object", {{"value", AnyVector{zero}}});
-            auto col = get_table(*r, "int array object")->get_column_key("value");
-            List list(r, obj.obj(), col);
-            r->commit_transaction();
-
-            REQUIRE(list.size() == 1);
-            REQUIRE(list.get(0).get<int64_t>(int_obj_col) == 0);
-            auto ref = ThreadSafeReference(list);
-            {
-                SharedRealm r2 = Realm::get_shared_realm(config);
-                List list = ref.resolve<List>(r2);
-                REQUIRE(list.size() == 1);
-                REQUIRE(list.get(0).get<int64_t>(int_obj_col) == 0);
-
-                r2->begin_transaction();
-                list.remove_all();
-                auto one = create_object(r2, "int object", {{"value", INT64_C(1)}});
-                auto two = create_object(r2, "int object", {{"value", INT64_C(2)}});
-                list.add(one.obj());
-                list.add(two.obj());
-                r2->commit_transaction();
-
-                REQUIRE(list.size() == 2);
-                REQUIRE(list.get(0).get<int64_t>(int_obj_col) == 1);
-                REQUIRE(list.get(1).get<int64_t>(int_obj_col) == 2);
-            }
-
-            REQUIRE(list.size() == 1);
-            REQUIRE(list.get(0).get<int64_t>(int_obj_col) == 0);
-
-            r->refresh();
-
-            REQUIRE(list.size() == 2);
-            REQUIRE(list.get(0).get<int64_t>(int_obj_col) == 1);
-            REQUIRE(list.get(1).get<int64_t>(int_obj_col) == 2);
-        }
-
-        SECTION("sorted object results") {
-            auto& table = *get_table(*r, "string object");
-            auto col = table.get_column_key("value");
-            auto results = Results(r, table.where().not_equal(col, "C")).sort({{{col}}, {false}});
-
-            r->begin_transaction();
-            create_object(r, "string object", {{"value", "A"s}});
-            create_object(r, "string object", {{"value", "B"s}});
-            create_object(r, "string object", {{"value", "C"s}});
-            create_object(r, "string object", {{"value", "D"s}});
-            r->commit_transaction();
-
-            REQUIRE(results.size() == 3);
-            REQUIRE(results.get(0).get<StringData>(col) == "D");
-            REQUIRE(results.get(1).get<StringData>(col) == "B");
-            REQUIRE(results.get(2).get<StringData>(col) == "A");
-            auto ref = ThreadSafeReference(results);
-            {
-                SharedRealm r2 = Realm::get_shared_realm(config);
-                Results results = ref.resolve<Results>(r2);
-
-                REQUIRE(results.size() == 3);
-                REQUIRE(results.get(0).get<StringData>(col) == "D");
-                REQUIRE(results.get(1).get<StringData>(col) == "B");
-                REQUIRE(results.get(2).get<StringData>(col) == "A");
-
-                r2->begin_transaction();
-                results.get(2).remove();
-                results.get(0).remove();
-                create_object(r2, "string object", {{"value", "E"s}});
-                r2->commit_transaction();
-
-                REQUIRE(results.size() == 2);
-                REQUIRE(results.get(0).get<StringData>(col) == "E");
-                REQUIRE(results.get(1).get<StringData>(col) == "B");
-            }
-
-            REQUIRE(results.size() == 3);
-            REQUIRE(results.get(0).get<StringData>(col) == "D");
-            REQUIRE(results.get(1).get<StringData>(col) == "B");
-            REQUIRE(results.get(2).get<StringData>(col) == "A");
-
-            r->refresh();
-
-            REQUIRE(results.size() == 2);
-            REQUIRE(results.get(0).get<StringData>(col) == "E");
-            REQUIRE(results.get(1).get<StringData>(col) == "B");
-        }
-
-        SECTION("distinct object results") {
-            auto& table = *get_table(*r, "string object");
-            auto col = table.get_column_key("value");
-            auto results = Results(r, table.where()).distinct({{{col}}}).sort({{"value", true}});
-
-            r->begin_transaction();
-            create_object(r, "string object", {{"value", "A"s}});
-            create_object(r, "string object", {{"value", "A"s}});
-            create_object(r, "string object", {{"value", "B"s}});
-            r->commit_transaction();
-
-            REQUIRE(results.size() == 2);
-            REQUIRE(results.get(0).get<StringData>(col) == "A");
-            REQUIRE(results.get(1).get<StringData>(col) == "B");
-            auto ref = ThreadSafeReference(results);
-            {
-                SharedRealm r2 = Realm::get_shared_realm(config);
-                Results results = ref.resolve<Results>(r2);
-
-                REQUIRE(results.size() == 2);
-                REQUIRE(results.get(0).get<StringData>(col) == "A");
-                REQUIRE(results.get(1).get<StringData>(col) == "B");
-
-                r2->begin_transaction();
-                results.get(0).remove();
-                create_object(r2, "string object", {{"value", "C"s}});
-                r2->commit_transaction();
-
-                REQUIRE(results.size() == 3);
-                REQUIRE(results.get(0).get<StringData>(col) == "A");
-                REQUIRE(results.get(1).get<StringData>(col) == "B");
-                REQUIRE(results.get(2).get<StringData>(col) == "C");
-            }
-
-            REQUIRE(results.size() == 2);
-            REQUIRE(results.get(0).get<StringData>(col) == "A");
-            REQUIRE(results.get(1).get<StringData>(col) == "B");
-
-            r->refresh();
-
-            REQUIRE(results.size() == 3);
-            REQUIRE(results.get(0).get<StringData>(col) == "A");
-            REQUIRE(results.get(1).get<StringData>(col) == "B");
-            REQUIRE(results.get(2).get<StringData>(col) == "C");
-        }
-
-        SECTION("int list") {
-            r->begin_transaction();
-            auto obj = create_object(r, "int array", {{"value", AnyVector{INT64_C(0)}}});
-            auto col = get_table(*r, "int array")->get_column_key("value");
-            List list(r, obj.obj(), col);
-            r->commit_transaction();
-
-            auto ref = ThreadSafeReference(list);
-            {
-                SharedRealm r2 = Realm::get_shared_realm(config);
-                List list = ref.resolve<List>(r2);
-                REQUIRE(list.size() == 1);
-                REQUIRE(list.get<int64_t>(0) == 0);
-
-                r2->begin_transaction();
-                list.remove_all();
-                list.add(int64_t(1));
-                list.add(int64_t(2));
-                r2->commit_transaction();
-
-                REQUIRE(list.size() == 2);
-                REQUIRE(list.get<int64_t>(0) == 1);
-                REQUIRE(list.get<int64_t>(1) == 2);
-            };
-
-            REQUIRE(list.size() == 1);
-            REQUIRE(list.get<int64_t>(0) == 0);
-
-            r->refresh();
-
-            REQUIRE(list.size() == 2);
-            REQUIRE(list.get<int64_t>(0) == 1);
-            REQUIRE(list.get<int64_t>(1) == 2);
-        }
-
-        SECTION("sorted int results") {
-            r->begin_transaction();
-            auto obj = create_object(r, "int array", {{"value", AnyVector{INT64_C(0), INT64_C(2), INT64_C(1)}}});
-            auto col = get_table(*r, "int array")->get_column_key("value");
-            List list(r, obj.obj(), col);
-            r->commit_transaction();
-
-            auto results = list.sort({{"self", true}});
-
-            REQUIRE(results.size() == 3);
-            REQUIRE(results.get<int64_t>(0) == 0);
-            REQUIRE(results.get<int64_t>(1) == 1);
-            REQUIRE(results.get<int64_t>(2) == 2);
-            auto ref = ThreadSafeReference(results);
-            std::thread([ref = std::move(ref), config]() mutable {
-                config.scheduler = util::Scheduler::get_frozen();
-                SharedRealm r = Realm::get_shared_realm(config);
-                Results results = ref.resolve<Results>(r);
-
-                REQUIRE(results.size() == 3);
-                REQUIRE(results.get<int64_t>(0) == 0);
-                REQUIRE(results.get<int64_t>(1) == 1);
-                REQUIRE(results.get<int64_t>(2) == 2);
-
-                r->begin_transaction();
-                auto table = get_table(*r, "int array");
-                List list(r, *table->begin(), table->get_column_key("value"));
-                list.remove(1);
-                list.add(int64_t(-1));
-                r->commit_transaction();
-
-                REQUIRE(results.size() == 3);
-                REQUIRE(results.get<int64_t>(0) == -1);
-                REQUIRE(results.get<int64_t>(1) == 0);
-                REQUIRE(results.get<int64_t>(2) == 1);
-            }).join();
-
-            REQUIRE(results.size() == 3);
-            REQUIRE(results.get<int64_t>(0) == 0);
-            REQUIRE(results.get<int64_t>(1) == 1);
-            REQUIRE(results.get<int64_t>(2) == 2);
-
-            r->refresh();
-
-            REQUIRE(results.size() == 3);
-            REQUIRE(results.get<int64_t>(0) == -1);
-            REQUIRE(results.get<int64_t>(1) == 0);
-            REQUIRE(results.get<int64_t>(2) == 1);
-        }
-
-        SECTION("distinct int results") {
-            r->begin_transaction();
-            auto obj = create_object(
-                r, "int array", {{"value", AnyVector{INT64_C(3), INT64_C(2), INT64_C(1), INT64_C(1), INT64_C(2)}}});
-            auto col = get_table(*r, "int array")->get_column_key("value");
-            List list(r, obj.obj(), col);
-            r->commit_transaction();
-
-            auto results = list.as_results().distinct({"self"}).sort({{"self", true}});
-
-            REQUIRE(results.size() == 3);
-            REQUIRE(results.get<int64_t>(0) == 1);
-            REQUIRE(results.get<int64_t>(1) == 2);
-            REQUIRE(results.get<int64_t>(2) == 3);
-
-            auto ref = ThreadSafeReference(results);
-            std::thread([ref = std::move(ref), config]() mutable {
-                config.scheduler = util::Scheduler::get_frozen();
-                SharedRealm r = Realm::get_shared_realm(config);
-                Results results = ref.resolve<Results>(r);
-
-                REQUIRE(results.size() == 3);
-                REQUIRE(results.get<int64_t>(0) == 1);
-                REQUIRE(results.get<int64_t>(1) == 2);
-                REQUIRE(results.get<int64_t>(2) == 3);
-
-                r->begin_transaction();
-                auto table = get_table(*r, "int array");
-                List list(r, *table->begin(), table->get_column_key("value"));
-                list.remove(1);
-                list.remove(0);
-                r->commit_transaction();
-
-                REQUIRE(results.size() == 2);
-                REQUIRE(results.get<int64_t>(0) == 1);
-                REQUIRE(results.get<int64_t>(1) == 2);
-            }).join();
-
-            REQUIRE(results.size() == 3);
-            REQUIRE(results.get<int64_t>(0) == 1);
-            REQUIRE(results.get<int64_t>(1) == 2);
-            REQUIRE(results.get<int64_t>(2) == 3);
-
-            r->refresh();
-
-            REQUIRE(results.size() == 2);
-            REQUIRE(results.get<int64_t>(0) == 1);
-            REQUIRE(results.get<int64_t>(1) == 2);
-        }
-
-        SECTION("multiple types") {
-            auto results = Results(r, get_table(*r, "int object")->where().equal(int_obj_col, 5));
-
-            r->begin_transaction();
-            auto num = create_object(r, "int object", {{"value", INT64_C(5)}});
-            auto obj = create_object(r, "int array object", {{"value", AnyVector{}}});
-            auto col = get_table(*r, "int array object")->get_column_key("value");
-            List list(r, obj.obj(), col);
-            r->commit_transaction();
-
-            REQUIRE(list.size() == 0);
-            REQUIRE(results.size() == 1);
-            REQUIRE(results.get(0).get<int64_t>(int_obj_col) == 5);
-            auto ref_num = ThreadSafeReference(num);
-            auto ref_list = ThreadSafeReference(list);
-            auto ref_results = ThreadSafeReference(results);
-            {
-                SharedRealm r2 = Realm::get_shared_realm(config);
-                auto num = ref_num.resolve<Object>(r2);
-                auto list = ref_list.resolve<List>(r2);
-                auto results = ref_results.resolve<Results>(r2);
-
-                REQUIRE(list.size() == 0);
-                REQUIRE(results.size() == 1);
-                REQUIRE(results.get(0).get<int64_t>(int_obj_col) == 5);
-
-                r2->begin_transaction();
-                num.obj().set_all(6);
-                list.add(num.obj().get_key());
-                r2->commit_transaction();
-
-                REQUIRE(list.size() == 1);
-                REQUIRE(list.get(0).get<int64_t>(int_obj_col) == 6);
-                REQUIRE(results.size() == 0);
-            }
-
-            REQUIRE(list.size() == 0);
-            REQUIRE(results.size() == 1);
-            REQUIRE(results.get(0).get<int64_t>(int_obj_col) == 5);
-
-            r->refresh();
-
-            REQUIRE(list.size() == 1);
-            REQUIRE(list.get(0).get<int64_t>(int_obj_col) == 6);
-            REQUIRE(results.size() == 0);
-        }
-    }
-
-    SECTION("resolve at version where handed over thing has been deleted") {
-        Object obj;
-        auto delete_and_resolve = [&](auto&& list) {
-            auto ref = ThreadSafeReference(list);
-
-            r->begin_transaction();
-            obj.obj().remove();
-            r->commit_transaction();
-
-            return ref.resolve<typename std::remove_reference<decltype(list)>::type>(r);
-        };
-
-        SECTION("object") {
-            r->begin_transaction();
-            obj = create_object(r, "int object", {{"value", INT64_C(7)}});
-            r->commit_transaction();
-
-            REQUIRE(!delete_and_resolve(obj).is_valid());
-        }
-
-        SECTION("object list") {
-            r->begin_transaction();
-            obj = create_object(r, "int array object", {{"value", AnyVector{AnyDict{{"value", INT64_C(0)}}}}});
-            auto col = get_table(*r, "int array object")->get_column_key("value");
-            List list(r, obj.obj(), col);
-            r->commit_transaction();
-
-            REQUIRE(!delete_and_resolve(list).is_valid());
-        }
-
-        SECTION("int list") {
-            r->begin_transaction();
-            obj = create_object(r, "int array", {{"value", AnyVector{{INT64_C(1)}}}});
-            auto col = get_table(*r, "int array")->get_column_key("value");
-            List list(r, obj.obj(), col);
-            r->commit_transaction();
-
-            REQUIRE(!delete_and_resolve(list).is_valid());
-        }
-
-        SECTION("object results") {
-            r->begin_transaction();
-            obj = create_object(r, "int array object", {{"value", AnyVector{AnyDict{{"value", INT64_C(0)}}}}});
-            auto col = get_table(*r, "int array object")->get_column_key("value");
-            List list(r, obj.obj(), col);
-            r->commit_transaction();
-
-            auto results = delete_and_resolve(list.sort({{"value", true}}));
-            REQUIRE(results.is_valid());
-            REQUIRE(results.size() == 0);
-        }
-
-        SECTION("int results") {
-            r->begin_transaction();
-            obj = create_object(r, "int array", {{"value", AnyVector{{INT64_C(1)}}}});
-            List list(r, obj.obj(), get_table(*r, "int array")->get_column_key("value"));
-            r->commit_transaction();
-
-            REQUIRE(!delete_and_resolve(list).is_valid());
-        }
-    }
-
-    SECTION("resolve at version before where handed over thing was created") {
-        auto create_ref = [&](auto&& fn) -> ThreadSafeReference {
-            ThreadSafeReference ref;
-            {
-                SharedRealm r2 = Realm::get_shared_realm(config);
-                r2->begin_transaction();
-                auto obj = fn(r2);
-                r2->commit_transaction();
-                ref = obj;
-            };
-            return ref;
-        };
-
-        SECTION("object") {
-            auto obj = create_ref([](auto& r) {
-                return create_object(r, "int object", {{"value", INT64_C(7)}});
-            }).resolve<Object>(r);
-            REQUIRE(obj.is_valid());
-            REQUIRE(obj.get_column_value<int64_t>("value") == 7);
-        }
-
-        SECTION("object list") {
-            auto list = create_ref([](auto& r) {
-                auto obj = create_object(r, "int array object", {{"value", AnyVector{AnyDict{{"value", INT64_C(0)}}}}});
-                return List(r, obj.obj(), get_table(*r, "int array object")->get_column_key("value"));
-            }).resolve<List>(r);
-            REQUIRE(list.is_valid());
-            REQUIRE(list.size() == 1);
-        }
-
-        SECTION("int list") {
-            auto list = create_ref([](auto& r) {
-                auto obj = create_object(r, "int array", {{"value", AnyVector{{INT64_C(1)}}}});
-                return List(r, obj.obj(), get_table(*r, "int array")->get_column_key("value"));
-            }).resolve<List>(r);
-            REQUIRE(list.is_valid());
-            REQUIRE(list.size() == 1);
-        }
-
-        SECTION("object results") {
-            auto results = create_ref([](auto& r) {
-                auto obj = create_object(r, "int array object", {{"value", AnyVector{AnyDict{{"value", INT64_C(0)}}}}});
-                Results results = List(r, obj.obj(), get_table(*r, "int array object")->get_column_key("value"))
-                    .sort({{"value", true}});
-                REQUIRE(results.size() == 1);
-                return results;
-            }).resolve<Results>(r);
-            REQUIRE(results.is_valid());
-            REQUIRE(results.size() == 1);
-        }
-
-        SECTION("int results") {
-            auto results = create_ref([](auto& r) {
-                auto obj = create_object(r, "int array", {{"value", AnyVector{{INT64_C(1)}}}});
-                return List(r, obj.obj(), get_table(*r, "int array")->get_column_key("value")).sort({{"self", true}});
-            }).resolve<Results>(r);
-            REQUIRE(results.is_valid());
-            REQUIRE(results.size() == 1);
-        }
-    }
-
-    SECTION("create TSR inside the write transaction which created the object being handed over") {
-        auto create_ref = [&](auto&& fn) -> ThreadSafeReference {
-            ThreadSafeReference ref;
-            {
-                SharedRealm r2 = Realm::get_shared_realm(config);
-                r2->begin_transaction();
-                ref = fn(r2);
-                r2->commit_transaction();
-            };
-            return ref;
-        };
-
-        SECTION("object") {
-            auto obj = create_ref([](auto& r) {
-                return create_object(r, "int object", {{"value", INT64_C(7)}});
-            }).resolve<Object>(r);
-            REQUIRE(obj.is_valid());
-            REQUIRE(obj.get_column_value<int64_t>("value") == 7);
-        }
-
-        SECTION("object list") {
-            auto list = create_ref([](auto& r) {
-                auto obj = create_object(r, "int array object", {{"value", AnyVector{AnyDict{{"value", INT64_C(0)}}}}});
-                return List(r, obj.obj(), get_table(*r, "int array object")->get_column_key("value"));
-            }).resolve<List>(r);
-            REQUIRE(list.is_valid());
-            REQUIRE(list.size() == 1);
-        }
-
-        SECTION("int list") {
-            auto list = create_ref([](auto& r) {
-                auto obj = create_object(r, "int array", {{"value", AnyVector{{INT64_C(1)}}}});
-                return List(r, obj.obj(), get_table(*r, "int array")->get_column_key("value"));
-            }).resolve<List>(r);
-            REQUIRE(list.is_valid());
-            REQUIRE(list.size() == 1);
-        }
-
-        SECTION("object results") {
-            REQUIRE_THROWS(create_ref([](auto& r) {
-                auto obj = create_object(r, "int array object", {{"value", AnyVector{AnyDict{{"value", INT64_C(0)}}}}});
-                Results results = List(r, obj.obj(), get_table(*r, "int array object")->get_column_key("value"))
-                    .sort({{"value", true}});
-                REQUIRE(results.size() == 1);
-                return results;
-            }));
-        }
-
-        SECTION("int results") {
-            auto results = create_ref([](auto& r) {
-                auto obj = create_object(r, "int array", {{"value", AnyVector{{INT64_C(1)}}}});
-                return List(r, obj.obj(), get_table(*r, "int array")->get_column_key("value")).sort({{"self", true}});
-            }).resolve<Results>(r);
-            REQUIRE(results.is_valid());
-            REQUIRE(results.size() == 1);
-        }
-    }
-
-    SECTION("create TSR inside cancelled write transaction") {
-        auto create_ref = [&](auto&& fn) -> ThreadSafeReference {
-            ThreadSafeReference ref;
-            {
-                SharedRealm r2 = Realm::get_shared_realm(config);
-                r2->begin_transaction();
-                ref = fn(r2);
-                r2->cancel_transaction();
-            };
-            return ref;
-        };
-
-        SECTION("object") {
-            auto obj = create_ref([](auto& r) {
-                return create_object(r, "int object", {{"value", INT64_C(7)}});
-            }).resolve<Object>(r);
-            REQUIRE_FALSE(obj.is_valid());
-        }
-
-        SECTION("object list") {
-            auto list = create_ref([](auto& r) {
-                auto obj = create_object(r, "int array object", {{"value", AnyVector{AnyDict{{"value", INT64_C(0)}}}}});
-                return List(r, obj.obj(), get_table(*r, "int array object")->get_column_key("value"));
-            }).resolve<List>(r);
-            REQUIRE_FALSE(list.is_valid());
-        }
-
-        SECTION("int list") {
-            auto list = create_ref([](auto& r) {
-                auto obj = create_object(r, "int array", {{"value", AnyVector{{INT64_C(1)}}}});
-                return List(r, obj.obj(), get_table(*r, "int array")->get_column_key("value"));
-            }).resolve<List>(r);
-            REQUIRE_FALSE(list.is_valid());
-        }
-
-        SECTION("object results") {
-            REQUIRE_THROWS(create_ref([](auto& r) {
-                auto obj = create_object(r, "int array object", {{"value", AnyVector{AnyDict{{"value", INT64_C(0)}}}}});
-                Results results = List(r, obj.obj(), get_table(*r, "int array object")->get_column_key("value"))
-                    .sort({{"value", true}});
-                REQUIRE(results.size() == 1);
-                return results;
-            }));
-        }
-
-        SECTION("int results") {
-            auto results = create_ref([](auto& r) {
-                auto obj = create_object(r, "int array", {{"value", AnyVector{{INT64_C(1)}}}});
-                return List(r, obj.obj(), get_table(*r, "int array")->get_column_key("value")).sort({{"self", true}});
-            }).resolve<Results>(r);
-            REQUIRE_FALSE(results.is_valid());
-        }
-    }
-
-    SECTION("lifetime") {
-        SECTION("retains source realm") { // else version will become unpinned
-            auto ref = ThreadSafeReference(foo);
-            foo = {};
-            r = nullptr;
-            r = Realm::get_shared_realm(config);
-            REQUIRE_NOTHROW(ref.resolve<Object>(r));
-        }
-
-        SECTION("retains source RealmCoordinator") {
-            auto ref = ThreadSafeReference(foo);
-            auto coordinator = _impl::RealmCoordinator::get_existing_coordinator(config.path).get();
-            foo = {};
-            r = nullptr;
-            REQUIRE(coordinator == _impl::RealmCoordinator::get_existing_coordinator(config.path).get());
-        }
-    }
-
-    SECTION("metadata") {
-        r->begin_transaction();
-        auto num = create_object(r, "int object", {{"value", INT64_C(5)}});
-        r->commit_transaction();
-        REQUIRE(num.get_object_schema().name == "int object");
-
-        auto ref = ThreadSafeReference(num);
-        {
-            SharedRealm r2 = Realm::get_shared_realm(config);
-            Object num = ref.resolve<Object>(r2);
-            REQUIRE(num.get_object_schema().name == "int object");
-        }
-    }
-
-    SECTION("allow multiple resolves") {
-        auto ref = ThreadSafeReference(foo);
-        ref.resolve<Object>(r);
-        REQUIRE_NOTHROW(ref.resolve<Object>(r));
-    }
-}

Some files were not shown because too many files changed in this diff