geostat/common.cpp

148 wiersze
3.7 KiB
C++

#include "common.h"
#include <algorithm>
#include <vector>
#include <iterator>
const int HIST_MAX = 20;
void htmlencode(std::string& data) {
std::string tmp;
tmp.reserve(data.size() + 20);
for (size_t i = 0; i != data.size(); i++) {
switch (data[i]) {
case '&':
tmp += "&amp;";
break;
case '\"':
tmp += "&quot;";
break;
case '\'':
tmp += "&apos;";
break;
case '<':
tmp += "&lt;";
break;
case '>':
tmp += "&gt;";
break;
default:
tmp += data[i];
break;
}
}
data.swap(tmp);
}
void show_histogram(const Caches& cc, std::string Cache::*ptr, const std::string& caption, bool html, bool sort_by_val) {
std::map<std::string, int> histogram;
std::vector<std::pair<std::string, int>> pairs;
for (auto el : cc)
histogram[el.*ptr]++;
std::copy(histogram.begin(), histogram.end(), std::back_inserter(pairs));
if (sort_by_val)
sort(pairs.begin(), pairs.end(), [&](std::pair<std::string, int>& a, std::pair<std::string, int>& b) { return a.second > b.second; });
else
sort(pairs.begin(), pairs.end(), [&](std::pair<std::string, int>& a, std::pair<std::string, int>& b) { return a.first < b.first; });
if (html) {
int max;
if (sort_by_val)
max = pairs[0].second;
else
max = std::max_element(pairs.begin(), pairs.end(), [&](std::pair<std::string, int>& a, std::pair<std::string, int>& b) { return a.second < b.second; })->second;
int i = 0;
std::cout << "<h2>" << caption << "</h2>\n";
std::cout << "<dl class=\"histogram\">\n";
for (auto own : pairs) {
htmlencode(own.first);
if (own.first.empty()) own.first = "[unknown]";
if (i < HIST_MAX)
std::cout << "<dd class=\"bar\" style=\"--percent: " << 100 * own.second / max << "%;\"><span class=\"text\">" << own.first << ": " << own.second << "</span></dd>\n";
else if (i == HIST_MAX) {
std::cout << "</dl>\n";
std::cout << "<div class=\"histogram_others\">";
std::cout << " <input id=\"histo_others\" class=\"toggle\" type=\"checkbox\">\n <label for=\"histo_others\" class=\"lbl-toggle\">See more</label>\n <div class=\"collapsible-content\">\n <div class=\"content-inner\">\n";
std::cout << own.first << " (" << own.second << ")";
}
if (i > HIST_MAX)
std::cout << ", " << own.first << " (" << own.second << ")";
i++;
}
if (i < HIST_MAX)
std::cout << "</dl>\n";
else
std::cout << " </div>\n </div>\n</div>\n";
} else {
std::cout << caption << '\n';
for (auto own : pairs)
std::cout << own.first << ": " << own.second << '\n';
}
}
static bool same_day(const std::tm& a, const std::tm& b) {
return (a.tm_year == b.tm_year && a.tm_mon == b.tm_mon && a.tm_mday == b.tm_mday);
}
static void next_day(std::tm& a) {
a.tm_mday++;
mktime(&a);
}
int find_streak(const std::multimap<std::time_t, const Cache*>& cc, std::tm& start) {
int max_str = 0;
int cur_str = 0;
std::tm cur_tm;
cur_tm.tm_year = 0;
std::tm cur_start_tm = cur_tm;
start = cur_tm;
for (auto i : cc) {
if (same_day(cur_tm, *std::localtime(&i.first)))
continue;
next_day(cur_tm);
if (same_day(cur_tm, *std::localtime(&i.first))) {
cur_str++;
continue;
}
if (max_str < cur_str) {
max_str = cur_str;
start = cur_start_tm;
}
cur_str = 1;
cur_tm = cur_start_tm = *std::localtime(&i.first);
if (max_str == 0) {
max_str = 1;
start = cur_tm;
}
}
if (max_str < cur_str) {
max_str = cur_str;
start = cur_start_tm;
}
return max_str;
}
long int get_num(char c, char* opt) {
try {
if (std::stoi(opt) > 0) {
return std::stoi(opt);
} else {
std::cout << "Option \"-" << c << "\" requires a valid number as an argument\n";
std::exit(EXIT_FAILURE);
}
}
catch (...) {
std::cout << "Option \"-" << c << "\" requires a valid number as an argument\n";
std::exit(EXIT_FAILURE);
}
}