diff --git a/entries/rlawson/src/parser.pas b/entries/rlawson/src/parser.pas index 87b6250..c1d3e97 100644 --- a/entries/rlawson/src/parser.pas +++ b/entries/rlawson/src/parser.pas @@ -5,7 +5,7 @@ interface uses - Classes, SysUtils, bufstream, Contnrs, Math; + Classes, SysUtils, bufstream, Contnrs, Math, util; procedure ReadMeasurements(inputFile: string); @@ -44,12 +44,12 @@ procedure ProcessMeasurements(var buffer: array of char; bufferLength: integer; begin while idx < (bufferLength - 1) do begin - // read the city until separator - //city := ''; + // read the city by looking for semicolon + city := ''; cityStart := idx; while buffer[idx] <> REC_SEP do Inc(idx); SetString(city, @buffer[cityStart], (idx - cityStart)); - // increment through temp reading and calculate integer temp (*100) + // parse the temp reading Inc(idx); // move pointer past the ; currentTempSign := 1; // check for negative sign, if so flag the multiplier and then move past neg sign @@ -59,20 +59,16 @@ procedure ProcessMeasurements(var buffer: array of char; bufferLength: integer; Inc(idx); end; // look ahead - is decimal point 2 spaces away then we have two digits + temp := 0; if buffer[idx + 2] = DECIMAL_POINT then begin - temp := currentTempSign * (100 * byte(buffer[idx]) + 10 * - byte(buffer[idx + 1]) + byte(buffer[idx + 2]) - 5328); - // move past digits and CRLF and position pointer to first character of next record - idx := idx + 6; - end - else - begin - temp := currentTempSign * (10 * byte(buffer[idx + 1]) + - byte(buffer[idx + 2]) - 528); - // move past digits and CRLF and position pointer to first character of next record - idx := idx + 5; + temp := 100 * (byte(buffer[idx]) - ANSI_ZERO); + Inc(idx); end; + temp := temp + 10 * (byte(buffer[idx]) - ANSI_ZERO); + idx := idx + 2; + temp := currentTempSign * (temp + (byte(buffer[idx]) - ANSI_ZERO)); + idx := idx + 3; reading := results.Find(city); if reading = nil then begin @@ -94,51 +90,6 @@ procedure ProcessMeasurements(var buffer: array of char; bufferLength: integer; end; end; -function PascalRound(x: double): double; -var - t: double; -begin - //round towards positive infinity - t := Trunc(x); - if (x < 0.0) and (t - x = 0.5) then - begin - // Do nothing - end - else if Abs(x - t) >= 0.5 then - begin - t := t + Math.Sign(x); - end; - - if t = 0.0 then - Result := 0.0 - else - Result := t; -end; - - -function RoundEx(x: double): double; -begin - Result := PascalRound(x * 10.0) / 10.0; -end; - -function Compare(AList: TStringList; AIndex1, AIndex2: integer): integer; -var - Pos1, Pos2: integer; - Str1, Str2: string; -begin - Result := 0; - Str1 := AList.Strings[AIndex1]; - Str2 := AList.Strings[AIndex2]; - Pos1 := Pos('=', Str1); - Pos2 := Pos('=', Str2); - if (Pos1 > 0) and (Pos2 > 0) then - begin - Str1 := Copy(Str1, 1, Pos1 - 1); - Str2 := Copy(Str2, 1, Pos2 - 1); - Result := CompareStr(Str1, Str2); - end; -end; - procedure DumpMeasurements(results: TFPHashList); var i: integer; @@ -160,11 +111,6 @@ procedure DumpMeasurements(results: TFPHashList); mean := RoundEx(reading^.total / reading^.numReadings / 10); readingStr := reading^.city + '=' + FormatFloat('0.0', min) + '/' + FormatFloat('0.0', mean) + '/' + FormatFloat('0.0', max); - {$IFDEF DEBUG} - readingStr := reading^.city + '=' + FormatFloat('0.0', min) + - '/' + FormatFloat('0.0', mean) + '/' + FormatFloat('0.0', max) + - '/' + IntToStr(reading^.total) + '/' + IntToStr(reading^.numReadings); - {$ENDIF} weatherStationList.Add(readingStr); Dispose(reading); end; @@ -183,29 +129,6 @@ procedure DumpMeasurements(results: TFPHashList); WriteLn('}'); end; - -procedure DumpExceptionCallStack(E: Exception); -var - I: integer; - Frames: PPointer; - Report: string; -begin - Report := 'Program exception! ' + LineEnding + 'Stacktrace:' + - LineEnding + LineEnding; - if E <> nil then - begin - Report := Report + 'Exception class: ' + E.ClassName + LineEnding + - 'Message: ' + E.Message + LineEnding; - end; - Report := Report + BackTraceStrFunc(ExceptAddr); - Frames := ExceptFrames; - for I := 0 to ExceptFrameCount - 1 do - Report := Report + LineEnding + BackTraceStrFunc(Frames[I]); - WriteLn(Report); - Halt; // End of program execution -end; - - procedure ReadMeasurements(inputFile: string); var totalBytesRead, BytesRead: int64; @@ -213,10 +136,7 @@ procedure ReadMeasurements(inputFile: string); FileStream: TFileStream; fileSize: int64; ReadBufferStream: TReadBufStream; - starttime: uint64; - elapsedTimeSec, MBRead: double; results: TFPHashList; - currentChar: char; idx: integer; startOfNextRecord: string; startOfNextRecordLength: integer; @@ -228,50 +148,29 @@ procedure ReadMeasurements(inputFile: string); ReadBufferStream := TReadBufStream.Create(FileStream); fileSize := FileStream.size; totalBytesRead := 0; - starttime := GetTickCount64; results := TFPHashList.Create; startOfNextRecord := ''; while totalBytesRead <= fileSize do // While the amount of data read is less than or equal to the size of the stream do begin startOfNextRecordLength := Length(startOfNextRecord); - //WriteLn('startOfNextRecordLength: ', startOfNextRecordLength); // if we have leftover from previous read then prepend it to this buffer if startOfNextRecordLength > 0 then Move(PChar(startOfNextRecord)^, Buffer[0], startOfNextRecordLength); BytesRead := ReadBufferStream.Read(Buffer[startOfNextRecordLength], READ_SIZE); - //WriteLn('Bytes read: ', BytesRead); if BytesRead < 1 then break; // now look in buffer backwards until we find the first LF bufferLength := startOfNextRecordLength + BytesRead; idx := bufferLength - 1; - currentChar := buffer[idx]; - while (currentChar <> LF) do - begin - Dec(idx); - currentChar := buffer[idx]; - end; + while (buffer[idx] <> LF) do Dec(idx); ProcessMeasurements(Buffer, idx + 1, results); startOfNextRecord := ''; startOfNextRecordLength := bufferLength - idx - 1; - //WriteLn('startOfNextRecordLength: ', startOfNextRecordLength); if startOfNextRecordLength > 0 then SetString(startOfNextRecord, @buffer[idx + 1], startOfNextRecordLength); Inc(totalBytesRead, BytesRead); end; DumpMeasurements(results); - elapsedTimeSec := (GetTickCount64() - starttime) / 1000; - MBRead := (totalBytesRead / (1024 * 1024)); - {$IFDEF DEBUG} - WriteLn(inputFile); - WriteLn('Buffer size: ', SizeOf(Buffer)); - WriteLn('Read size: ', READ_SIZE); - WriteLn('File size: ', FileStream.Size); - WriteLn('Total Bytes Read: ', totalBytesRead); - WriteLn(Format('%f MB read', [MBRead])); - WriteLn(Format('%f secs', [elapsedTimeSec])); - WriteLn(Format('%f MB/s processed', [MBRead / elapsedTimeSec])); - {$ENDIF} ReadBufferStream.Free; FileStream.Free; results.Free; diff --git a/entries/rlawson/src/util.pas b/entries/rlawson/src/util.pas new file mode 100644 index 0000000..2537419 --- /dev/null +++ b/entries/rlawson/src/util.pas @@ -0,0 +1,82 @@ +unit util; + +{$mode ObjFPC}{$H+} + +interface + +uses + Classes, SysUtils, Math; + +procedure DumpExceptionCallStack(E: Exception); +function RoundEx(x: double): double; +function Compare(AList: TStringList; AIndex1, AIndex2: integer): integer; + +implementation + +procedure DumpExceptionCallStack(E: Exception); +var + I: integer; + Frames: PPointer; + Report: string; +begin + Report := 'Program exception! ' + LineEnding + 'Stacktrace:' + + LineEnding + LineEnding; + if E <> nil then + begin + Report := Report + 'Exception class: ' + E.ClassName + LineEnding + + 'Message: ' + E.Message + LineEnding; + end; + Report := Report + BackTraceStrFunc(ExceptAddr); + Frames := ExceptFrames; + for I := 0 to ExceptFrameCount - 1 do + Report := Report + LineEnding + BackTraceStrFunc(Frames[I]); + WriteLn(Report); + Halt; // End of program execution +end; + +function PascalRound(x: double): double; +var + t: double; +begin + //round towards positive infinity + t := Trunc(x); + if (x < 0.0) and (t - x = 0.5) then + begin + // Do nothing + end + else if Abs(x - t) >= 0.5 then + begin + t := t + Math.Sign(x); + end; + + if t = 0.0 then + Result := 0.0 + else + Result := t; +end; + + +function RoundEx(x: double): double; +begin + Result := PascalRound(x * 10.0) / 10.0; +end; + +function Compare(AList: TStringList; AIndex1, AIndex2: integer): integer; +var + Pos1, Pos2: integer; + Str1, Str2: string; +begin + Result := 0; + Str1 := AList.Strings[AIndex1]; + Str2 := AList.Strings[AIndex2]; + Pos1 := Pos('=', Str1); + Pos2 := Pos('=', Str2); + if (Pos1 > 0) and (Pos2 > 0) then + begin + Str1 := Copy(Str1, 1, Pos1 - 1); + Str2 := Copy(Str2, 1, Pos2 - 1); + Result := CompareStr(Str1, Str2); + end; +end; + +end. diff --git a/entries/rlawson/src/weather.lpi b/entries/rlawson/src/weather.lpi index 5e316f3..1d6b891 100644 --- a/entries/rlawson/src/weather.lpi +++ b/entries/rlawson/src/weather.lpi @@ -83,7 +83,7 @@ - + @@ -92,6 +92,10 @@ + + + + diff --git a/entries/rlawson/src/weather.lpr b/entries/rlawson/src/weather.lpr index e47ca4d..1e897af 100644 --- a/entries/rlawson/src/weather.lpr +++ b/entries/rlawson/src/weather.lpr @@ -4,11 +4,12 @@ uses {$IFDEF UNIX} - cthreads, + cmem, cthreads, {$ENDIF} Classes, SysUtils, - CustApp, parser; + CustApp, + parser; type