An amazing project that generates micro reports from tournament results
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

147 lines
5.0 KiB

////////////////////////////////////////////////////////////////////////////
//
// Copyright 2014 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////
#import "RLMRealmUtil.hpp"
#import "RLMObjectSchema_Private.hpp"
#import "RLMObservation.hpp"
#import "RLMRealm_Private.hpp"
#import "RLMUtil.hpp"
#import <Realm/RLMConstants.h>
#import <Realm/RLMSchema.h>
#import "binding_context.hpp"
#import <map>
#import <mutex>
#import <sys/event.h>
#import <sys/stat.h>
#import <sys/time.h>
#import <unistd.h>
// Global realm state
static std::mutex& s_realmCacheMutex = *new std::mutex();
static std::map<std::string, NSMapTable *>& s_realmsPerPath = *new std::map<std::string, NSMapTable *>();
void RLMCacheRealm(std::string const& path, __unsafe_unretained RLMRealm *const realm) {
std::lock_guard<std::mutex> lock(s_realmCacheMutex);
NSMapTable *realms = s_realmsPerPath[path];
if (!realms) {
s_realmsPerPath[path] = realms = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsOpaquePersonality|NSPointerFunctionsOpaqueMemory
valueOptions:NSPointerFunctionsWeakMemory];
}
[realms setObject:realm forKey:(__bridge id)pthread_self()];
}
RLMRealm *RLMGetAnyCachedRealmForPath(std::string const& path) {
std::lock_guard<std::mutex> lock(s_realmCacheMutex);
return [s_realmsPerPath[path] objectEnumerator].nextObject;
}
RLMRealm *RLMGetThreadLocalCachedRealmForPath(std::string const& path) {
std::lock_guard<std::mutex> lock(s_realmCacheMutex);
return [s_realmsPerPath[path] objectForKey:(__bridge id)pthread_self()];
}
void RLMClearRealmCache() {
std::lock_guard<std::mutex> lock(s_realmCacheMutex);
s_realmsPerPath.clear();
}
bool RLMIsInRunLoop() {
// The main thread may not be in a run loop yet if we're called from
// something like `applicationDidFinishLaunching:`, but it presumably will
// be in the future
if ([NSThread isMainThread]) {
return true;
}
// Current mode indicates why the current callout from the runloop was made,
// and is null if a runloop callout isn't currently being processed
if (auto mode = CFRunLoopCopyCurrentMode(CFRunLoopGetCurrent())) {
CFRelease(mode);
return true;
}
return false;
}
namespace {
class RLMNotificationHelper : public realm::BindingContext {
public:
RLMNotificationHelper(RLMRealm *realm) : _realm(realm) { }
bool can_deliver_notifications() const noexcept override {
return RLMIsInRunLoop();
}
void changes_available() override {
@autoreleasepool {
auto realm = _realm;
if (realm && !realm.autorefresh) {
[realm sendNotifications:RLMRealmRefreshRequiredNotification];
}
}
}
std::vector<ObserverState> get_observed_rows() override {
@autoreleasepool {
if (auto realm = _realm) {
[realm detachAllEnumerators];
return RLMGetObservedRows(realm->_info);
}
return {};
}
}
void will_change(std::vector<ObserverState> const& observed, std::vector<void*> const& invalidated) override {
@autoreleasepool {
RLMWillChange(observed, invalidated);
}
}
void did_change(std::vector<ObserverState> const& observed, std::vector<void*> const& invalidated, bool version_changed) override {
try {
@autoreleasepool {
RLMDidChange(observed, invalidated);
if (version_changed) {
[_realm sendNotifications:RLMRealmDidChangeNotification];
}
}
}
catch (...) {
// This can only be called during a write transaction if it was
// called due to the transaction beginning, so cancel it to ensure
// exceptions thrown here behave the same as exceptions thrown when
// actually beginning the write
if (_realm.inWriteTransaction) {
[_realm cancelWriteTransaction];
}
throw;
}
}
private:
// This is owned by the realm, so it needs to not retain the realm
__weak RLMRealm *const _realm;
};
} // anonymous namespace
std::unique_ptr<realm::BindingContext> RLMCreateBindingContext(__unsafe_unretained RLMRealm *const realm) {
return std::unique_ptr<realm::BindingContext>(new RLMNotificationHelper(realm));
}