-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.cpp
150 lines (130 loc) · 3.84 KB
/
main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#include <chrono>
#include <format>
#include <fstream>
#include <iostream>
#include <limits>
#include <ranges>
#include <stdio.h>
#include <string_view>
#include <string>
#include <unordered_map>
// Thanks, I hate it
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <Windows.h>
using namespace std::chrono;
enum class ReadState {
NAME,
TEMPERATURE,
};
struct Station {
double sum = 0;
uint64_t count = 0;
double min = std::numeric_limits<double>::max();
double max = std::numeric_limits<double>::lowest();
};
static double pow(int base, int exp) {
int result = 1;
for (int i = 0; i < exp; ++i) {
result *= base;
}
return result;
}
static double parse_number(const std::string& str) {
if (str.empty()) {
return 0; // whatever for the purposes of this project
}
const char* data = str.data();
size_t data_size = str.size();
int sign = 1;
if (data[0] == '-') {
sign = -1;
++data;
--data_size;
}
static std::vector<int> v; // static for speed, reuse the same vector every time
v.clear();
v.resize(data_size - 2); // only non-fractional part
int e = 0;
bool seen_dot = false;
for (size_t i = 0; i < data_size; ++i) {
if (data[i] == '.') {
seen_dot = true;
continue;
}
if (!seen_dot) {
v[i] = data[i] - 48;
}
else {
e = data[i] - 48;
}
}
double result = 0;
int i = data_size - 2;
for (auto& num : v) {
result += num * pow(10, --i);
}
result += e * 0.1;
return result * sign;
}
int main(int argc, const char* argv[]) {
// Shut up warnings!
argc; argv;
SetConsoleOutputCP(CP_UTF8);
auto start = steady_clock::now();
// Let's raw dog some C; read the entire file into a buffer (we got RAM)
FILE* f = nullptr;
fopen_s(&f, "measurements.txt", "rb");
fseek(f, 0, SEEK_END);
long long size = _ftelli64(f);
std::cout << "Allocating " << size << " bytes" << std::endl;
char* data = new char[size];
std::cout << "Reading file" << std::endl;
rewind(f);
fread(data, sizeof(char), size, f);
std::cout << std::format("File loaded in {}\n", duration_cast<milliseconds>(steady_clock::now() - start));
// Still keeping track of every weather station in a map
std::unordered_map<std::string, Station> stations;
// Loop over characters using a state machine
ReadState state = ReadState::NAME;
std::string name_buffer;
std::string value_buffer;
for (long long i = 0; i < size; ++i) {
switch (state) {
case ReadState::NAME: {
if (data[i] == ';') {
state = ReadState::TEMPERATURE;
continue;
}
name_buffer += data[i];
break;
}
case ReadState::TEMPERATURE: {
if (data[i] == '\n') {
double v = parse_number(value_buffer);
auto& station = stations[name_buffer];
station.sum += v;
station.count++;
station.min = std::min(v, station.min);
station.max = std::max(v, station.max);
// Prepare for next line
name_buffer.clear();
value_buffer.clear();
state = ReadState::NAME;
continue;
}
value_buffer += data[i];
break;
}
}
}
std::cout << '{';
const char* delim = "";
for (const auto& [name, station] : stations) {
std::cout << std::format("{}{}={:.1f}/{:.1f}/{:.1f}", delim, name, station.min, station.sum / station.count, station.max);
delim = ", ";
}
std::cout << "}\n\n";
std::cout << std::format("Elapsed time: {}\n", duration_cast<milliseconds>(steady_clock::now() - start));
return 0;
}