forked from yavfast/dbg-spider
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCollectList.pas
240 lines (186 loc) · 4.9 KB
/
CollectList.pas
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
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
unit CollectList;
interface
uses Classes, SysUtils, SyncObjs, ClassUtils;
const
_DEF_SEGMENT_SIZE = 16 * 1024;
_SEG_LIST_GROW = 16;
type
TSegment<T> = Array of T;
TSegList<T> = Array of TSegment<T>;
TCollectListError = class(Exception);
PData = Pointer;
TBaseCollectList = class
private
FCount: Integer;
FAddCount: Integer;
FLock: TMREWSync;
protected
FSegLength: Integer;
function GetItem(const Index: Integer): PData; virtual; abstract;
procedure CheckSeg(const Seg: Integer); virtual; abstract;
function IndexToSegment(const Index: Integer; var Seg, Offset: Integer): LongBool;
procedure RaiseError(Msg: PString; const Args: Array of const);
public
constructor Create;
destructor Destroy; override;
function Add: PData; virtual;
procedure Commit; virtual;
procedure Clear; virtual;
procedure BeginRead; inline;
procedure EndRead; inline;
procedure BeginWrite; inline;
procedure EndWrite; inline;
property Count: Integer read FCount;
property Items[const Index: Integer]: PData read GetItem; default;
property Lock: TMREWSync read FLock;
end;
TCollectList<T> = class(TBaseCollectList)
private
FSegList: TSegList<T>;
protected
function GetItem(const Index: Integer): PData; override;
procedure CheckSeg(const Seg: Integer); override;
public
constructor Create(const SegSize: Integer = _DEF_SEGMENT_SIZE);
destructor Destroy; override;
function Add: PData; override;
procedure Clear; override;
end;
//XE6 bug? default AtomicIncrement gives an AV!
function AtomicIncrement(var Target: Integer; Increment: Integer): Integer; overload;
function AtomicIncrement(var Target: Integer): Integer; overload;
implementation
uses
Winapi.Windows;
{ TBaseCollectList }
function AtomicIncrement(var Target: Integer; Increment: Integer): Integer; overload; inline;
begin
Result := InterlockedExchangeAdd(Target, Increment);
end;
function AtomicIncrement(var Target: Integer): Integer; overload; inline;
begin
Result := InterlockedIncrement(Target);
end;
function TBaseCollectList.Add: PData;
begin
Result := Nil;
AtomicIncrement(FAddCount);
end;
procedure TBaseCollectList.Clear;
begin
FCount := 0;
end;
procedure TBaseCollectList.Commit;
begin
BeginWrite;
AtomicIncrement(FCount, FAddCount);
AtomicExchange(FAddCount, 0);
EndWrite;
end;
constructor TBaseCollectList.Create;
begin
inherited;
FCount := 0;
FLock := TMREWSync.Create;
end;
destructor TBaseCollectList.Destroy;
begin
Clear;
FreeAndNil(FLock);
inherited;
end;
procedure TBaseCollectList.BeginRead;
begin
FLock.BeginRead;
end;
procedure TBaseCollectList.BeginWrite;
begin
FLock.BeginWrite;
end;
procedure TBaseCollectList.RaiseError(Msg: PString; const Args: array of const);
begin
raise TCollectListError.CreateFmt(Msg^, Args);
end;
procedure TBaseCollectList.EndRead;
begin
FLock.EndRead;
end;
procedure TBaseCollectList.EndWrite;
begin
FLock.EndWrite;
end;
function TBaseCollectList.IndexToSegment(const Index: Integer; var Seg, Offset: Integer): LongBool;
begin
Result := (Index < FCount) and (Index >= 0);
Seg := Index div FSegLength;
Offset := Index mod FSegLength;
end;
{ TCollectList<T> }
function TCollectList<T>.Add: PData;
var
Seg, Offset: Integer;
NextIdx: Integer;
begin
BeginRead;
// Ðåçåðâèðóåì ñëåäóþùèé ýëåìåíò
NextIdx := FCount + AtomicIncrement(FAddCount) - 1;
// Ïðîâåðÿåì äîñòóïíîñòü ñåãìåíòà
IndexToSegment(NextIdx, Seg, Offset);
CheckSeg(Seg);
// Ïîëó÷àåì óêàçàòåëü íà íîâûé ýëåìåíò
Result := @FSegList[Seg][Offset];
EndRead;
FillChar(Result^, SizeOf(T), 0);
//Initialize(T(Result^));
end;
procedure TCollectList<T>.CheckSeg(const Seg: Integer);
begin
//BeginRead;
if Length(FSegList) <= Seg then
begin
BeginWrite;
SetLength(FSegList, Seg + _SEG_LIST_GROW);
SetLength(FSegList[Seg], FSegLength);
EndWrite;
end;
if Length(FSegList[Seg]) = 0 then
begin
BeginWrite;
SetLength(FSegList[Seg], FSegLength);
EndWrite;
end;
//EndRead;
end;
procedure TCollectList<T>.Clear;
begin
BeginWrite;
inherited Clear;
SetLength(FSegList, 0);
EndWrite;
end;
constructor TCollectList<T>.Create(const SegSize: Integer = _DEF_SEGMENT_SIZE);
begin
inherited Create;
FSegLength := SegSize div SizeOf(T);
SetLength(FSegList, 0);
end;
destructor TCollectList<T>.Destroy;
begin
Clear;
inherited;
end;
function TCollectList<T>.GetItem(const Index: Integer): PData;
var
Seg, Offset: Integer;
begin
Result := nil;
if IndexToSegment(Index, Seg, Offset) then
begin
BeginRead;
Result := @FSegList[Seg][Offset];
EndRead;
end
else
RaiseError(@EIndexError, [Index]);
end;
end.