diff --git a/DataFormats/Headers/include/Headers/DataHeader.h b/DataFormats/Headers/include/Headers/DataHeader.h index f24fad8f5142e..3b0aed94865a4 100644 --- a/DataFormats/Headers/include/Headers/DataHeader.h +++ b/DataFormats/Headers/include/Headers/DataHeader.h @@ -205,6 +205,11 @@ struct DescriptorCompareTraits { static bool compare(const T &lh, const T &rh, Length N) { return std::memcmp(lh.str, rh.str, N) == 0; } + template + static bool lessThen(const T& lh, const T& rh, Length N) + { + return std::memcmp(lh.str, rh.str, N) < 0; + } }; template<> struct DescriptorCompareTraits<1> { @@ -212,6 +217,11 @@ struct DescriptorCompareTraits<1> { static bool compare(const T &lh, const T &rh, Length) { return lh.itg[0] == rh.itg[0]; } + template + static bool lessThen(const T& lh, const T& rh, Length) + { + return lh.itg[0] < rh.itg[0]; + } }; template<> struct DescriptorCompareTraits<2> { @@ -219,6 +229,11 @@ struct DescriptorCompareTraits<2> { static bool compare(const T &lh, const T &rh, Length) { return (lh.itg[0] == rh.itg[0]) && (lh.itg[1] == rh.itg[1]); } + template + static bool lessThen(const T& lh, const T& rh, Length) + { + return std::tie(lh.itg[0], lh.itg[1]) < std::tie(rh.itg[0], rh.itg[1]); + } }; //__________________________________________________________________________________________________ @@ -293,6 +308,7 @@ struct Descriptor { } bool operator==(const Descriptor& other) const {return DescriptorCompareTraits::compare(*this,other, N);} + bool operator<(const Descriptor& other) const { return DescriptorCompareTraits::lessThen(*this, other, N); } bool operator!=(const Descriptor& other) const {return not this->operator==(other);} // explicitly forbid comparison with e.g. const char* strings diff --git a/DataFormats/Headers/test/testDataHeader.cxx b/DataFormats/Headers/test/testDataHeader.cxx index 8727ddd545a45..c20b351bbae65 100644 --- a/DataFormats/Headers/test/testDataHeader.cxx +++ b/DataFormats/Headers/test/testDataHeader.cxx @@ -132,6 +132,11 @@ namespace o2 { BOOST_CHECK(desc.as().length() == 6); BOOST_CHECK(runtimeDesc.as().length() == 16); BOOST_CHECK(DataDescription("INVALIDDATA").as().length() == 11); + + BOOST_CHECK(DataDescription("A") < DataDescription("B")); + BOOST_CHECK(DataDescription("AA") < DataDescription("AB")); + BOOST_CHECK(DataDescription("AAA") < DataDescription("AAB")); + BOOST_CHECK(DataDescription("AAA") < DataDescription("ABA")); } BOOST_AUTO_TEST_CASE(DataOrigin_test) @@ -141,12 +146,56 @@ namespace o2 { using TestDescriptorT = Descriptor; BOOST_CHECK(TestDescriptorT::size == descriptorSize); BOOST_CHECK(TestDescriptorT::bitcount == descriptorSize * 8); - BOOST_CHECK(sizeof(TestDescriptorT::ItgType)*TestDescriptorT::arraySize == descriptorSize); + BOOST_CHECK(sizeof(TestDescriptorT::ItgType) * TestDescriptorT::arraySize == descriptorSize); BOOST_CHECK(TestDescriptorT::size == sizeof(DataOrigin)); // we want to explicitely have the size of DataOrigin to be 4 static_assert(sizeof(DataOrigin) == 4, "DataOrigin struct must be of size 4"); + + // Check that ordering works. + BOOST_CHECK(DataOrigin("A") < DataOrigin("B")); + BOOST_CHECK(DataOrigin("AA") < DataOrigin("AB")); + BOOST_CHECK(DataOrigin("AAA") < DataOrigin("AAB")); + BOOST_CHECK(DataOrigin("AAA") < DataOrigin("ABA")); + std::vector v1 = { DataOrigin("B"), DataOrigin("C"), DataOrigin("A") }; + std::sort(v1.begin(), v1.end()); + BOOST_CHECK_EQUAL(v1[0], DataOrigin("A")); + BOOST_CHECK_EQUAL(v1[1], DataOrigin("B")); + BOOST_CHECK_EQUAL(v1[2], DataOrigin("C")); + std::vector v2 = { DataOrigin("A"), DataOrigin("B") }; + std::sort(v2.begin(), v2.end()); + BOOST_CHECK_EQUAL(v2[0], DataOrigin("A")); + BOOST_CHECK_EQUAL(v2[1], DataOrigin("B")); + + using CustomHeader = std::tuple; + std::vector v3{ CustomHeader{ "TST", "B" }, CustomHeader{ "TST", "A" } }; + std::sort(v3.begin(), v3.end()); + auto h0 = CustomHeader{ "TST", "A" }; + auto h1 = CustomHeader{ "TST", "B" }; + BOOST_CHECK(v3[0] == h0); + BOOST_CHECK(v3[1] == h1); + + using CustomHeader2 = std::tuple; + std::vector v4{ CustomHeader2{ "TST", "A", 1 }, CustomHeader2{ "TST", "A", 0 } }; + std::sort(v4.begin(), v4.end()); + auto hh0 = CustomHeader2{ "TST", "A", 0 }; + auto hh1 = CustomHeader2{ "TST", "A", 1 }; + BOOST_CHECK(v4[0] == hh0); + BOOST_CHECK(v4[1] == hh1); + + struct CustomHeader3 { + DataOrigin origin; + DataDescription desc; + uint64_t subSpec; + int isOut; + }; + std::vector v5{ CustomHeader3{ "TST", "A", 0, 1 }, CustomHeader3{ "TST", "A", 0, 0 } }; + std::sort(v5.begin(), v5.end(), [](CustomHeader3 const& lhs, CustomHeader3 const& rhs) { + return std::tie(lhs.origin, lhs.desc, rhs.subSpec, lhs.isOut) < std::tie(rhs.origin, rhs.desc, rhs.subSpec, rhs.isOut); + }); + BOOST_CHECK(v5[0].isOut == 0); + BOOST_CHECK(v5[1].isOut == 1); } BOOST_AUTO_TEST_CASE(BaseHeader_test)