1
1
unit Generate.Common;
2
2
3
+ { $IFDEF FPC}
3
4
{ $mode ObjFPC}{ $H+}
5
+ { $ENDIF}
4
6
5
7
interface
6
8
7
9
uses
8
10
Classes
9
11
, SysUtils
10
- , streamex
12
+ { $IFDEF FPC}
13
+ { $ELSE}
14
+ { $ENDIF}
11
15
;
12
16
13
17
const
@@ -41,12 +45,21 @@ TGenerator = class(TObject)
41
45
implementation
42
46
43
47
uses
44
- Math,
45
- bufstream
48
+ Math
49
+ { $IFDEF FPC}
50
+ , streamex
51
+ , bufstream
52
+ { $ELSE}
53
+ , System.Diagnostics
54
+ { $ENDIF}
46
55
;
47
56
48
57
const
49
- batchPercent = 10 ;
58
+ linesPercent = 10 ;
59
+ stationsCapacity = 50000 ;
60
+ chunkBatch = 10000 ;
61
+ chunkCapacity = 20 * 1024 * 1024 ;
62
+ lineEnding = #13 #10 ;
50
63
51
64
{ TGenerator }
52
65
@@ -61,8 +74,7 @@ constructor TGenerator.Create(
61
74
FLineCount:= ALineCount;
62
75
63
76
FStationNames:= TStringList.Create;
64
- FStationNames.Capacity:= 50000 ;
65
- // FStationNames.CaseSensitive:= False;
77
+ FStationNames.Capacity:= stationsCapacity;
66
78
FStationNames.UseLocale:= False;
67
79
FStationNames.Duplicates:= dupIgnore;
68
80
FStationNames.Sorted:= True;
@@ -80,7 +92,7 @@ procedure TGenerator.BuildStationNames;
80
92
streamReader: TStreamReader;
81
93
entry: String;
82
94
count: Int64 = 0 ;
83
- start, stop: QWord ;
95
+ start, stop: Int64 ;
84
96
begin
85
97
WriteLn(' Building Weather Stations...' );
86
98
// Load the Weather Station names
@@ -90,19 +102,27 @@ procedure TGenerator.BuildStationNames;
90
102
try
91
103
streamReader:= TStreamReader.Create(inputStream);
92
104
try
105
+ { $IFDEF FPC}
93
106
start:= GetTickCount64;
94
107
while not streamReader.Eof do
108
+ { $ELSE}
109
+ start := TStopwatch.GetTimeStamp;
110
+ while not streamReader.EndOfStream do
111
+ { $ENDIF}
95
112
begin
96
113
entry:= streamReader.ReadLine;
97
114
if entry[1 ] <> ' #' then
98
115
begin
99
116
entry:= entry.Split(' ;' )[0 ];
100
117
FStationNames.Add(entry);
101
- // WriteLn('Got: ', entry);
102
118
Inc(count);
103
119
end ;
104
120
end ;
121
+ { $IFDEF FPC}
105
122
stop:= GetTickCount64;
123
+ { $ELSE}
124
+ stop := TStopwatch.GetTimeStamp;
125
+ { $ENDIF}
106
126
finally
107
127
streamReader.Free;
108
128
end ;
@@ -149,12 +169,11 @@ procedure TGenerator.Generate;
149
169
stationId: Int64;
150
170
randomTemp: Integer;
151
171
randomTempStr: String[4 ];
152
- outputFileStream: TFileStream;
153
- outputBufWriter: TWriteBufStream;
154
- line, randomTempFinal: String;
172
+ outputFileStream: TBufferedFileStream;
173
+ chunkLine, randomTempFinal: String;
155
174
stationArray, temperatureArray: TStringArray;
156
175
LenStationArray, LenTemperatureArray: Array of Integer;
157
- i, count, len , stationsCount, temperaturesCount: Integer;
176
+ chunkCount, chunkLen , stationsCount, temperaturesCount: Integer;
158
177
start: TDateTime;
159
178
begin
160
179
// Randomize sets this variable depending on the current time
@@ -164,90 +183,88 @@ procedure TGenerator.Generate;
164
183
// Build list of station names
165
184
BuildStationNames;
166
185
167
- outputFileStream:= TFileStream .Create(FOutPutFile, fmCreate);
186
+ outputFileStream:= TBufferedFileStream .Create(FOutPutFile, fmCreate);
168
187
169
- progressBatch:= floor(FLineCount * (batchPercent / 100 ));
188
+ progressBatch:= floor(FLineCount * (linesPercent / 100 ));
170
189
start:= Now;
171
190
191
+ // This is all paweld magic:
192
+ // From here
172
193
// based on code @domasz from lazarus forum, github: PascalVault
173
194
stationsCount := FStationNames.Count;
174
195
SetLength(stationArray, stationsCount);
175
196
SetLength(LenStationArray, stationsCount);
176
- for i := 0 to stationsCount - 1 do
197
+ for index := 0 to stationsCount - 1 do
177
198
begin
178
- stationArray[i ] := FStationNames[i ] + ' ;' ;
179
- LenStationArray[i ] := Length(stationArray[i ]);
199
+ stationArray[index ] := FStationNames[index ] + ' ;' ;
200
+ LenStationArray[index ] := Length(stationArray[index ]);
180
201
end ;
181
202
182
203
temperaturesCount := 1999 ;
183
204
SetLength(temperatureArray, temperaturesCount);
184
205
SetLength(LenTemperatureArray, temperaturesCount);
185
- temperatureArray[0 ] := ' 0.0' + # 13 # 10 ;
206
+ temperatureArray[0 ] := ' 0.0' + lineEnding ;
186
207
LenTemperatureArray[0 ] := Length(temperatureArray[0 ]);
187
- for i := 1 to 999 do
208
+ for index := 1 to 999 do
188
209
begin
189
- randomTempStr := IntToStr(i );
210
+ randomTempStr := IntToStr(index );
190
211
case Ord(randomTempStr[0 ]) of
191
212
1 : randomTempFinal := ' 0.' + randomTempStr;
192
213
2 : randomTempFinal := randomTempStr[1 ] + ' .' + randomTempStr[2 ];
193
214
3 : randomTempFinal := randomTempStr[1 ] + randomTempStr[2 ] + ' .' + randomTempStr[3 ];
194
215
4 : randomTempFinal := randomTempStr[1 ] + randomTempStr[2 ] + randomTempStr[3 ] + ' .' + randomTempStr[4 ];
195
216
end ;
196
- temperatureArray[i * 2 - 1 ] := randomTempFinal + # 13 # 10 ;
197
- LenTemperatureArray[i * 2 - 1 ] := Length(temperatureArray[i * 2 - 1 ]);
198
- temperatureArray[i * 2 ] := ' -' + randomTempFinal + # 13 # 10 ;
199
- LenTemperatureArray[i * 2 ] := LenTemperatureArray[i * 2 - 1 ] + 1 ;
217
+ temperatureArray[index * 2 - 1 ] := randomTempFinal + lineEnding ;
218
+ LenTemperatureArray[index * 2 - 1 ] := Length(temperatureArray[index * 2 - 1 ]);
219
+ temperatureArray[index * 2 ] := ' -' + randomTempFinal + lineEnding ;
220
+ LenTemperatureArray[index * 2 ] := LenTemperatureArray[index * 2 - 1 ] + 1 ;
200
221
end ;
201
- //
202
222
203
- count := 0 ;
204
- len := 0 ;
205
- SetLength(line, 1024 * 1024 * 20 );
223
+ chunkCount := chunkBatch;
224
+ chunkLen := 0 ;
225
+ SetLength(chunkLine, chunkCapacity);
226
+ // To here
206
227
207
228
try
208
- // outputBufWriter:= TWriteBufStream.Create(outputFileStream, 4*1024);
209
- outputBufWriter:= TWriteBufStream.Create(outputFileStream, 64 *1024 );
210
- try
211
- Write(GenerateProgressBar(1 , FLineCount, 50 , 0 , Now - start), #13 );
212
- // Generate the file
213
- for index:= 1 to FLineCount do
214
- begin
215
- stationId:= Random(stationsCount);
216
- // This is all paweld magic:
217
- // From here
218
- randomTemp:= Random(temperaturesCount);
219
- Move(stationArray[stationId][1 ], line[len + 1 ], LenStationArray[stationId]);
220
- Inc(len, LenStationArray[stationId]);
221
- Move(temperatureArray[randomTemp][1 ], line[len + 1 ], LenTemperatureArray[randomTemp]);
222
- Inc(len, LenTemperatureArray[randomTemp]);
229
+ // Print first state of the progress bar
230
+ Write(GenerateProgressBar(1 , FLineCount, 50 , 0 , Now - start), #13 );
231
+ // Generate the file
232
+ for index:= 1 to FLineCount do
233
+ begin
234
+ stationId:= Random(stationsCount);
235
+ // This is all paweld magic:
236
+ // From here
237
+ randomTemp:= Random(temperaturesCount);
238
+ Move(stationArray[stationId][1 ], chunkLine[chunkLen + 1 ], LenStationArray[stationId]);
239
+ Inc(chunkLen, LenStationArray[stationId]);
240
+ Move(temperatureArray[randomTemp][1 ], chunkLine[chunkLen + 1 ], LenTemperatureArray[randomTemp]);
241
+ Inc(chunkLen, LenTemperatureArray[randomTemp]);
223
242
224
- Inc(count);
225
- if count = 10000 then
226
- begin
227
- outputBufWriter.WriteBuffer(line[1 ], len);
228
- count := 0 ;
229
- len := 0 ;
230
- end ;
231
- // To here
232
- Dec(progressBatch);
233
- if progressBatch = 0 then
234
- begin
235
- Write(GenerateProgressBar(
236
- index,
237
- FLineCount,
238
- 50 ,
239
- outputFileStream.Size,
240
- Now - start
241
- ), #13 );
242
- progressBatch:= floor(FLineCount * (batchPercent / 100 ));
243
- end ;
243
+ Dec(chunkCount);
244
+ if chunkCount = 0 then
245
+ begin
246
+ outputFileStream.WriteBuffer(chunkLine[1 ], chunkLen);
247
+ chunkCount := chunkBatch;
248
+ chunkLen := 0 ;
244
249
end ;
245
- if count > 0 then
250
+ // To here
251
+ Dec(progressBatch);
252
+ if progressBatch = 0 then
246
253
begin
247
- outputBufWriter.WriteBuffer(line[1 ], len);
254
+ Write(GenerateProgressBar(
255
+ index,
256
+ FLineCount,
257
+ 50 ,
258
+ outputFileStream.Size,
259
+ Now - start
260
+ ), #13 );
261
+ progressBatch:= floor(FLineCount * (linesPercent / 100 ));
248
262
end ;
249
- finally
250
- outputBufWriter.Free;
263
+ end ;
264
+ if chunkCount > 0 then
265
+ begin
266
+ outputFileStream.WriteBuffer(chunkLine[1 ], chunkLen);
267
+ outputFileStream.Flush;
251
268
end ;
252
269
finally
253
270
WriteLn;
0 commit comments