| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #include <cstddef> |
| | #include <cstdint> |
| | #include <atomic> |
| |
|
| | template<class T> static constexpr T min(T a, T b) { return a < b ? a : b; } |
| |
|
| | struct trie { |
| | struct ref { |
| | std::atomic<trie*> ptr = ATOMIC_VAR_INIT(nullptr); |
| | |
| | std::atomic_flag flag = ATOMIC_VAR_INIT(0); |
| | } next[26]; |
| | std::atomic<int> count = ATOMIC_VAR_INIT(0); |
| | }; |
| | int index_of(char c) { |
| | if(c >= 'a' && c <= 'z') return c - 'a'; |
| | if(c >= 'A' && c <= 'Z') return c - 'A'; |
| | return -1; |
| | }; |
| | void make_trie( trie& root, |
| | std::atomic<trie*>& bump, |
| | const char* begin, const char* end, |
| | unsigned index, |
| | unsigned domain) { |
| |
|
| | auto const size = end - begin; |
| | auto const stride = (size / domain + 1); |
| |
|
| | auto off = min(size, stride * index); |
| | auto const last = min(size, off + stride); |
| |
|
| | for(char c = begin[off]; off < size && off != last && c != 0 && index_of(c) != -1; ++off, c = begin[off]); |
| | for(char c = begin[off]; off < size && off != last && c != 0 && index_of(c) == -1; ++off, c = begin[off]); |
| |
|
| | trie *n = &root; |
| | for(char c = begin[off]; ; ++off, c = begin[off]) { |
| | auto const index = off >= size ? -1 : index_of(c); |
| | if(index == -1) { |
| | if(n != &root) { |
| | n->count.fetch_add(1, std::memory_order_relaxed); |
| | n = &root; |
| | } |
| | |
| | if(off >= size || off > last) |
| | break; |
| | else |
| | continue; |
| | } |
| | if(n->next[index].ptr.load(std::memory_order_acquire) == nullptr) { |
| | if(n->next[index].flag.test_and_set(std::memory_order_relaxed) == 1) |
| | while(n->next[index].ptr.load(std::memory_order_acquire) == nullptr); |
| | else { |
| | auto next = bump.fetch_add(1, std::memory_order_relaxed); |
| | n->next[index].ptr.store(next, std::memory_order_release); |
| | } |
| | } |
| | n = n->next[index].ptr.load(std::memory_order_relaxed); |
| | } |
| | } |
| |
|
| | #include <iostream> |
| | #include <cassert> |
| | #include <fstream> |
| | #include <utility> |
| | #include <chrono> |
| | #include <thread> |
| | #include <memory> |
| | #include <vector> |
| | #include <string> |
| |
|
| | void do_trie(std::string const& input, int threads) { |
| | |
| | std::vector<trie> nodes(1<<17); |
| | |
| | auto t = nodes.data(); |
| | std::atomic<trie*> b(nodes.data()+1); |
| |
|
| | auto const begin = std::chrono::steady_clock::now(); |
| | std::atomic_signal_fence(std::memory_order_seq_cst); |
| | std::vector<std::thread> tv(threads); |
| | for(auto count = threads; count; --count) |
| | tv[count - 1] = std::thread([&, count]() { |
| | make_trie(*t, b, input.data(), input.data() + input.size(), count - 1, threads); |
| | }); |
| | for(auto& t : tv) |
| | t.join(); |
| | std::atomic_signal_fence(std::memory_order_seq_cst); |
| | auto const end = std::chrono::steady_clock::now(); |
| | auto const time = std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count(); |
| | auto const count = b.load() - nodes.data(); |
| | std::cout << "Assembled " << count << " nodes on " << threads << " cpu threads in " << time << "ms." << std::endl; |
| | } |
| |
|
| | int main() { |
| |
|
| | std::string input; |
| |
|
| | char const* files[] = { |
| | "books/2600-0.txt", "books/2701-0.txt", "books/35-0.txt", "books/84-0.txt", "books/8800.txt", |
| | "books/pg1727.txt", "books/pg55.txt", "books/pg6130.txt", "books/pg996.txt", "books/1342-0.txt" |
| | }; |
| |
|
| | for(auto* ptr : files) { |
| | std::cout << ptr << std::endl; |
| | auto const cur = input.size(); |
| | std::ifstream in(ptr); |
| | if(in.fail()) { |
| | std::cerr << "Failed to open file: " << ptr << std::endl; |
| | return -1; |
| | } |
| | in.seekg(0, std::ios_base::end); |
| | auto const pos = in.tellg(); |
| | input.resize(cur + pos); |
| | in.seekg(0, std::ios_base::beg); |
| | in.read((char*)input.data() + cur, pos); |
| | } |
| |
|
| | do_trie(input, 1); |
| | do_trie(input, 1); |
| | do_trie(input, std::thread::hardware_concurrency()); |
| | do_trie(input, std::thread::hardware_concurrency()); |
| |
|
| | return 0; |
| | } |
| |
|