added iOS source code
[wl-app.git] / iOS / Pods / Realm / include / RLMObservation.hpp
diff --git a/iOS/Pods/Realm/include/RLMObservation.hpp b/iOS/Pods/Realm/include/RLMObservation.hpp
new file mode 100644 (file)
index 0000000..0f5b215
--- /dev/null
@@ -0,0 +1,153 @@
+////////////////////////////////////////////////////////////////////////////
+//
+// Copyright 2015 Realm Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////
+
+#import <Foundation/Foundation.h>
+
+#import "binding_context.hpp"
+
+#import <realm/row.hpp>
+#import <realm/table.hpp>
+
+#import <unordered_map>
+
+@class RLMObjectBase, RLMRealm, RLMSchema, RLMProperty, RLMObjectSchema;
+class RLMClassInfo;
+class RLMSchemaInfo;
+
+namespace realm {
+    class History;
+    class SharedGroup;
+}
+
+// RLMObservationInfo stores all of the KVO-related data for RLMObjectBase and
+// RLMArray. There is a one-to-one relationship between observed objects and
+// RLMObservationInfo instances, so it could be folded into RLMObjectBase, and
+// is a separate class mostly to avoid making all accessor objects far larger.
+//
+// RLMClassInfo stores a vector of pointers to the first observation info
+// created for each row. If there are multiple observation infos for a single
+// row (such as if there are multiple observed objects backed by a single row,
+// or if both an object and an array property of that object are observed),
+// they're stored in an intrusive doubly-linked-list in the `next` and `prev`
+// members. This is done primarily to make it simpler and faster to loop over
+// all of the observed objects for a single row, as that needs to be done for
+// every change.
+class RLMObservationInfo {
+public:
+    RLMObservationInfo(id object);
+    RLMObservationInfo(RLMClassInfo &objectSchema, std::size_t row, id object);
+    ~RLMObservationInfo();
+
+    realm::Row const& getRow() const {
+        return row;
+    }
+
+    NSString *columnName(size_t col) const noexcept;
+
+    // Send willChange/didChange notifications to all observers for this object/row
+    // Sends the array versions if indexes is non-nil, normal versions otherwise
+    void willChange(NSString *key, NSKeyValueChange kind=NSKeyValueChangeSetting, NSIndexSet *indexes=nil) const;
+    void didChange(NSString *key, NSKeyValueChange kind=NSKeyValueChangeSetting, NSIndexSet *indexes=nil) const;
+
+    bool isForRow(size_t ndx) const {
+        return row && row.get_index() == ndx;
+    }
+
+    void recordObserver(realm::Row& row, RLMClassInfo *objectInfo, RLMObjectSchema *objectSchema, NSString *keyPath);
+    void removeObserver();
+    bool hasObservers() const { return observerCount > 0; }
+
+    // valueForKey: on observed object and array properties needs to return the
+    // same object each time for KVO to work at all. Doing this all the time
+    // requires some odd semantics to avoid reference cycles, so instead we do
+    // it only to the extent specifically required by KVO. In addition, we
+    // need to continue to return the same object even if this row is deleted,
+    // or deleting an object with active observers will explode horribly.
+    // Once prepareForInvalidation() is called, valueForKey() will always return
+    // the cached value for object and array properties without checking the
+    // backing row to verify it's up-to-date.
+    //
+    // prepareForInvalidation() must be called on the head of the linked list
+    // (i.e. on the object pointed to directly by the object schema)
+    id valueForKey(NSString *key);
+
+    void prepareForInvalidation();
+
+private:
+    // Doubly-linked-list of observed objects for the same row as this
+    RLMObservationInfo *next = nullptr;
+    RLMObservationInfo *prev = nullptr;
+
+    // Row being observed
+    realm::Row row;
+    RLMClassInfo *objectSchema = nullptr;
+
+    // Object doing the observing
+    __unsafe_unretained id object = nil;
+
+    // valueForKey: hack
+    bool invalidated = false;
+    size_t observerCount = 0;
+    NSString *lastKey = nil;
+    __unsafe_unretained RLMProperty *lastProp = nil;
+
+    // objects returned from valueForKey() to keep them alive in case observers
+    // are added and so that they can still be accessed after row is detached
+    NSMutableDictionary *cachedObjects;
+
+    void setRow(realm::Table &table, size_t newRow);
+
+    template<typename F>
+    void forEach(F&& f) const {
+        // The user's observation handler may release their last reference to
+        // the object being observed, which will result in the RLMObservationInfo
+        // being destroyed. As a result, we need to retain the object which owns
+        // both `this` and the current info we're looking at.
+        __attribute__((objc_precise_lifetime)) id self = object, current;
+        for (auto info = prev; info; info = info->prev) {
+            current = info->object;
+            f(info->object);
+        }
+        for (auto info = this; info; info = info->next) {
+            current = info->object;
+            f(info->object);
+        }
+    }
+
+    // Default move/copy constructors don't work due to the intrusive linked
+    // list and we don't need them
+    RLMObservationInfo(RLMObservationInfo const&) = delete;
+    RLMObservationInfo(RLMObservationInfo&&) = delete;
+    RLMObservationInfo& operator=(RLMObservationInfo const&) = delete;
+    RLMObservationInfo& operator=(RLMObservationInfo&&) = delete;
+};
+
+// Get the the observation info chain for the given row
+// Will simply return info if it's non-null, and will search ojectSchema's array
+// for a matching one otherwise, and return null if there are none
+RLMObservationInfo *RLMGetObservationInfo(RLMObservationInfo *info, size_t row, RLMClassInfo& objectSchema);
+
+// delete all objects from a single table with change notifications
+void RLMClearTable(RLMClassInfo &realm);
+
+// invoke the block, sending notifications for cascading deletes/link nullifications
+void RLMTrackDeletions(RLMRealm *realm, dispatch_block_t block);
+
+std::vector<realm::BindingContext::ObserverState> RLMGetObservedRows(RLMSchemaInfo const& schema);
+void RLMWillChange(std::vector<realm::BindingContext::ObserverState> const& observed, std::vector<void *> const& invalidated);
+void RLMDidChange(std::vector<realm::BindingContext::ObserverState> const& observed, std::vector<void *> const& invalidated);