Skip to content

Commit

Permalink
Change fast enumeration to use a Results snapshot rather than a Table…
Browse files Browse the repository at this point in the history
…View
  • Loading branch information
tgoyne committed Jul 25, 2017
1 parent 275f3f7 commit c902e67
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 62 deletions.
4 changes: 2 additions & 2 deletions Realm/RLMAccessor.mm
Original file line number Diff line number Diff line change
Expand Up @@ -682,11 +682,11 @@ static void validateValueForProperty(__unsafe_unretained id const obj,

id RLMAccessorContext::box(realm::Object&& o) {
REALM_ASSERT(currentProperty);
return RLMCreateObjectAccessor(_realm, _info.linkTargetType(currentProperty.index), o.row().get_index());
return RLMCreateObjectAccessor(_realm, _info.linkTargetType(currentProperty.index), o.row());
}

id RLMAccessorContext::box(realm::RowExpr r) {
return RLMCreateObjectAccessor(_realm, _info, r.get_index());
return RLMCreateObjectAccessor(_realm, _info, r);
}

id RLMAccessorContext::box(realm::Results&& r) {
Expand Down
2 changes: 1 addition & 1 deletion Realm/RLMCollection.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

#import <Foundation/Foundation.h>

#import "RLMThreadSafeReference.h"
#import <Realm/RLMThreadSafeReference.h>

NS_ASSUME_NONNULL_BEGIN

Expand Down
99 changes: 67 additions & 32 deletions Realm/RLMCollection.mm
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@

#import "RLMCollection_Private.hpp"

#import "RLMArray_Private.h"
#import "RLMAccessor.hpp"
#import "RLMArray_Private.hpp"
#import "RLMListBase.h"
#import "RLMObjectSchema_Private.hpp"
#import "RLMObjectStore.h"
#import "RLMObject_Private.hpp"
Expand All @@ -28,8 +30,6 @@
#import "list.hpp"
#import "results.hpp"

#import <realm/table_view.hpp>

static const int RLMEnumerationBufferSize = 16;

@implementation RLMFastEnumerator {
Expand All @@ -42,27 +42,56 @@ @implementation RLMFastEnumerator {
RLMRealm *_realm;
RLMClassInfo *_info;

// Collection being enumerated. Only one of these two will be valid: when
// possible we enumerate the collection directly, but when in a write
// transaction we instead create a frozen TableView and enumerate that
// instead so that mutating the collection during enumeration works.
id<RLMFastEnumerable> _collection;
realm::TableView _tableView;
// A pointer to either _snapshot or a Results from the source collection,
// to avoid having to copy the Results when not in a write transaction
realm::Results *_results;
realm::Results _snapshot;

// A strong reference to the collection being enumerated to ensure it stays
// alive when we're holding a pointer to a member in it
id _collection;
}

- (instancetype)initWithCollection:(id<RLMFastEnumerable>)collection objectSchema:(RLMClassInfo&)info {
- (instancetype)initWithList:(realm::List&)list
collection:(id)collection
realm:(RLMRealm *)realm
classInfo:(RLMClassInfo&)info
{
self = [super init];
if (self) {
_realm = collection.realm;
if (realm.inWriteTransaction) {
_snapshot = list.snapshot();
}
else {
_snapshot = list.as_results();
_collection = collection;
[realm registerEnumerator:self];
}
_results = &_snapshot;
_realm = realm;
_info = &info;
}
return self;
}

if (_realm.inWriteTransaction) {
_tableView = [collection tableView];
- (instancetype)initWithResults:(realm::Results&)results
collection:(id)collection
realm:(RLMRealm *)realm
classInfo:(RLMClassInfo&)info
{
self = [super init];
if (self) {
if (realm.inWriteTransaction) {
_snapshot = results.snapshot();
_results = &_snapshot;
}
else {
_results = &results;
_collection = collection;
[_realm registerEnumerator:self];
[realm registerEnumerator:self];
}
_realm = realm;
_info = &info;
}
return self;
}
Expand All @@ -74,14 +103,15 @@ - (void)dealloc {
}

- (void)detach {
_tableView = [_collection tableView];
_snapshot = _results->snapshot();
_results = &_snapshot;
_collection = nil;
}

- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state
count:(NSUInteger)len {
[_realm verifyThread];
if (!_tableView.is_attached() && !_collection) {
if (!_results->is_valid()) {
@throw RLMException(@"Collection is no longer valid");
}
// The fast enumeration buffer size is currently a hardcoded number in the
Expand All @@ -93,18 +123,12 @@ - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state

NSUInteger batchCount = 0, count = state->extra[1];

Class accessorClass = _info->rlmObjectSchema.accessorClass;
for (NSUInteger index = state->state; index < count && batchCount < len; ++index) {
RLMObject *accessor = RLMCreateManagedAccessor(accessorClass, _realm, _info);
if (_collection) {
accessor->_row = (*_info->table())[[_collection indexInSource:index]];
@autoreleasepool {
RLMAccessorContext ctx(_realm, *_info);
for (NSUInteger index = state->state; index < count && batchCount < len; ++index) {
_strongBuffer[batchCount] = _results->get(ctx, index);
batchCount++;
}
else if (_tableView.is_row_attached(index)) {
accessor->_row = (*_info->table())[_tableView.get_source_ndx(index)];
}
RLMInitializeSwiftAccessorGenerics(accessor);
_strongBuffer[batchCount] = accessor;
batchCount++;
}

for (NSUInteger i = batchCount; i < len; ++i) {
Expand All @@ -114,13 +138,11 @@ - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state
if (batchCount == 0) {
// Release our data if we're done, as we're autoreleased and so may
// stick around for a while
_collection = nil;
if (_tableView.is_attached()) {
_tableView = {};
}
else {
if (_collection) {
_collection = nil;
[_realm unregisterEnumerator:self];
}
_snapshot = {};
}

state->itemsPtr = (__unsafe_unretained id *)(void *)_strongBuffer;
Expand All @@ -131,6 +153,19 @@ - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state
}
@end

NSUInteger RLMFastEnumerate(NSFastEnumerationState *state, NSUInteger len, id<RLMFastEnumerable> collection) {
__autoreleasing RLMFastEnumerator *enumerator;
if (state->state == 0) {
enumerator = collection.fastEnumerator;
state->extra[0] = (long)enumerator;
state->extra[1] = collection.count;
}
else {
enumerator = (__bridge id)(void *)state->extra[0];
}

return [enumerator countByEnumeratingWithState:state count:len];
}

NSArray *RLMCollectionValueForKey(id<RLMFastEnumerable> collection, NSString *key) {
size_t count = collection.count;
Expand Down
13 changes: 11 additions & 2 deletions Realm/RLMCollection_Private.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ namespace realm {
struct NotificationToken;
}
class RLMClassInfo;
@class RLMFastEnumerator;

@protocol RLMFastEnumerable
@property (nonatomic, readonly) RLMRealm *realm;
Expand All @@ -36,14 +37,21 @@ class RLMClassInfo;

- (NSUInteger)indexInSource:(NSUInteger)index;
- (realm::TableView)tableView;
- (RLMFastEnumerator *)fastEnumerator;
@end

// An object which encapulates the shared logic for fast-enumerating RLMArray
// and RLMResults, and has a buffer to store strong references to the current
// set of enumerated items
@interface RLMFastEnumerator : NSObject
- (instancetype)initWithCollection:(id<RLMFastEnumerable>)collection
objectSchema:(RLMClassInfo&)objectSchema;
- (instancetype)initWithList:(realm::List&)list
collection:(id)collection
realm:(RLMRealm *)realm
classInfo:(RLMClassInfo&)info;
- (instancetype)initWithResults:(realm::Results&)results
collection:(id)collection
realm:(RLMRealm *)realm
classInfo:(RLMClassInfo&)info;

// Detach this enumerator from the source collection. Must be called before the
// source collection is changed.
Expand All @@ -52,6 +60,7 @@ class RLMClassInfo;
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state
count:(NSUInteger)len;
@end
NSUInteger RLMFastEnumerate(NSFastEnumerationState *state, NSUInteger len, id<RLMFastEnumerable> collection);

@interface RLMNotificationToken ()
- (void)suppressNextNotification;
Expand Down
21 changes: 8 additions & 13 deletions Realm/RLMManagedArray.mm
Original file line number Diff line number Diff line change
Expand Up @@ -222,19 +222,7 @@ - (NSUInteger)hash {
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state
objects:(__unused __unsafe_unretained id [])buffer
count:(NSUInteger)len {
__autoreleasing RLMFastEnumerator *enumerator;
if (state->state == 0) {
translateErrors([&] { _backingList.verify_attached(); });

enumerator = [[RLMFastEnumerator alloc] initWithCollection:self objectSchema:*_objectInfo];
state->extra[0] = (long)enumerator;
state->extra[1] = self.count;
}
else {
enumerator = (__bridge id)(void *)state->extra[0];
}

return [enumerator countByEnumeratingWithState:state count:len];
return RLMFastEnumerate(state, len, self);
}

- (id)objectAtIndex:(NSUInteger)index {
Expand Down Expand Up @@ -449,6 +437,13 @@ - (NSUInteger)indexInSource:(NSUInteger)index {
return translateErrors([&] { return _backingList.get_query(); }).find_all();
}

- (RLMFastEnumerator *)fastEnumerator {
return translateErrors([&] {
return [[RLMFastEnumerator alloc] initWithList:_backingList collection:self
realm:_realm classInfo:*_objectInfo];
});
}

// The compiler complains about the method's argument type not matching due to
// it not having the generic type attached, but it doesn't seem to be possible
// to actually include the generic type
Expand Down
20 changes: 8 additions & 12 deletions Realm/RLMResults.mm
Original file line number Diff line number Diff line change
Expand Up @@ -156,18 +156,7 @@ - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state
if (!_info) {
return 0;
}

__autoreleasing RLMFastEnumerator *enumerator;
if (state->state == 0) {
enumerator = [[RLMFastEnumerator alloc] initWithCollection:self objectSchema:*_info];
state->extra[0] = (long)enumerator;
state->extra[1] = self.count;
}
else {
enumerator = (__bridge id)(void *)state->extra[0];
}

return [enumerator countByEnumeratingWithState:state count:len];
return RLMFastEnumerate(state, len, self);
}

- (NSUInteger)indexOfObjectWhere:(NSString *)predicateFormat, ... {
Expand Down Expand Up @@ -420,6 +409,13 @@ - (NSUInteger)indexInSource:(NSUInteger)index {
return translateErrors([&] { return _results.get_tableview(); });
}

- (RLMFastEnumerator *)fastEnumerator {
return translateErrors([&] {
return [[RLMFastEnumerator alloc] initWithResults:_results collection:self
realm:_realm classInfo:*_info];
});
}

// The compiler complains about the method's argument type not matching due to
// it not having the generic type attached, but it doesn't seem to be possible
// to actually include the generic type
Expand Down

0 comments on commit c902e67

Please sign in to comment.