Created
November 19, 2014 08:13
-
-
Save Kaali/ad78efb37591c1ecd757 to your computer and use it in GitHub Desktop.
rakkauden kalkulaattori
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <fcntl.h> | |
#include <errno.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <sys/mman.h> | |
#include <sys/stat.h> | |
#include <cassert> | |
#include <fstream> | |
#include <iostream> | |
#include <iterator> | |
#include <string> | |
#include <thread> | |
#include <vector> | |
struct Counts { | |
Counts() : p(0), a(0), i(0), r(0), s(0) {} | |
unsigned p, a, i, r, s; | |
}; | |
template <typename T> | |
Counts CountChars(T const& str) { | |
Counts counts; | |
for (auto const& c : str) { | |
switch (c) { | |
case 'p': | |
case 'P': | |
counts.p++; | |
break; | |
case 'a': | |
case 'A': | |
counts.a++; | |
break; | |
case 'i': | |
case 'I': | |
counts.i++; | |
break; | |
case 'r': | |
case 'R': | |
counts.r++; | |
break; | |
case 's': | |
case 'S': | |
counts.s++; | |
break; | |
} | |
} | |
return counts; | |
} | |
template <typename T> | |
inline | |
T Clamp(T const& value) { | |
return value < 10 ? value : value - 9; | |
} | |
template <typename T> | |
auto Compatibility(T const& first, T const& second) -> decltype(Clamp(first.p + second.p)) { | |
using K = decltype(Clamp(first.p + second.p)); | |
K p = Clamp(first.p + second.p); | |
K a = Clamp(first.a + second.a); | |
K i = Clamp(first.i + second.i); | |
K r = Clamp(first.r + second.r); | |
K s = Clamp(first.s + second.s); | |
p = Clamp(p + a); | |
a = Clamp(a + i); | |
i = Clamp(i + r); | |
r = Clamp(r + s); | |
p = Clamp(p + a); | |
a = Clamp(a + i); | |
i = Clamp(i + r); | |
p = Clamp(p + a); | |
a = Clamp(a + i); | |
return (p * 10) + a; | |
} | |
std::vector<Counts> ReadCounts(std::string const& filename); // TODO: What? | |
std::vector<Counts> ReadCounts(std::string const& filename) { | |
std::ios::sync_with_stdio(false); | |
std::fstream f{filename}; | |
std::string line; | |
line.reserve(30); | |
std::vector<Counts> counts; | |
counts.reserve(1024); | |
while (std::getline(f, line)) { | |
counts.push_back(CountChars(line)); | |
} | |
return counts; | |
} | |
std::vector<Counts> ReadCountsMmap(std::string const& filename); | |
std::vector<Counts> ReadCountsMmap(std::string const& filename) { | |
std::vector<Counts> counts; | |
counts.reserve(1024); | |
auto fd = open(filename.c_str(), O_RDONLY); | |
if (fd < 0) abort(); | |
struct stat s; | |
auto status = fstat(fd, &s); | |
if (status < 0) abort(); | |
size_t size = static_cast<size_t>(s.st_size); | |
const char* mapped = static_cast<char*>(mmap(0, size, PROT_READ, MAP_PRIVATE, fd, 0)); | |
if (mapped == MAP_FAILED) { | |
abort(); | |
} | |
Counts count; | |
for (decltype(size) i = 0; i < size; ++i) { | |
switch (mapped[i]) { | |
case 'p': | |
case 'P': | |
count.p++; | |
break; | |
case 'a': | |
case 'A': | |
count.a++; | |
break; | |
case 'i': | |
case 'I': | |
count.i++; | |
break; | |
case 'r': | |
case 'R': | |
count.r++; | |
break; | |
case 's': | |
case 'S': | |
count.s++; | |
break; | |
case '\n': | |
counts.push_back(count); | |
count.p = 0; | |
count.a = 0; | |
count.i = 0; | |
count.r = 0; | |
count.s = 0; | |
break; | |
} | |
} | |
return counts; | |
} | |
template <typename T> | |
void split_work(size_t concurrency, T const& data, | |
std::function<void(size_t, size_t)> worker) { | |
std::vector<std::thread> threads(concurrency); | |
size_t const worksize = data.size() / concurrency; | |
size_t i = 0; | |
for (auto it = std::begin(threads); it != std::end(threads) - 1; ++it) { | |
*it = std::thread(worker, i, i + worksize); | |
i += worksize; | |
} | |
threads.back() = std::thread(worker, i, data.size()); | |
for (auto&& t : threads) t.join(); | |
} | |
int main(int argc, char** argv) { | |
if (argc != 2) { | |
std::cout << "Usage: " << argv[0] << " filename" << std::endl; | |
return -1; | |
} | |
auto counts = ReadCountsMmap(argv[1]); | |
auto concurrency = std::thread::hardware_concurrency(); | |
//auto concurrency = 1u; | |
std::atomic<unsigned> result(0); | |
auto worker = [&](size_t first, size_t last) { | |
unsigned res = 0; | |
for (size_t i = first; i < last; ++i) { | |
for (size_t j = i + 1; j < counts.size(); ++j) { | |
auto compat = Compatibility(counts[i], counts[j]); | |
if (compat == 99) { | |
res++; | |
} | |
} | |
} | |
result += res; | |
}; | |
if (concurrency == 1) { | |
worker(0, counts.size()); | |
} else { | |
split_work(concurrency, counts, worker); | |
} | |
std::cout << result << std::endl; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment