diff --git a/examples/emplace.cc b/examples/emplace.cc index c5a4554..c97a9bb 100644 --- a/examples/emplace.cc +++ b/examples/emplace.cc @@ -30,95 +30,142 @@ class custom_type std::uint64_t five = 5; public: custom_type() = default; + // Make object movable and non-copyable custom_type(custom_type &&) = default; custom_type& operator=(custom_type &&) = default; + // should be automatically deleted per http://www.slideshare.net/ripplelabs/howard-hinnant-accu2014 //custom_type(custom_type const&) = delete; //custom_type& operator=(custom_type const&) = delete; }; +class custom_type_2 +{ + std::uint32_t three = 3; + std::uint64_t four = 4; + std::uint64_t five = 5; + std::uint64_t six = 6; +public: + custom_type_2() = default; + + // Make object movable and non-copyable + custom_type_2(custom_type_2 &&) = default; + custom_type_2& operator=(custom_type_2 &&) = default; + + // should be automatically deleted per http://www.slideshare.net/ripplelabs/howard-hinnant-accu2014 + //custom_type_2(custom_type_2 const&) = delete; + //custom_type_2& operator=(custom_type_2 const&) = delete; +}; + +// emplace string + large struct +// ----------------------------- +template struct _emplace +{ + void operator()(Map &m, std::size_t j); +}; + +// "void" template parameter -> use emplace +template struct _emplace +{ + void operator()(Map &m, std::size_t j) + { + m.emplace(patch::to_string(j), V()); + } +}; + +// "int" template parameter -> use emplace_back for std::vector +template struct _emplace +{ + void operator()(Map &m, std::size_t j) + { + m.emplace_back(patch::to_string(j), V()); + } +}; + +// insert +// --------------------------- +template struct emplace_2_ints +{ + void operator()(Map &m, std::size_t j); +}; + +// "void" template parameter -> use emplace +template struct emplace_2_ints +{ + void operator()(Map &m, std::size_t j) + { + m.emplace(j, V()); + } +}; + +// "int" template parameter -> use emplace_back for std::vector +template struct emplace_2_ints +{ + void operator()(Map &m, std::size_t j) + { + m.emplace_back(j, V()); + } +}; + +// The test itself +// --------------- +template class INSERT> +void _test(std::size_t iterations, std::size_t container_size, const char *map_name) +{ + std::size_t count = 0; + auto t1 = std::chrono::high_resolution_clock::now(); + INSERT insert; + for (std::size_t i=0; i(t2 - t1).count(); + if (count != iterations*container_size) + std::clog << " invalid count: " << count << "\n"; + std::clog << map_name << std::fixed << int(elapsed) << " ms\n"; +} + + +template class INSERT> void test(std::size_t iterations, std::size_t container_size) { std::clog << "bench: iterations: " << iterations << " / container_size: " << container_size << "\n"; - { - std::size_t count = 0; - auto t1 = std::chrono::high_resolution_clock::now(); - for (std::size_t i=0; i m; - m.reserve(container_size); - for (std::size_t j=0; j(t2 - t1).count(); - if (count != iterations*container_size) - std::clog << " invalid count: " << count << "\n"; - std::clog << " std::unordered_map: " << std::fixed << int(elapsed) << " ms\n"; - } - - { - std::size_t count = 0; - auto t1 = std::chrono::high_resolution_clock::now(); - for (std::size_t i=0; i m; - for (std::size_t j=0; j(t2 - t1).count(); - if (count != iterations*container_size) - std::clog << " invalid count: " << count << "\n"; - std::clog << " std::map: " << std::fixed << int(elapsed) << " ms\n"; - } - - { - std::size_t count = 0; - auto t1 = std::chrono::high_resolution_clock::now(); - for (std::size_t i=0; i> m; - m.reserve(container_size); - for (std::size_t j=0; j(t2 - t1).count(); - if (count != iterations*container_size) - std::clog << " invalid count: " << count << "\n"; - std::clog << " std::vector: " << std::fixed << int(elapsed) << " ms\n"; - } - - { - std::size_t count = 0; - auto t1 = std::chrono::high_resolution_clock::now(); - for (std::size_t i=0; i m; - m.reserve(container_size); - for (std::size_t j=0; j(t2 - t1).count(); - if (count != iterations*container_size) - std::clog << " invalid count: " << count << "\n"; - std::clog << " phmap::flat_hash_map: " << std::fixed << int(elapsed) << " ms\n"; - } + _test, V, void, INSERT>(iterations, container_size, " std::map: "); + _test, V, void, INSERT>(iterations, container_size, " std::unordered_map: "); + _test, V, void, INSERT>(iterations, container_size, " phmap::flat_hash_map: "); + _test>, V, int, INSERT> (iterations, container_size, " std::vector: "); + std::clog << "\n"; + } int main() { std::size_t iterations = 100000; - test(iterations,1); - test(iterations,10); - test(iterations,50); + // test with custom_type_2 (int key + 32 byte value). This is representative + // of the hash table insertion speed. + // ------------------------------------------------------------------------- + std::clog << "\n\n" << "testing with " "\n"; + std::clog << "---------------------------------" "\n"; + test(iterations,10); + test(iterations,100); + test(iterations,500); + + // test with custom_type, which contains two std::string values, and use + // a generated string key. This is not very indicative of the speed of the + // hash itself, as a good chunk of the time is spent creating the keys and + // values (as shown by the long times even for std::vector). + // ----------------------------------------------------------------------- + std::clog << "\n" << "testing with " "\n"; + std::clog << "---------------------------------" "\n"; + test(iterations,1); + test(iterations,10); + test(iterations,50); + }