Skip to content

Commit 151a313

Browse files
authored
Merge pull request #97 from dtpfl/main
v1 entry
2 parents c3ebbee + ce4373f commit 151a313

File tree

3 files changed

+1310
-0
lines changed

3 files changed

+1310
-0
lines changed

entries/dtoepfl/README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# General
2+
3+
1. Be sure there is a valid measurements is available in .\data\measurements.txt !
4+
2. Open this project in Delphi
5+
3. Compile it as release!
6+
4. Execute the application (.\bin\dtpfl_1brc.dtoepfl-win-64.exe) as followed:
7+
```
8+
.\bin\dtpfl_1brc.dtoepfl-win-64.exe -i ..\data\measurements.txt
9+
```
10+
11+
## Acknowledgements
12+
13+
Thanks to [Gustavo 'Gus' Carreno](https://github.com/gcarreno) & [georges-hatem](https://github.com/georges-hatem)
14+
15+

entries/dtoepfl/src/dtpfl_1brc.dpr

Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
program dtpfl_1brc;
2+
3+
{$APPTYPE CONSOLE}
4+
{$R *.res}
5+
6+
uses
7+
System.SysUtils,
8+
System.StrUtils,
9+
System.IOUtils,
10+
System.Classes,
11+
System.TimeSpan,
12+
System.Generics.Collections,
13+
System.Diagnostics,
14+
generate.console in '..\..\..\generator\Common\generate.console.pas';
15+
16+
type TAlgorithm = (v1, v2, Count);
17+
var algorithm: TAlgorithm;
18+
FormatSettings: TFormatSettings;
19+
const paramPrefix = '--';
20+
paramPrefixShort = '-';
21+
22+
function Ceiling(const ANumber: Double): integer;
23+
begin
24+
Result := Trunc(ANumber) + Ord(Frac(ANumber) > 0);
25+
end;
26+
27+
function RoundExDouble(const ATemp: Double): Double;
28+
var
29+
tmp: Double;
30+
begin
31+
tmp:= ATemp * 10;
32+
Result := Ceiling(tmp) / 10;
33+
end;
34+
35+
{$REGION 'v1'}
36+
37+
type TStationEntry = record
38+
min, max, sum: Double;
39+
count: Integer;
40+
end;
41+
42+
/// <summary>Simple algorithm, single-thread</summary>
43+
procedure runV1;
44+
var FileStream: TFileStream;
45+
StreamReader: TStreamReader;
46+
CityTemperatures: TDictionary<String, TStationEntry>; //Station, min, avrg, max
47+
Line: String;
48+
Parts: TArray<String>;
49+
entry: TStationEntry;
50+
value: Double;
51+
begin
52+
CityTemperatures := TDictionary<String, TStationEntry>.Create;
53+
54+
try
55+
FileStream := TFileStream.Create(inputFilename, fmOpenRead or fmShareDenyWrite);
56+
try
57+
StreamReader := TStreamReader.Create(FileStream, TEncoding.UTF8);
58+
59+
// Read the first three bytes to check for UTF-8 BOM
60+
// var NumRead := FileStream.Read(BOM, Length(BOM));
61+
// If the file starts with the UTF-8 BOM, continue as is, otherwise reset the stream position.
62+
// if (NumRead <> Length(BOM)) or (BOM[0] <> $EF) or (BOM[1] <> $BB) or (BOM[2] <> $BF) then
63+
// begin
64+
// FileStream.Position := 0; // Reset the position if no BOM or not a UTF-8 BOM
65+
// end;
66+
67+
try
68+
while not StreamReader.EndOfStream do
69+
begin
70+
Line := StreamReader.ReadLine;
71+
Parts := SplitString(Line, ';');
72+
if (TryStrToFloat(Parts[1], value, FormatSettings)) then
73+
begin
74+
if (CityTemperatures.ContainsKey(Parts[0])) then
75+
begin
76+
entry := CityTemperatures[Parts[0]];
77+
78+
if (value < entry.min) then //min
79+
entry.min := value;
80+
81+
entry.sum := (entry.sum + value); //average
82+
entry.count := entry.count + 1;
83+
84+
if (value > entry.max) then //max
85+
entry.max := value;
86+
87+
CityTemperatures[Parts[0]] := entry;
88+
end
89+
else
90+
begin
91+
entry.min := value;
92+
entry.count := 1;
93+
entry.sum := value;
94+
entry.max := value;
95+
CityTemperatures.Add(Parts[0], entry);
96+
end;
97+
end;
98+
end;
99+
100+
101+
//Sorted output
102+
var SortedKeys := TList<String>.Create(CityTemperatures.Keys);
103+
SortedKeys.Sort;
104+
var i := 0;
105+
{$IFDEF DEBUG}
106+
var vStream := TStringStream.Create('', TEncoding.UTF8);
107+
{$ENDIF}
108+
try
109+
for var Key in SortedKeys do
110+
begin
111+
112+
// Windows will mess up the characters when outputting to STDOUT.
113+
// for debug purposes, we'll output it to a file instead.
114+
//https://github.com/gcarreno/1brc-ObjectPascal/blob/main/baseline/Common/baseline.delphi.pas @https://github.com/georges-hatem
115+
{$IFDEF DEBUG}
116+
if (i = 0) then
117+
vStream.WriteString('{');
118+
119+
vStream.WriteString(Format('%s=%.1f/%.1f/%.1f', [key, CityTemperatures[key].min, RoundExDouble(CityTemperatures[key].sum / CityTemperatures[key].count), CityTemperatures[key].max], FormatSettings));
120+
121+
if (i = CityTemperatures.Count-1) then
122+
vStream.WriteString('}' + #10)
123+
else
124+
vStream.WriteString(', ');
125+
126+
{$ELSE}
127+
if (i = 0) then
128+
Write('{');
129+
130+
Write(Format('%s=%.1f/%.1f/%.1f', [key, CityTemperatures[key].min, RoundExDouble(CityTemperatures[key].sum / CityTemperatures[key].count), CityTemperatures[key].max], FormatSettings));
131+
132+
if (i = CityTemperatures.Count-1) then
133+
Write('}' + #10)
134+
else
135+
Write(', ');
136+
{$ENDIF}
137+
138+
Inc(i);
139+
end;
140+
141+
{$IFDEF DEBUG}
142+
vStream.SaveToFile('output.txt');
143+
{$ENDIF}
144+
145+
finally
146+
{$IFDEF DEBUG}
147+
vStream.Free;
148+
{$ENDIF}
149+
end;
150+
151+
finally
152+
StreamReader.Free;
153+
end;
154+
finally
155+
FileStream.Free;
156+
end;
157+
finally
158+
CityTemperatures.Free;
159+
end;
160+
end;
161+
{$ENDREGION}
162+
163+
{$REGION 'v2'}
164+
procedure runV2;
165+
begin
166+
raise Exception.Create('v2 not implemented yet!');
167+
end;
168+
{$ENDREGION}
169+
170+
function TryGetParamValue(index: Int8): String;
171+
begin
172+
try
173+
Result := ParamStr(index + 1).ToLower
174+
except on e:exception do
175+
raise Exception.Create('Invalid parameter for ' + ParamStr(index) + sLineBreak + e.Message);
176+
end;
177+
end;
178+
179+
begin
180+
try
181+
FormatSettings := TFormatSettings.Create;
182+
FormatSettings.DecimalSeparator := '.';
183+
184+
{$REGION 'Application Params'}
185+
var Arg: String;
186+
for var i := 1 to ParamCount do
187+
begin
188+
Arg := ParamStr(i).ToLower;
189+
190+
if (Arg = paramPrefixShort + cShortOptions[2]) or
191+
(Arg = paramPrefix + cLongOptions[2]) then //input-file
192+
inputFilename := TryGetParamValue(i);
193+
194+
if (Arg = paramPrefixShort + 'a') or
195+
(Arg = paramPrefix + 'algorithm') then //algorithm
196+
begin
197+
const v = StringReplace(TryGetParamValue(i), 'v', '', [rfReplaceAll]);
198+
199+
var version: Integer;
200+
if (TryStrToInt(v, version)) then
201+
begin
202+
203+
if (Ord(TAlgorithm.Count) = version) then
204+
begin
205+
case version of
206+
1: algorithm := TAlgorithm.v1;
207+
2: algorithm := TAlgorithm.v2;
208+
end;
209+
end
210+
else
211+
raise Exception.Create('Invalid algorithm version!');
212+
213+
end;
214+
end;
215+
end;
216+
217+
//Check if values are valid
218+
if (inputFilename.IsEmpty) then
219+
raise Exception.Create(Format(rsErrorMessage, [ rsMissingInputFlag ]));
220+
221+
inputFilename := ExpandFileName(inputFilename);
222+
{$ENDREGION}
223+
224+
{$IFDEF DEBUG}
225+
WriteLn('The One Billion Row Challenge in Object Pascal');
226+
WriteLn('Source: https://github.com/dtpfl, https://github.com/gcarreno/1brc-ObjectPascal');
227+
WriteLn;
228+
WriteLn(Format(rsInputFile, [ inputFilename ]));
229+
WriteLn(Format('Algorithm: v%d', [Ord(algorithm)+1]));
230+
WriteLn;
231+
232+
var Stopwatch := TStopwatch.StartNew;
233+
{$ENDIF}
234+
235+
if (algorithm = TAlgorithm.v1) then
236+
runV1
237+
else if (algorithm = TAlgorithm.v2) then
238+
runv2;
239+
240+
{$IFDEF DEBUG}
241+
var Elapsed: TTimeSpan := Stopwatch.Elapsed;
242+
Writeln;
243+
Writeln('Elapsed time: ' + FormatFloat('0.000', Elapsed.TotalSeconds) + ' seconds');
244+
{$ENDIF}
245+
except
246+
on E: Exception do
247+
Writeln(E.ClassName, ': ', E.Message);
248+
end;
249+
end.

0 commit comments

Comments
 (0)