Skip to content

Instantly share code, notes, and snippets.

@ikt32
Last active March 2, 2020 20:46
Show Gist options
  • Save ikt32/02dc6f850eab905d7a8a5e41ef0b2246 to your computer and use it in GitHub Desktop.
Save ikt32/02dc6f850eab905d7a8a5e41ef0b2246 to your computer and use it in GitHub Desktop.
Compare stl::find_if vs simple search
#include <cstdint>
#include <tuple>
#include <vector>
#include <algorithm>
#include <string>
#include <random>
#include <chrono>
#include <iostream>
typedef uint32_t Hash;
std::vector<std::tuple<Hash, int, int, int>> addonImages;
bool isPresentinAddonImages_STL(Hash hash) {
return addonImages.end() != std::find_if(addonImages.begin(), addonImages.end(), [&hash](const std::tuple<Hash, int, int, int>& element) {
return std::get<0>(element) == hash;
});
}
bool isPresentinAddonImages_loop(Hash hash) {
for (const auto& addonImage : addonImages) {
if (std::get<0>(addonImage) == hash)
return true;
}
return false;
}
Hash joaat(std::string s) {
std::transform(s.begin(), s.end(), s.begin(), ::tolower);
Hash hash = 0;
for (int i = 0; i < s.size(); i++) {
hash += s[i];
hash += (hash << 10);
hash ^= (hash >> 6);
}
hash += (hash << 3);
hash ^= (hash >> 11);
hash += (hash << 15);
return hash;
}
int main() {
Hash needle = joaat("needle");
std::mt19937 rng;
rng.seed(std::random_device()());
std::uniform_int_distribution<std::mt19937::result_type> dist(1, 9999); // distribution in range [1, 6]
for (int i = 0; i < 1000; i++) {
Hash hash = joaat("notneedle" + std::to_string(dist(rng)));
addonImages.push_back(std::make_tuple(hash, 1, 480, 270));
}
addonImages.push_back(std::make_tuple(needle, 1, 480, 270));
for (int i = 0; i < 1000; i++) {
Hash hash = joaat("notneedle" + std::to_string(dist(rng)));
addonImages.push_back(std::make_tuple(hash, 1, 480, 270));
}
std::cout << "Elements: " << addonImages.size() << "\n";
auto t1 = std::chrono::high_resolution_clock::now();
bool res = isPresentinAddonImages_STL(needle);
auto t2 = std::chrono::high_resolution_clock::now();
std::cout << "STL:\nDid ";
if (!res) {
std::cout << "not ";
}
std::cout << "find the needle in "
<< std::chrono::duration_cast<std::chrono::nanoseconds>(t2 - t1).count()
<< " ns!\n";
t1 = std::chrono::high_resolution_clock::now();
res = isPresentinAddonImages_loop(needle);
t2 = std::chrono::high_resolution_clock::now();
std::cout << "loop:\nDid";
if (!res) {
std::cout << "not ";
}
std::cout << "find the needle in "
<< std::chrono::duration_cast<std::chrono::nanoseconds>(t2 - t1).count()
<< " ns!\n";
return 0;
}
@Inori
Copy link

Inori commented Mar 2, 2020

for (auto addonImage : addonImages)
should be:
for (const auto& addonImage : addonImages)
this makes the most difference.

@ikt32
Copy link
Author

ikt32 commented Mar 2, 2020

@Inori

Thanks for the suggestion. Wew, this was 3 years ago, I don't even remember what I ended up doing. Running the "benchmark" now the difference is minimal anyway, with no clear winner with either a reference or by value. Plus, the collection size usually is less than 1000 anyway, or other issues might occur ;)

@Inori
Copy link

Inori commented Mar 2, 2020

On my machine, under MSVC x64 Release build, passing by value is 3 times slower than passing by reference on average.
After the fix, no significant difference anymore.
I'm just curious about the performence of find_if, and searching on Google brings me here.

@ikt32
Copy link
Author

ikt32 commented Mar 2, 2020

Ah yeah, under debug mode the difference is significant, I forgot to mention I tested with a release type build this time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment