Skip to content

Commit 2ac2840

Browse files
committed
refactor and cleanup
Fix defect in previous version (math wrong on temps)
1 parent f965506 commit 2ac2840

File tree

4 files changed

+123
-75
lines changed

4 files changed

+123
-75
lines changed

entries/rlawson/src/parser.pas

Lines changed: 33 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
interface
66

77
uses
8-
Classes, SysUtils, bufstream, Contnrs, Math;
8+
Classes, SysUtils, bufstream, Contnrs, Math, util;
99

1010
procedure ReadMeasurements(inputFile: string);
1111

@@ -20,13 +20,16 @@ TCityTemp = record
2020
numReadings: integer;
2121
end;
2222

23+
2324
implementation
2425

2526
const
2627
READ_SIZE = 65536;
2728
// read size plus enough to hold one record if we split it
2829
BUFFER_SIZE = READ_SIZE + 1024;
2930
REC_SEP: char = ';';
31+
LF: char = chr(10);
32+
ANSI_ZERO: integer = 48;
3033
DECIMAL_POINT: char = '.';
3134
NEGATIVE_SIGN: char = '-';
3235

@@ -41,11 +44,12 @@ procedure ProcessMeasurements(var buffer: array of char; bufferLength: integer;
4144
begin
4245
while idx < (bufferLength - 1) do
4346
begin
44-
// read the city until separator
47+
// read the city by looking for semicolon
48+
city := '';
4549
cityStart := idx;
4650
while buffer[idx] <> REC_SEP do Inc(idx);
4751
SetString(city, @buffer[cityStart], (idx - cityStart));
48-
// increment through temp reading and calculate integer temp (*100)
52+
// parse the temp reading
4953
Inc(idx); // move pointer past the ;
5054
currentTempSign := 1;
5155
// check for negative sign, if so flag the multiplier and then move past neg sign
@@ -55,21 +59,16 @@ procedure ProcessMeasurements(var buffer: array of char; bufferLength: integer;
5559
Inc(idx);
5660
end;
5761
// look ahead - is decimal point 2 spaces away then we have two digits
62+
temp := 0;
5863
if buffer[idx + 2] = DECIMAL_POINT then
5964
begin
60-
// this is the math that results from subtracting the byte value of ansi zero from each character
61-
temp := currentTempSign * (100 * byte(buffer[idx]) + 10 *
62-
byte(buffer[idx + 1]) + byte(buffer[idx + 2]) - 5328);
63-
// move past digits and CRLF and position pointer to first character of next record
64-
idx := idx + 6;
65-
end
66-
else
67-
begin
68-
temp := currentTempSign * (10 * byte(buffer[idx + 1]) +
69-
byte(buffer[idx + 2]) - 528);
70-
// move past digits and CRLF and position pointer to first character of next record
71-
idx := idx + 5;
65+
temp := 100 * (byte(buffer[idx]) - ANSI_ZERO);
66+
Inc(idx);
7267
end;
68+
temp := temp + 10 * (byte(buffer[idx]) - ANSI_ZERO);
69+
idx := idx + 2;
70+
temp := currentTempSign * (temp + (byte(buffer[idx]) - ANSI_ZERO));
71+
idx := idx + 3;
7372
reading := results.Find(city);
7473
if reading = nil then
7574
begin
@@ -91,51 +90,6 @@ procedure ProcessMeasurements(var buffer: array of char; bufferLength: integer;
9190
end;
9291
end;
9392

94-
function PascalRound(x: double): double;
95-
var
96-
t: double;
97-
begin
98-
//round towards positive infinity
99-
t := Trunc(x);
100-
if (x < 0.0) and (t - x = 0.5) then
101-
begin
102-
// Do nothing
103-
end
104-
else if Abs(x - t) >= 0.5 then
105-
begin
106-
t := t + Math.Sign(x);
107-
end;
108-
109-
if t = 0.0 then
110-
Result := 0.0
111-
else
112-
Result := t;
113-
end;
114-
115-
116-
function RoundEx(x: double): double;
117-
begin
118-
Result := PascalRound(x * 10.0) / 10.0;
119-
end;
120-
121-
function Compare(AList: TStringList; AIndex1, AIndex2: integer): integer;
122-
var
123-
Pos1, Pos2: integer;
124-
Str1, Str2: string;
125-
begin
126-
Result := 0;
127-
Str1 := AList.Strings[AIndex1];
128-
Str2 := AList.Strings[AIndex2];
129-
Pos1 := Pos('=', Str1);
130-
Pos2 := Pos('=', Str2);
131-
if (Pos1 > 0) and (Pos2 > 0) then
132-
begin
133-
Str1 := Copy(Str1, 1, Pos1 - 1);
134-
Str2 := Copy(Str2, 1, Pos2 - 1);
135-
Result := CompareStr(Str1, Str2);
136-
end;
137-
end;
138-
13993
procedure DumpMeasurements(results: TFPHashList);
14094
var
14195
i: integer;
@@ -147,6 +101,7 @@ procedure DumpMeasurements(results: TFPHashList);
147101
weatherStationList: TStringList;
148102
isFirstKey: boolean = True;
149103
begin
104+
//WriteLn(results.Count);
150105
weatherStationList := TStringList.Create;
151106
for i := 0 to results.Count - 1 do
152107
begin
@@ -163,21 +118,23 @@ procedure DumpMeasurements(results: TFPHashList);
163118
Write('{');
164119
for ws in weatherStationList do
165120
begin
121+
// If it's not the first key, print a comma
166122
if not isFirstKey then
167123
Write(', ');
124+
// Print the weather station and the temp stat
168125
Write(ws);
126+
// Set isFirstKey to False after printing the first key
169127
isFirstKey := False;
170128
end;
171129
WriteLn('}');
172130
end;
173131

174132
procedure ReadMeasurements(inputFile: string);
175-
type
176-
TCharArray = array of char;
177133
var
178-
BytesRead: int64;
179-
buffer: TCharArray;
134+
totalBytesRead, BytesRead: int64;
135+
Buffer: array [0..BUFFER_SIZE] of char;
180136
FileStream: TFileStream;
137+
fileSize: int64;
181138
ReadBufferStream: TReadBufStream;
182139
results: TFPHashList;
183140
idx: integer;
@@ -186,29 +143,32 @@ procedure ReadMeasurements(inputFile: string);
186143
bufferLength: integer = 0;
187144
begin
188145
try
189-
buffer := Default(TCharArray);
190-
SetLength(buffer, BUFFER_SIZE);
191146
FileStream := TFileStream.Create(inputFile, fmOpenRead);
192-
FileStream.Position := 0;
147+
FileStream.Position := 0; // Ensure you are at the start of the file
193148
ReadBufferStream := TReadBufStream.Create(FileStream);
149+
fileSize := FileStream.size;
150+
totalBytesRead := 0;
194151
results := TFPHashList.Create;
195152
startOfNextRecord := '';
196-
while True do
153+
while totalBytesRead <= fileSize do
154+
// While the amount of data read is less than or equal to the size of the stream do
197155
begin
198156
startOfNextRecordLength := Length(startOfNextRecord);
199157
// if we have leftover from previous read then prepend it to this buffer
200158
if startOfNextRecordLength > 0 then
201-
Move(PChar(startOfNextRecord)^, buffer[0], startOfNextRecordLength);
202-
BytesRead := ReadBufferStream.Read(buffer[startOfNextRecordLength], READ_SIZE);
159+
Move(PChar(startOfNextRecord)^, Buffer[0], startOfNextRecordLength);
160+
BytesRead := ReadBufferStream.Read(Buffer[startOfNextRecordLength], READ_SIZE);
203161
if BytesRead < 1 then break;
204162
// now look in buffer backwards until we find the first LF
205163
bufferLength := startOfNextRecordLength + BytesRead;
206164
idx := bufferLength - 1;
207-
while (buffer[idx] <> REC_SEP) do Inc(idx);
208-
ProcessMeasurements(buffer, idx + 1, results);
165+
while (buffer[idx] <> LF) do Dec(idx);
166+
ProcessMeasurements(Buffer, idx + 1, results);
167+
startOfNextRecord := '';
209168
startOfNextRecordLength := bufferLength - idx - 1;
210169
if startOfNextRecordLength > 0 then
211170
SetString(startOfNextRecord, @buffer[idx + 1], startOfNextRecordLength);
171+
Inc(totalBytesRead, BytesRead);
212172
end;
213173
DumpMeasurements(results);
214174
ReadBufferStream.Free;
@@ -218,6 +178,7 @@ procedure ReadMeasurements(inputFile: string);
218178
on E: Exception do
219179
begin
220180
writeln('File ', inputFile, ' could not be read or written because: ', E.ToString);
181+
DumpExceptionCallStack(E);
221182
end;
222183
end;
223184
end;

entries/rlawson/src/util.pas

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
unit util;
2+
3+
{$mode ObjFPC}{$H+}
4+
5+
interface
6+
7+
uses
8+
Classes, SysUtils, Math;
9+
10+
procedure DumpExceptionCallStack(E: Exception);
11+
function RoundEx(x: double): double;
12+
function Compare(AList: TStringList; AIndex1, AIndex2: integer): integer;
13+
14+
implementation
15+
16+
procedure DumpExceptionCallStack(E: Exception);
17+
var
18+
I: integer;
19+
Frames: PPointer;
20+
Report: string;
21+
begin
22+
Report := 'Program exception! ' + LineEnding + 'Stacktrace:' +
23+
LineEnding + LineEnding;
24+
if E <> nil then
25+
begin
26+
Report := Report + 'Exception class: ' + E.ClassName + LineEnding +
27+
'Message: ' + E.Message + LineEnding;
28+
end;
29+
Report := Report + BackTraceStrFunc(ExceptAddr);
30+
Frames := ExceptFrames;
31+
for I := 0 to ExceptFrameCount - 1 do
32+
Report := Report + LineEnding + BackTraceStrFunc(Frames[I]);
33+
WriteLn(Report);
34+
Halt; // End of program execution
35+
end;
36+
37+
function PascalRound(x: double): double;
38+
var
39+
t: double;
40+
begin
41+
//round towards positive infinity
42+
t := Trunc(x);
43+
if (x < 0.0) and (t - x = 0.5) then
44+
begin
45+
// Do nothing
46+
end
47+
else if Abs(x - t) >= 0.5 then
48+
begin
49+
t := t + Math.Sign(x);
50+
end;
51+
52+
if t = 0.0 then
53+
Result := 0.0
54+
else
55+
Result := t;
56+
end;
57+
58+
59+
function RoundEx(x: double): double;
60+
begin
61+
Result := PascalRound(x * 10.0) / 10.0;
62+
end;
63+
64+
function Compare(AList: TStringList; AIndex1, AIndex2: integer): integer;
65+
var
66+
Pos1, Pos2: integer;
67+
Str1, Str2: string;
68+
begin
69+
Result := 0;
70+
Str1 := AList.Strings[AIndex1];
71+
Str2 := AList.Strings[AIndex2];
72+
Pos1 := Pos('=', Str1);
73+
Pos2 := Pos('=', Str2);
74+
if (Pos1 > 0) and (Pos2 > 0) then
75+
begin
76+
Str1 := Copy(Str1, 1, Pos1 - 1);
77+
Str2 := Copy(Str2, 1, Pos2 - 1);
78+
Result := CompareStr(Str1, Str2);
79+
end;
80+
end;
81+
82+
end.

entries/rlawson/src/weather.lpi

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@
8383
<RunParams>
8484
<FormatVersion Value="2"/>
8585
</RunParams>
86-
<Units Count="2">
86+
<Units Count="3">
8787
<Unit0>
8888
<Filename Value="weather.lpr"/>
8989
<IsPartOfProject Value="True"/>
@@ -92,6 +92,10 @@
9292
<Filename Value="parser.pas"/>
9393
<IsPartOfProject Value="True"/>
9494
</Unit1>
95+
<Unit2>
96+
<Filename Value="util.pas"/>
97+
<IsPartOfProject Value="True"/>
98+
</Unit2>
9599
</Units>
96100
</ProjectOptions>
97101
<CompilerOptions>

entries/rlawson/src/weather.lpr

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44

55
uses
66
{$IFDEF UNIX}
7-
cthreads,
7+
cthreads, cmem,
88
{$ENDIF}
99
Classes,
1010
SysUtils,
11-
CustApp, parser;
11+
CustApp,
12+
parser;
1213

1314
type
1415

0 commit comments

Comments
 (0)