This repository has been archived by the owner on Jul 7, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathODDS_AND_ENDS
211 lines (174 loc) · 7.49 KB
/
ODDS_AND_ENDS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
/** @taskunit command log */
// in general:
// - base case (this is the only one nested versioning supported):
// - linear undo/redo for a given proot:branch
// = oblivious to branch switches - acts as if you were always working
// on the subject branch even if you switched to other branches and worked on them
// - proot case:
// - linear undo over an entire proot:
// = includes all changes made on all branches.
// = includes creating and deleting branches
// = includes branch switches
// = includes editing metadata (name etc)
// = oblivious to other proots - acts as if you were always working
// on the subject proot even if you switched to other proots and worked on them
// - global case:
// = includes all changes made in a store
//
// think about selective undo UI
// NOTE: this should elegantly solve the "quark undo problem"
// where you have a project editor containing documents,
// and undo/redo on the project editor is expected
/**
random stuff to think about:
- deep copy mergability:
- record what a proot was copied from
- "snapshot" feature that tags state of a proot and all embedded proots?
-
*/
/**
* Relationship cacheing:
* rationale: we only store (and version) one side of a relationship:
* e.g., in a Boss we store a list of the Employees. (one-many relation)
* in a Book we store a list of Tags. (many-many relation)
*
* why? because one side is calculated from the other. if we stored both sides
* it would be easy for one to get out of sync with the other.
*
* to get the boss of an employee, or to get all the books that have a given tag,
* we would have to do a linear scan. to avoid that, we maintain this cache.
*
* note that it is just a discardable/regeneratable cache; not part of the actual
* store data.
*/
/**
* Linear-time version of:
*
* [[arrayA arrayByAddingObjectsFromArray: arrayB] sortedArrayUsingSelector: cmpSel]]
*
* for when the arrays are already sorted.
*/
NSArray *COMergeSortedArraysUsingSelector(NSArray *sortredArrayA, NSArray *sortredArrayB, SEL cmpSel)
{
const NSUInteger arrayACount = [sortredArrayA count];
const NSUInteger arrayBCount = [sortredArrayB count];
NSMutableArray *result = [NSMutableArray arrayWithCapacity: arrayACount + arrayBCount];
NSUInteger arrayAIndex = 0;
NSUInteger arrayBIndex = 0;
while (arrayAIndex < arrayACount || arrayBIndex < arrayBCount)
{
if (arrayAIndex == arrayACount)
{
[result addObject: [sortredArrayB objectAtIndex: arrayBIndex++]];
}
else if (arrayBIndex == arrayBCount)
{
[result addObject: [sortredArrayA objectAtIndex: arrayAIndex++]];
}
else
{
id arrayAElement = [sortredArrayA objectAtIndex: arrayAIndex];
id arrayBElement = [sortredArrayB objectAtIndex: arrayBIndex];
IMP cmpImp = [arrayAElement methodForSelector: cmpSel];
NSComparisonResult cmpResult = ((NSComparisonResult (*)(id, SEL, id))cmpImp)(arrayAElement, cmpSel, arrayBElement);
if (cmpResult == NSOrderedAscending || cmpResult == NSOrderedSame)
{
[result addObject: arrayAElement];
[result addObject: arrayBElement];
}
else if (cmpResult == NSOrderedDescending)
{
[result addObject: arrayBElement];
[result addObject: arrayAElement];
}
else
{
[NSException raise: NSInternalInconsistencyException
format: @"comparison method returned invalid value"];
}
arrayAIndex++;
arrayBIndex++;
}
}
return result;
}
#define NUM 100
#define RUNS 1
- (void) testUUIDPerf
{
COUUID *uuids[NUM];
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity: NUM];
for (int i=0; i<NUM;i++) {
uuids[i] = [COUUID UUID];
[dict setObject: uuids[i] forKey: uuids[i]];
}
{
NSMutableArray *result = [NSMutableArray arrayWithCapacity: NUM];
NSDate *s1 = [NSDate date];
for (int j=0; j<RUNS; j++) {
for (int i=0; i<NUM;i++) {
[result addObject: uuids[i]];
}
[result removeAllObjects];
}
NSLog(@"Adding %d UUIDS to array %d times took %lf ms", NUM, RUNS, 1000.0 * [s1 timeIntervalSinceNow]);
NSLog(@"%@", result);
}
{
NSMutableArray *result = [NSMutableArray arrayWithCapacity: NUM];
NSDate *s1 = [NSDate date];
for (int j=0; j<RUNS; j++) {
for (int i=0; i<NUM;i++) {
[result addObject: [dict objectForKey: uuids[i]]];
}
[result removeAllObjects];
}
NSLog(@"Adding %d UUIDS to array %d times with lookup took %lf ms", NUM, RUNS, 1000.0 * [s1 timeIntervalSinceNow]);
NSLog(@"%@", result);
}
}
2013-06-23 22:31:28.929 test[47808:503] Adding 100 UUIDS to array 1 times took -0.014007 ms
2013-06-23 22:31:28.930 test[47808:503] (
)
2013-06-23 22:31:28.930 test[47808:503] Adding 100 UUIDS to array 1 times with lookup took -0.036001 ms
another run:
2013-06-23 22:35:48.953 test[47946:303] Adding 100 UUIDS to array 1 times took -0.015020 ms
2013-06-23 22:35:48.954 test[47946:303] (
)
2013-06-23 22:35:48.954 test[47946:303] Adding 100 UUIDS to array 1 times with lookup took -0.016987 ms
Old TODO list
=============
[ ] (Mar 31/2012) implement "concatenate" operation for COSubtreeDiff
[ ] (Feb 15/2012) work out merge metadata. is attempting to be concious of individual cherry-picked
commits worthwhile? is it going to work?
[ ] (Feb 15/2012) decide what to do about merge conflicts. concerns to resolve:
- only providing "choosing between hunks in a COSequenceDiff" is not
sufficient for conflict resolution.
+ user might need to make manual changes to correctly resolve the change
+ the granularity that makes sense could differ depending on application
(some might make sense to make hunk-level accept/reject resolution,
others might be picking between object A with all edits applied and object B)
- seems good to be able to switch branches while there are conflicts pending resolution on dev branch,
continue working on stable branch, and return to dev branch later to complete the merge
- When conflict resolution is complete, we want "1 commit" on the "target branch"
with special metadata saying it represents commits X through Y from the "source branch"
cherry-picked onto the target branch.
- anything else...?
[ ] (Feb 15/2012) StoreBrowser: implement persistent root diff window, including showing changes in
nested persistent roots, and showing conflicts
[ ] (Feb 11/2012) add a feature like Quentin's COSCustomTrack. of particular interest
would be a "local undo" - linear undo/redo on all objects in a persistent
root _except_ the current versions of branches would be unaltered.
this would support the QuArK-explorer use case, of
undo/redo in the project window which doesn't affect the versions of the
embedded documents.
[ ] (Feb 8/2012) add code to search for all _different_ (i.e. curentVersion not same)
branches of a given persistent root, for making a UI summary
[ ] (Feb 8/2012) add support for merging changes from the store into an editing
context's in-memory tree, (in particular for when a commit is
made on a nested persistent root while a context stays open on
one of its parents) so all of the ugly "reopen context"
code in the tests can be removed.
[ ] (Nov 30/2011) investigate a lazy loading/faulting api
[ ] (dec 5) search
[ ] migrate to sqlite