diff --git a/roottest/root/io/cpp11Containers/commonUtilsUnorderedMap.h b/roottest/root/io/cpp11Containers/commonUtilsUnorderedMap.h new file mode 100644 index 0000000000000..59aa104f8daf8 --- /dev/null +++ b/roottest/root/io/cpp11Containers/commonUtilsUnorderedMap.h @@ -0,0 +1,601 @@ +#include +#include "TH1F.h" +#include +#include +#include +#include +#include +#include +#include +#include "TFile.h" +#include +#include + +#ifndef ROOTTEST_COMMON_UTILS +#define ROOTTEST_COMMON_UTILS + +bool gVerboseComparison = false; + +std::mt19937 gRNG{1}; +std::normal_distribution gGaus{0., 1.}; +std::uniform_real_distribution gUniform{1., 2.}; + +template +bool IsSame(const T &a, const T &b) +{ + std::cout << "ERROR\n"; + return a == b; +} + +template <> +bool IsSame<>(const int &a, const int &b) +{ + if (a == b) + return true; + std::cout << "Error numbers differ: " << a << " " << b << std::endl; + return false; +} + +template <> +bool IsSame<>(const Long64_t &a, const Long64_t &b) +{ + if (a == b) + return true; + std::cout << "Error numbers differ: " << a << " " << b << std::endl; + return false; +} + +template <> +bool IsSame<>(const double &a, const double &b) +{ + if (a == b) + return true; + std::cout << "Error numbers differ: " << a << " " << b << std::endl; + return false; +} + +template <> +bool IsSame<>(const float &a, const float &b) +{ + if (a == b) + return true; + std::cout << "Error numbers differ: " << a << " " << b << std::endl; + return false; +} + +template +bool IsSame(const std::complex &a, const std::complex &b) +{ + if (a == b) + return true; + std::cout << "Error complex numbers differ: " << a << " " << b << std::endl; + return false; +} + +template +bool IsSame(const std::pair &a, const std::pair &b) +{ + return IsSame(a.first, b.first) && IsSame(a.second, b.second); +} + +template +bool IsSameCont(const Cont &a, const Cont &b) +{ + auto size = std::distance(a.begin(), a.end()); + if (size != std::distance(b.begin(), b.end())) + return false; + for (auto aIt = a.cbegin(), bIt = b.begin(); aIt != a.end(); aIt++, bIt++) { + if (!IsSame(*aIt, *bIt)) + return false; + } + + return true; +} + +template +bool IsSame(const std::forward_list &a, const std::forward_list &b) +{ + return IsSameCont(a, b); +} + +template +bool IsSame(const std::list &a, const std::list &b) +{ + return IsSameCont(a, b); +} +template +bool IsSame(const std::vector &a, const std::vector &b) +{ + return IsSameCont(a, b); +} +template +bool IsSame(const std::deque &a, const std::deque &b) +{ + return IsSameCont(a, b); +} + +template +bool IsSame(const std::unordered_set &a, const std::unordered_set &b) +{ + std::vector v1; + for (auto &el : a) + v1.emplace_back(el); + std::vector v2; + for (auto &el : b) + v2.emplace_back(el); + + auto sortingFunction = [](const T &o1, const T &o2) { + return std::string(o1.GetName()) < std::string(o2.GetName()); + }; + std::sort(v1.begin(), v1.end(), sortingFunction); // FUNDAMENTAL! + std::sort(v2.begin(), v2.end(), sortingFunction); // FUNDAMENTAL! + return IsSame(v1, v2); +} + +template +bool IsSame(const std::unordered_multiset &a, const std::unordered_multiset &b) +{ + std::vector v1; + for (auto &el : a) + v1.emplace_back(el); + std::vector v2; + for (auto &el : b) + v2.emplace_back(el); + + auto sortingFunction = [](const T &o1, const T &o2) { + return std::string(o1.GetName()) < std::string(o2.GetName()); + }; + std::sort(v1.begin(), v1.end(), sortingFunction); // FUNDAMENTAL! + std::sort(v2.begin(), v2.end(), sortingFunction); // FUNDAMENTAL! + return IsSame(v1, v2); +} + +template +bool IsSame(const std::unordered_set> &a, const std::unordered_set> &b) +{ + std::vector> v1; + for (auto &el : a) + v1.emplace_back(el); + std::vector> v2; + for (auto &el : b) + v2.emplace_back(el); + + auto sortingFunction = [](const std::vector &vt1, const std::vector &vt2) { + std::string namesA, namesB; + for (auto &&h : vt1) + namesA += h.GetName(); + for (auto &&h : vt2) + namesB += h.GetName(); + return namesA < namesB; + }; + + std::sort(v1.begin(), v1.end(), sortingFunction); // FUNDAMENTAL! + std::sort(v2.begin(), v2.end(), sortingFunction); // FUNDAMENTAL! + return IsSame(v1, v2); +} + +template +bool IsSame(const std::unordered_multiset> &a, const std::unordered_multiset> &b) +{ + std::vector> v1; + for (auto &el : a) + v1.emplace_back(el); + std::vector> v2; + for (auto &el : b) + v2.emplace_back(el); + + auto sortingFunction = [](const std::vector &vt1, const std::vector &vt2) { + std::string namesA, namesB; + for (auto &&h : vt1) + namesA += h.GetName(); + for (auto &&h : vt2) + namesB += h.GetName(); + return namesA < namesB; + }; + std::sort(v1.begin(), v1.end(), sortingFunction); // FUNDAMENTAL! + std::sort(v2.begin(), v2.end(), sortingFunction); // FUNDAMENTAL! + return IsSame(v1, v2); +} + +template <> +bool IsSame(const std::unordered_set &a, const std::unordered_set &b) +{ + std::vector v1; + for (auto &el : a) + v1.emplace_back(el); + std::vector v2; + for (auto &el : b) + v2.emplace_back(el); + + std::sort(v1.begin(), v1.end()); // FUNDAMENTAL! + std::sort(v2.begin(), v2.end()); // FUNDAMENTAL! + return IsSame(v1, v2); +} + +template <> +bool IsSame(const std::unordered_multiset &a, const std::unordered_multiset &b) +{ + std::vector v1; + for (auto &el : a) + v1.emplace_back(el); + std::vector v2; + for (auto &el : b) + v2.emplace_back(el); + + std::sort(v1.begin(), v1.end()); // FUNDAMENTAL! + std::sort(v2.begin(), v2.end()); // FUNDAMENTAL! + return IsSame(v1, v2); +} + +template <> +bool IsSame<>(const TH1F &a, const TH1F &b) +{ + if (0 != strcmp(a.GetName(), b.GetName())) { + if (gVerboseComparison) + std::cout << "The names of the histograms differ: " << a.GetName() << " " << b.GetName() << std::endl; + return false; + } + if (0 != strcmp(a.GetTitle(), b.GetTitle())) { + if (gVerboseComparison) + std::cout << "The title of the histograms differ: " << a.GetTitle() << " " << b.GetTitle() << std::endl; + return false; + } + auto nbinsa = a.GetNbinsX(); + auto nbinsb = b.GetNbinsX(); + if (nbinsa != nbinsb) { + if (gVerboseComparison) + std::cout << "The # of bins of the histograms differ: " << nbinsa << " " << nbinsb << std::endl; + return false; + } + const auto AreBitwiseEqual = [](auto x, auto y) { + ULong64_t lx, ly; + memcpy(&lx, &x, sizeof(x)); + memcpy(&ly, &y, sizeof(y)); + return lx == ly; + }; + for (int i = 0; i < a.GetNbinsX(); ++i) { + auto binca = a.GetBinContent(i); + auto bincb = b.GetBinContent(i); + if (!AreBitwiseEqual(binca, bincb)) { + if (gVerboseComparison) + std::cout << "The content of bin " << i << " of the histograms differ: " << binca << " " << bincb + << std::endl; + return false; + } + auto binea = a.GetBinError(i); + auto bineb = b.GetBinError(i); + if (!AreBitwiseEqual(binea, bineb)) { + if (gVerboseComparison) + std::cout << "The error of bin " << i << " of the histograms differ: " << binea << " " << bineb + << std::endl; + return false; + } + } + + return true; +} + +template +bool IsSame(const std::map &a, const std::map &b) +{ + std::vector> v1; + for (auto &el : a) + v1.emplace_back(el); + std::vector> v2; + for (auto &el : b) + v2.emplace_back(el); + + return IsSame(v1, v2); +} + +template +bool IsSame(const std::multimap &a, const std::multimap &b) +{ + std::vector> v1; + for (auto &el : a) + v1.emplace_back(el); + std::vector> v2; + for (auto &el : b) + v2.emplace_back(el); + return IsSame(v1, v2); +} + +// For gcc48: lambda not correctly compiled +// template bool sortingFunction(std::pair& p1,std::pair& p2){return p1.first +bool IsSame(const std::unordered_map &a, const std::unordered_map &b) +{ + std::vector> v1; + for (auto &el : a) + v1.emplace_back(el); + std::vector> v2; + for (auto &el : b) + v2.emplace_back(el); + + auto sortingFunction = [](const std::pair &p1, const std::pair &p2) { return p1.first < p2.first; }; + + std::sort(v1.begin(), v1.end(), sortingFunction); // FUNDAMENTAL! + std::sort(v2.begin(), v2.end(), sortingFunction); // FUNDAMENTAL! + + return IsSame(v1, v2); +} + +template +bool IsSame(const std::unordered_multimap &a, const std::unordered_multimap &b) +{ + std::vector> v1; + for (auto &el : a) + v1.emplace_back(el); + std::vector> v2; + for (auto &el : b) + v2.emplace_back(el); + + auto sortingFunction = [](const std::pair &p1, const std::pair &p2) { return p1.first < p2.first; }; + + std::sort(v1.begin(), v1.end(), sortingFunction); // FUNDAMENTAL! + std::sort(v2.begin(), v2.end(), sortingFunction); // FUNDAMENTAL! + + return IsSame(v1, v2); +} + +void createFile(const char *filename) +{ + auto file = TFile::Open(filename, "RECREATE"); + delete file; +} + +template +void writeToFile(const T &obj, const char *objName, const char *filename) +{ + auto file = TFile::Open(filename, "UPDATE"); + file->WriteObject(&obj, objName); + delete file; +} + +template +void readAndCheckFromFile(const T &obj, const char *objName, const char *filename) +{ + auto file = TFile::Open(filename, "READ"); + auto objFromFile = (T *)file->Get(objName); + if (!objFromFile) { + std::cerr << "Error in reading object " << objName << " from file " << filename << "\n"; + delete file; + return; + } + if (!IsSame(obj, *objFromFile)) { + std::cerr << "Error: object " << objName << " read from file " << filename + << " from file and in memory are not identical!\n"; + } + + delete file; +} + +template +void writeReadCheck(const T &obj, const char *objName, const char *filename) +{ + gVerboseComparison = true; + writeToFile(obj, objName, filename); + readAndCheckFromFile(obj, objName, filename); + gVerboseComparison = false; +} + +template +void fillHistoCont(Cont &cont, unsigned int n = 5000) +{ + for (auto &h : cont) + for (unsigned int i = 0; i < n; i++) + h.Fill(gGaus(gRNG)); +} + +template +void fillHistoAssoCont(Cont &cont, unsigned int n = 5000) +{ + using contPair_t = std::pair; + std::vector v; + for (auto &el : cont) + v.emplace_back(el); + auto sortingFunction = [](const contPair_t &p1, const contPair_t &p2) { return p1.first < p2.first; }; + std::sort(v.begin(), v.end(), sortingFunction); // FUNDAMENTAL! + cont.clear(); + for (auto &h : v) { + for (unsigned int i = 0; i < n; i++) + h.second.Fill(gGaus(gRNG)); + cont.insert(h); + } +} + +template +void fillHistoNestedCont(NestedCont &nestedCont, unsigned int n = 5000) +{ + for (auto &hCont : nestedCont) { + fillHistoCont(hCont, n); + } +} + +template +void fillHistoNestedAssoCont(std::vector &nestedCont, unsigned int n = 5000) +{ + for (auto &hCont : nestedCont) { + fillHistoAssoCont(hCont, n); + } +} + +template +void fillHistoNestedAssoCont(NestedCont &nestedCont, unsigned int n = 5000) +{ + using contPair_t = std::pair; + std::vector v; + for (auto &el : nestedCont) + v.emplace_back(el); + auto sortingFunction = [](const contPair_t &p1, const contPair_t &p2) { return p1.first < p2.first; }; + std::sort(v.begin(), v.end(), sortingFunction); // FUNDAMENTAL! + nestedCont.clear(); + for (auto &hCont : v) { + fillHistoCont(hCont.second, n); + nestedCont.insert(hCont); + } +} + +template +void randomizeCont(Cont &cont) +{ + for (auto &el : cont) { + el *= gUniform(gRNG); + } +} + +template +void randomizeAssoCont(Cont &cont) +{ + using contPair_t = std::pair; + std::vector v; + for (auto &el : cont) + v.emplace_back(el); + auto sortingFunction = [](const contPair_t &p1, const contPair_t &p2) { return p1.first < p2.first; }; + std::sort(v.begin(), v.end(), sortingFunction); // FUNDAMENTAL! + cont.clear(); + for (auto &el : v) { + cont.insert(std::make_pair(el.first, el.second * gUniform(gRNG))); + } +} + +//------------------------------------------------------------------------------ +// For the unordered set +namespace std { +template <> +struct hash { +public: + size_t operator()(const TH1F &h) const + { + std::hash shash; + return shash(h.GetName()); + } +}; // hash +template <> +struct hash> { +public: + size_t operator()(const std::vector &hVect) const + { + std::string names; + for (auto &&h : hVect) + names += h.GetName(); + std::hash shash; + return shash(names); + } +}; // hash + +template <> +struct equal_to { + bool operator()(const TH1F &a, const TH1F &b) const { return IsSame(a, b); } +}; +template <> +struct equal_to> { + bool operator()(const std::vector &a, const std::vector &b) const { return IsSame(a, b); } +}; + +} // namespace std + +template +void fillHistoCont(std::unordered_set &cont, unsigned int n = 5000) +{ + std::vector v; + for (auto &el : cont) + v.emplace_back(el); + cont.clear(); + std::sort(v.begin(), v.end(), [](const T &a, const T &b) { + return std::string(a.GetName()) < std::string(b.GetName()); + }); // FUNDAMENTAL! + for (auto &h : v) { + for (unsigned int i = 0; i < n; i++) + h.Fill(gGaus(gRNG)); + cont.insert(h); + } +} + +template +void fillHistoNestedCont(std::unordered_set &nestedCont, unsigned int n = 5000) +{ + std::vector v; + for (auto &hCont : nestedCont) + v.emplace_back(hCont); + std::sort(v.begin(), v.end(), [](const T &a, const T &b) { + std::string namesA, namesB; + for (auto &&h : a) + namesA += h.GetName(); + for (auto &&h : b) + namesB += h.GetName(); + return namesA < namesB; + }); + nestedCont.clear(); + for (auto &hCont : v) { + fillHistoCont(hCont, n); + nestedCont.insert(hCont); + } +} + +template +void randomizeCont(std::unordered_set &cont) +{ + std::vector v; + for (auto &el : cont) + v.emplace_back(el); + std::sort(v.begin(), v.end()); // FUNDAMENTAL! + cont.clear(); + for (auto &el : v) { + cont.insert(el * gUniform(gRNG)); + } +} + +template +void fillHistoCont(std::unordered_multiset &cont, unsigned int n = 5000) +{ + std::vector v; + for (auto &el : cont) + v.emplace_back(el); + cont.clear(); + std::sort(v.begin(), v.end(), [](const T &a, const T &b) { + return std::string(a.GetName()) < std::string(b.GetName()); + }); // FUNDAMENTAL! + for (auto &h : v) { + for (unsigned int i = 0; i < n; i++) + h.Fill(gGaus(gRNG)); + cont.insert(h); + } +} + +template +void fillHistoNestedCont(std::unordered_multiset &nestedCont, unsigned int n = 5000) +{ + std::vector v; + for (auto &hCont : nestedCont) + v.emplace_back(hCont); + std::sort(v.begin(), v.end(), [](const T &a, const T &b) { + std::string namesA, namesB; + for (auto &&h : a) + namesA += h.GetName(); + for (auto &&h : b) + namesB += h.GetName(); + return namesA < namesB; + }); + nestedCont.clear(); + for (auto &hCont : v) { + fillHistoCont(hCont, n); + nestedCont.insert(hCont); + } +} + +template +void randomizeCont(std::unordered_multiset &cont) +{ + std::vector v; + for (auto &el : cont) + v.emplace_back(el); + std::sort(v.begin(), v.end()); // FUNDAMENTAL! + cont.clear(); + for (auto &el : v) { + cont.insert(el * gUniform(gRNG)); + } +} + +#endif diff --git a/roottest/root/io/cpp11Containers/execUnorderedMap.C b/roottest/root/io/cpp11Containers/execUnorderedMap.C index 48ca30903a02a..e847ee8b0eb5b 100644 --- a/roottest/root/io/cpp11Containers/execUnorderedMap.C +++ b/roottest/root/io/cpp11Containers/execUnorderedMap.C @@ -7,8 +7,7 @@ // The test still has some repetitions which one could wash away with metaprogramming. -#include "commonUtils.h" - +#include "commonUtilsUnorderedMap.h" template void checkObjects(const char* name, const T& a, const T& b){ @@ -22,7 +21,9 @@ void check(const char* testName){ printf("o Checking %s\n",testName); TH1::AddDirectory(0); // same name is ok - gRandom->SetSeed(1); // make all contents identical irrespective of the container + gRNG.seed(1); + gGaus.reset(); + gUniform.reset(); // make all contents identical irrespective of the container std::string binFilename(testName); binFilename+="UnorderedMap"; binFilename+=".root"; std::string xmlFilename(testName); xmlFilename+="UnorderedMap"; xmlFilename+=".xml"; @@ -68,7 +69,9 @@ void check(const char* testName){ auto contHistoVecOrig = contHistoVec; // Write - gRandom->SetSeed(1); + gRNG.seed(1); + gGaus.reset(); + gUniform.reset(); { printf(" * Write\n"); TFile f(binFilename.c_str(),"UPDATE"); @@ -91,7 +94,9 @@ void check(const char* testName){ t.Write(); } // And Read - gRandom->SetSeed(1); + gRNG.seed(1); + gGaus.reset(); + gUniform.reset(); { printf(" * Read\n"); TFile f(binFilename.c_str());