Skip to content

Instantly share code, notes, and snippets.

@ribomation
Last active January 16, 2024 15:29
Show Gist options
  • Save ribomation/e24c62899cd3120a890a9133be54161c to your computer and use it in GitHub Desktop.
Save ribomation/e24c62899cd3120a890a9133be54161c to your computer and use it in GitHub Desktop.
Simple implementation of 1BRC in Moden C++
#include <iostream>
#include <fstream>
#include <string>
#include <unordered_map>
#include <map>
#include <algorithm>
#include <format>
#include <limits>
#include "util.hxx"
using std::cout;
using std::string;
using namespace std::string_literals;
namespace rm = ribomation::util;
struct Aggregation {
unsigned count = 0;
double sum = 0;
double min = std::numeric_limits<double>::max();
double max = std::numeric_limits<double>::min();
void operator+=(double t) {
++count;
sum += t;
min = std::min(min, t);
max = std::max(max, t);
}
friend auto operator<<(std::ostream& os, Aggregation const& a) -> std::ostream& {
return os << std::format("{:+.2f}C, {:+.1f}/{:+.1f} ({:Ld})",
(a.sum / a.count), a.min, a.max, a.count);
}
};
int main(int argc, char** argv) {
auto filename = rm::getFilename(argc, argv);
cout << "filename: " << filename << "\n----\n";
rm::elapsed([filename]() {
auto f = std::ifstream{filename};
if (!f) throw std::invalid_argument{"cannot open "s + filename};
auto data = std::unordered_map<string, Aggregation>{};
data.reserve(500);
auto count = 0U;
for (string line; std::getline(f, line);) {
++count;
auto semi = line.find(';');
auto name = line.substr(0, semi);
auto temp = std::stod(line.substr(semi + 1));
data[name] += temp;
}
// auto sorted = std::map<string, Aggregation>{data.begin(), data.end()};
auto sorted = std::vector<std::pair<string, Aggregation>>{data.begin(), data.end()};
std::sort(sorted.begin(), sorted.end(), [](auto&& lhs, auto&& rhs){
return lhs.first < rhs.first;
});
for (auto&& [name, aggr]: sorted) {
cout << name << ": " << aggr << "\n";
}
cout << "------\n# records: " << count << "\n";
});
}
#include <iostream>
#include <string>
#include <chrono>
#include "util.hxx"
namespace ribomation::util {
using namespace std::string_literals;
namespace cr = std::chrono;
using std::cout;
using std::string;
void elapsed(std::function<void()> const& stmts) {
auto startTime = cr::high_resolution_clock::now();
stmts();
auto endTime = cr::high_resolution_clock::now();
auto elapsed = cr::duration<double, std::ratio<1, 1>>{endTime - startTime};
cout << std::format("Elapsed time: {:.3f} seconds\n", elapsed.count());
}
auto getFilename(int argc, char** argv) -> string {
auto filename = "data/weather-data-100K.csv"s;
for (auto k = 1; k < argc; ++k) {
auto arg = string{argv[k]};
if (arg == "-f"s) {
filename = argv[++k];
} else {
std::cerr << "usage: " << argv[0] << " [-f <str>]\n";
throw std::invalid_argument{"usage"};
}
}
return filename;
}
}
#pragma once
#include <functional>
#include <string>
namespace ribomation::util {
void elapsed(const std::function<void()>& stmts);
auto getFilename(int argc, char** argv) -> std::string;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment