Permalink
Browse files

Update NSPointerArray usage in SPDataStorage for 10.9 SDK, tracking e…

…dited row count and using for fast bounds checks; this should fix #1884
  • Loading branch information...
rowanbeentje committed Feb 4, 2014
1 parent 0dad321 commit 1d8db00d8fc0ef855b6308de8c9c66faa70f7d05
Showing with 49 additions and 20 deletions.
  1. +1 −0 Source/SPDataStorage.h
  2. +48 −20 Source/SPDataStorage.m
View
@@ -46,6 +46,7 @@
BOOL *unloadedColumns;
NSUInteger numberOfColumns;
NSUInteger editedRowCount;

This comment has been minimized.

@dmoagx

dmoagx Feb 4, 2014

Member

The name had me confused for a few minutes. It suggests this is the "number of edited rows", but actually it is the "number of rows after editing". Perhaps rename it to rowCountAfterEdit or rowCountIncludingEdits or rowCountNew?

This comment has been minimized.

@rowanbeentje

rowanbeentje Feb 4, 2014

Collaborator

It is actually the "number of edited rows" :) SPDataStorage manages two groups of storage; firstly it allows access to a wrapped SPMySQLStreamingResultStore (low memory usage for uneditable records), and secondly it keeps a sparse NSPointerArray of rows that have been edited. On initial load this will have zero size; when the table has fully loaded it'll be setCount: to the total number of rows, but have no entries until a row is actually edited.

A bit complicated, but that allows us to use a nice compact uneditable store for the vast majority of rows, then layer a few NSObject-based rows on top of that... :)

}
/* Setting result store */
View
@@ -58,6 +58,7 @@ - (void) setDataStorage:(SPMySQLStreamingResultStore *)newDataStorage updatingEx
{
NSUInteger i;
[editedRows release], editedRows = nil;
editedRowCount = 0;
if (unloadedColumns) free(unloadedColumns), unloadedColumns = NULL;
if (dataStorage) {
@@ -96,9 +97,12 @@ - (NSMutableArray *) rowContentsAtIndex:(NSUInteger)anIndex
{
// If an edited row exists for the supplied index, return it
NSMutableArray *editedRow = SPDataStorageGetEditedRow(editedRows, anIndex);
if (editedRow != NULL) {
return editedRow;
if (anIndex < editedRowCount) {
NSMutableArray *editedRow = SPDataStorageGetEditedRow(editedRows, anIndex);
if (editedRow != NULL) {
return editedRow;
}
}
// Otherwise, prepare to return the underlying storage row
@@ -120,10 +124,12 @@ - (NSMutableArray *) rowContentsAtIndex:(NSUInteger)anIndex
- (id) cellDataAtRow:(NSUInteger)rowIndex column:(NSUInteger)columnIndex
{
// If an edited row exists at the supplied index, return it
NSMutableArray *editedRow = SPDataStorageGetEditedRow(editedRows, rowIndex);
if (rowIndex < editedRowCount) {
NSMutableArray *editedRow = SPDataStorageGetEditedRow(editedRows, rowIndex);
if (editedRow != NULL) {
return CFArrayGetValueAtIndex((CFArrayRef)editedRow, columnIndex);
if (editedRow != NULL) {
return CFArrayGetValueAtIndex((CFArrayRef)editedRow, columnIndex);
}
}
// Throw an exception if the column index is out of bounds
@@ -148,13 +154,16 @@ - (id) cellPreviewAtRow:(NSUInteger)rowIndex column:(NSUInteger)columnIndex prev
{
// If an edited row exists at the supplied index, return it
NSMutableArray *editedRow = SPDataStorageGetEditedRow(editedRows, rowIndex);
if (editedRow != NULL) {
id anObject = CFArrayGetValueAtIndex((CFArrayRef)editedRow, columnIndex);
if ([anObject isKindOfClass:[NSString class]] && [(NSString *)anObject length] > 150) {
return ([NSString stringWithFormat:@"%@...", [anObject substringToIndex:147]]);
if (rowIndex < editedRowCount) {
NSMutableArray *editedRow = SPDataStorageGetEditedRow(editedRows, rowIndex);
if (editedRow != NULL) {
id anObject = CFArrayGetValueAtIndex((CFArrayRef)editedRow, columnIndex);
if ([anObject isKindOfClass:[NSString class]] && [(NSString *)anObject length] > 150) {
return ([NSString stringWithFormat:@"%@...", [anObject substringToIndex:147]]);
}
return anObject;
}
return anObject;
}
// Throw an exception if the column index is out of bounds
@@ -177,9 +186,12 @@ - (id) cellPreviewAtRow:(NSUInteger)rowIndex column:(NSUInteger)columnIndex prev
- (BOOL) cellIsNullOrUnloadedAtRow:(NSUInteger)rowIndex column:(NSUInteger)columnIndex
{
// If an edited row exists at the supplied index, check it for a NULL.
NSMutableArray *editedRow = SPDataStorageGetEditedRow(editedRows, rowIndex);
if (editedRow != NULL) {
return [(id)CFArrayGetValueAtIndex((CFArrayRef)editedRow, columnIndex) isNSNull];
if (rowIndex < editedRowCount) {
NSMutableArray *editedRow = SPDataStorageGetEditedRow(editedRows, rowIndex);
if (editedRow != NULL) {
return [(id)CFArrayGetValueAtIndex((CFArrayRef)editedRow, columnIndex) isNSNull];
}
}
// Throw an exception if the column index is out of bounds
@@ -204,13 +216,17 @@ - (BOOL) cellIsNullOrUnloadedAtRow:(NSUInteger)rowIndex column:(NSUInteger)colum
*/
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len
{
NSMutableArray *targetRow = NULL;
// If the start index is out of bounds, return 0 to indicate end of results
if (state->state >= SPMySQLResultStoreGetRowCount(dataStorage)) return 0;
// If an edited row exists for the supplied index, use that; otherwise use the underlying
// storage row
NSMutableArray *targetRow = SPDataStorageGetEditedRow(editedRows, state->state);
if (state->state < editedRowCount) {
targetRow = SPDataStorageGetEditedRow(editedRows, state->state);
}
if (targetRow == NULL) {
targetRow = SPMySQLResultStoreGetRow(dataStorage, state->state);
@@ -248,6 +264,7 @@ - (void) addRowWithContents:(NSMutableArray *)aRow
// Add the new row to the editable store
[editedRows addPointer:aRow];
editedRowCount++;
// Update the underlying store as well to keep counts correct
[dataStorage addDummyRow];
@@ -277,6 +294,7 @@ - (void) insertRowContents:(NSMutableArray *)aRow atIndex:(NSUInteger)anIndex
// Add the new row to the editable store
[editedRows insertPointer:aRow atIndex:anIndex];
editedRowCount++;
// Update the underlying store to keep counts and indices correct
[dataStorage insertDummyRowAtIndex:anIndex];
@@ -296,9 +314,13 @@ - (void) replaceRowAtIndex:(NSUInteger)anIndex withRowContents:(NSMutableArray *
*/
- (void) replaceObjectInRow:(NSUInteger)rowIndex column:(NSUInteger)columnIndex withObject:(id)anObject
{
NSMutableArray *editableRow = NULL;
if (rowIndex < editedRowCount) {
editableRow = SPDataStorageGetEditedRow(editedRows, rowIndex);
}
// Make sure that the row in question is editable
NSMutableArray *editableRow = SPDataStorageGetEditedRow(editedRows, rowIndex);
if (editableRow == NULL) {
editableRow = [self rowContentsAtIndex:rowIndex];
[editedRows replacePointerAtIndex:rowIndex withPointer:editableRow];
@@ -320,7 +342,9 @@ - (void) removeRowAtIndex:(NSUInteger)anIndex
}
// Remove the row from the edited list and underlying storage
[editedRows removePointerAtIndex:anIndex];
if (anIndex < editedRowCount) {
[editedRows removePointerAtIndex:anIndex];
}
[dataStorage removeRowAtIndex:anIndex];
}
@@ -337,9 +361,10 @@ - (void) removeRowsInRange:(NSRange)rangeToRemove
}
// Remove the rows from the edited list and underlying storage
NSUInteger i = rangeToRemove.location + rangeToRemove.length;
NSUInteger i = MIN(editedRowCount, rangeToRemove.location + rangeToRemove.length);
while (--i >= rangeToRemove.location) {
[editedRows removePointerAtIndex:i];
editedRowCount--;
}
[dataStorage removeRowsInRange:rangeToRemove];
}
@@ -350,6 +375,7 @@ - (void) removeRowsInRange:(NSRange)rangeToRemove
- (void) removeAllRows
{
[editedRows setCount:0];
editedRowCount = 0;
[dataStorage removeAllRows];
}
@@ -400,7 +426,8 @@ - (BOOL) dataDownloaded
*/
- (void)resultStoreDidFinishLoadingData:(SPMySQLStreamingResultStore *)resultStore
{
[editedRows setCount:(NSUInteger)[resultStore numberOfRows]];
editedRowCount = [resultStore numberOfRows];
[editedRows setCount:editedRowCount];
}
/**
@@ -415,6 +442,7 @@ - (id) init {
unloadedColumns = NULL;
numberOfColumns = 0;
editedRowCount = 0;
}
return self;
}

0 comments on commit 1d8db00

Please sign in to comment.