55interface
66
77uses
8- Classes, SysUtils, bufstream, Contnrs, Math;
8+ Classes, SysUtils, bufstream, Contnrs, Math, util ;
99
1010procedure ReadMeasurements (inputFile: string);
1111
@@ -20,13 +20,16 @@ TCityTemp = record
2020 numReadings: integer;
2121 end ;
2222
23+
2324implementation
2425
2526const
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;
4144begin
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 ;
9291end ;
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-
13993procedure DumpMeasurements (results: TFPHashList);
14094var
14195 i: integer;
@@ -147,6 +101,7 @@ procedure DumpMeasurements(results: TFPHashList);
147101 weatherStationList: TStringList;
148102 isFirstKey: boolean = True;
149103begin
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(' }' );
172130end ;
173131
174132procedure ReadMeasurements (inputFile: string);
175- type
176- TCharArray = array of char;
177133var
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 ;
187144begin
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 ;
223184end ;
0 commit comments