File indexing completed on 2025-07-31 02:19:16
0001
0002
0003
0004
0005
0006
0007
0008 #include <catch.hpp>
0009 #include <cassert>
0010 #include <cstdint>
0011 #include <iostream>
0012 #include <string>
0013 #include <utility>
0014 #include "FWCore/Utilities/interface/SoATuple.h"
0015
0016 namespace {
0017 struct ConstructDestructCounter {
0018 static unsigned int s_constructorCalls;
0019 static unsigned int s_destructorCalls;
0020
0021
0022 void* originalThis;
0023
0024 ConstructDestructCounter() : originalThis(this) { ++s_constructorCalls; }
0025 ConstructDestructCounter(ConstructDestructCounter const&) : originalThis(this) { ++s_constructorCalls; }
0026 ConstructDestructCounter(ConstructDestructCounter&&) : originalThis(this) { ++s_constructorCalls; }
0027 ~ConstructDestructCounter() {
0028 REQUIRE(originalThis == this);
0029 ++s_destructorCalls;
0030 }
0031 };
0032 unsigned int ConstructDestructCounter::s_constructorCalls = 0;
0033 unsigned int ConstructDestructCounter::s_destructorCalls = 0;
0034
0035 struct CharDummy {
0036 char i;
0037 char j;
0038 };
0039
0040 struct ComplexDummy {
0041 char* p;
0042 double f;
0043 };
0044 }
0045
0046 TEST_CASE("edm::SoATuple", "[SoATuple]") {
0047 SECTION("builtinTest") {
0048 edm::SoATuple<int, float, bool> s;
0049 s.reserve(3);
0050 REQUIRE(s.size() == 0);
0051
0052 s.push_back(std::make_tuple(int{1}, float{3.2}, false));
0053 REQUIRE(s.size() == 1);
0054 REQUIRE(1 == s.get<0>(0));
0055 REQUIRE(float{3.2} == s.get<1>(0));
0056 REQUIRE(false == s.get<2>(0));
0057
0058 s.push_back(std::make_tuple(int{2}, float{3.1415}, true));
0059 REQUIRE(s.size() == 2);
0060 REQUIRE(1 == s.get<0>(0));
0061 REQUIRE(float{3.2} == s.get<1>(0));
0062 REQUIRE(false == s.get<2>(0));
0063 REQUIRE(2 == s.get<0>(1));
0064 REQUIRE(float{3.1415} == s.get<1>(1));
0065 REQUIRE(true == s.get<2>(1));
0066
0067 s.push_back(std::make_tuple(int{-1}, float{58.6}, true));
0068 REQUIRE(s.size() == 3);
0069 REQUIRE(1 == s.get<0>(0));
0070 REQUIRE(float{3.2} == s.get<1>(0));
0071 REQUIRE(false == s.get<2>(0));
0072 REQUIRE(2 == s.get<0>(1));
0073 REQUIRE(float{3.1415} == s.get<1>(1));
0074 REQUIRE(true == s.get<2>(1));
0075 REQUIRE(-1 == s.get<0>(2));
0076 REQUIRE(float{58.6} == s.get<1>(2));
0077 REQUIRE(true == s.get<2>(2));
0078 }
0079
0080 SECTION("badPaddingTest") {
0081 edm::SoATuple<bool, int, double> s;
0082 s.reserve(3);
0083 REQUIRE(s.size() == 0);
0084
0085 s.push_back(std::make_tuple(false, int{1}, double{3.2}));
0086 REQUIRE(s.size() == 1);
0087 REQUIRE(1 == s.get<1>(0));
0088 REQUIRE(double{3.2} == s.get<2>(0));
0089 REQUIRE(false == s.get<0>(0));
0090
0091 s.push_back(std::make_tuple(true, int{2}, double{3.1415}));
0092 REQUIRE(s.size() == 2);
0093 REQUIRE(1 == s.get<1>(0));
0094 REQUIRE(double{3.2} == s.get<2>(0));
0095 REQUIRE(false == s.get<0>(0));
0096 REQUIRE(2 == s.get<1>(1));
0097 REQUIRE(double{3.1415} == s.get<2>(1));
0098 REQUIRE(true == s.get<0>(1));
0099
0100 s.push_back(std::make_tuple(true, int{-1}, double{58.6}));
0101 REQUIRE(s.size() == 3);
0102 REQUIRE(1 == s.get<1>(0));
0103 REQUIRE(double{3.2} == s.get<2>(0));
0104 REQUIRE(false == s.get<0>(0));
0105 REQUIRE(2 == s.get<1>(1));
0106 REQUIRE(double{3.1415} == s.get<2>(1));
0107 REQUIRE(true == s.get<0>(1));
0108 REQUIRE(-1 == s.get<1>(2));
0109 REQUIRE(double{58.6} == s.get<2>(2));
0110 REQUIRE(true == s.get<0>(2));
0111 }
0112
0113 SECTION("classTest") {
0114 ConstructDestructCounter::s_constructorCalls = 0;
0115 ConstructDestructCounter::s_destructorCalls = 0;
0116 REQUIRE(ConstructDestructCounter::s_constructorCalls == ConstructDestructCounter::s_destructorCalls);
0117 {
0118 edm::SoATuple<std::string, ConstructDestructCounter> s;
0119 s.reserve(3);
0120 const std::string kFoo{"foo"};
0121 REQUIRE(s.size() == 0);
0122 {
0123 ConstructDestructCounter dummy;
0124 s.push_back(std::make_tuple(kFoo, dummy));
0125 }
0126 REQUIRE(ConstructDestructCounter::s_constructorCalls == ConstructDestructCounter::s_destructorCalls + 1);
0127 REQUIRE(s.size() == 1);
0128 REQUIRE(kFoo == s.get<0>(0));
0129
0130 const std::string kBar{"bar"};
0131 {
0132 ConstructDestructCounter dummy;
0133 s.push_back(std::make_tuple(kBar, dummy));
0134 }
0135 REQUIRE(ConstructDestructCounter::s_constructorCalls == ConstructDestructCounter::s_destructorCalls + 2);
0136 REQUIRE(s.size() == 2);
0137 REQUIRE(kFoo == s.get<0>(0));
0138 REQUIRE(kBar == s.get<0>(1));
0139 }
0140 REQUIRE(ConstructDestructCounter::s_constructorCalls == ConstructDestructCounter::s_destructorCalls);
0141 }
0142
0143 SECTION("growthTest") {
0144 ConstructDestructCounter::s_constructorCalls = 0;
0145 ConstructDestructCounter::s_destructorCalls = 0;
0146 REQUIRE(ConstructDestructCounter::s_constructorCalls == ConstructDestructCounter::s_destructorCalls);
0147 {
0148 edm::SoATuple<unsigned int, ConstructDestructCounter> s;
0149 REQUIRE(s.size() == 0);
0150 REQUIRE(s.capacity() == 0);
0151 for (unsigned int i = 0; i < 100; ++i) {
0152 {
0153 ConstructDestructCounter dummy;
0154 s.push_back(std::make_tuple(i, dummy));
0155 }
0156 REQUIRE(ConstructDestructCounter::s_constructorCalls == ConstructDestructCounter::s_destructorCalls + i + 1);
0157 REQUIRE(s.size() == i + 1);
0158 REQUIRE(s.capacity() >= i + 1);
0159 for (unsigned int j = 0; j < s.size(); ++j) {
0160 REQUIRE(j == s.get<0>(j));
0161 }
0162 }
0163
0164 s.shrink_to_fit();
0165 REQUIRE(s.capacity() == s.size());
0166 REQUIRE(ConstructDestructCounter::s_constructorCalls - ConstructDestructCounter::s_destructorCalls == s.size());
0167 for (unsigned int j = 0; j < s.size(); ++j) {
0168 REQUIRE(j == s.get<0>(j));
0169 }
0170 }
0171
0172 REQUIRE(ConstructDestructCounter::s_constructorCalls == ConstructDestructCounter::s_destructorCalls);
0173 }
0174
0175 SECTION("copyConstructorTest") {
0176 ConstructDestructCounter::s_constructorCalls = 0;
0177 ConstructDestructCounter::s_destructorCalls = 0;
0178 REQUIRE(ConstructDestructCounter::s_constructorCalls == ConstructDestructCounter::s_destructorCalls);
0179 {
0180 edm::SoATuple<unsigned int, ConstructDestructCounter> s;
0181 REQUIRE(s.size() == 0);
0182 REQUIRE(s.capacity() == 0);
0183 for (unsigned int i = 0; i < 100; ++i) {
0184 {
0185 ConstructDestructCounter dummy;
0186 s.push_back(std::make_tuple(i, dummy));
0187 }
0188 edm::SoATuple<unsigned int, ConstructDestructCounter> sCopy(s);
0189 REQUIRE(ConstructDestructCounter::s_constructorCalls ==
0190 ConstructDestructCounter::s_destructorCalls + 2 * i + 2);
0191 REQUIRE(s.size() == i + 1);
0192 REQUIRE(s.capacity() >= i + 1);
0193 REQUIRE(sCopy.size() == i + 1);
0194 REQUIRE(sCopy.capacity() >= i + 1);
0195
0196 for (unsigned int j = 0; j < s.size(); ++j) {
0197 REQUIRE(j == s.get<0>(j));
0198 REQUIRE(j == sCopy.get<0>(j));
0199 }
0200 }
0201 }
0202 REQUIRE(ConstructDestructCounter::s_constructorCalls == ConstructDestructCounter::s_destructorCalls);
0203 }
0204
0205 SECTION("assignmentTest") {
0206 const std::vector<std::string> sValues = {"foo", "fii", "fee"};
0207 edm::SoATuple<std::string, int> s;
0208 s.reserve(sValues.size());
0209 int i = 0;
0210 for (auto const& v : sValues) {
0211 s.push_back(std::make_tuple(v, i));
0212 ++i;
0213 }
0214
0215 edm::SoATuple<std::string, int> sAssign;
0216 sAssign.reserve(2);
0217 sAssign.push_back(std::make_tuple("barney", 10));
0218 sAssign.push_back(std::make_tuple("fred", 7));
0219 REQUIRE(sAssign.size() == 2);
0220
0221 sAssign = s;
0222 REQUIRE(sAssign.size() == s.size());
0223 REQUIRE(sAssign.size() == sValues.size());
0224
0225 i = 0;
0226 for (auto const& v : sValues) {
0227 REQUIRE(v == sAssign.get<0>(i));
0228 REQUIRE(i == sAssign.get<1>(i));
0229 ++i;
0230 }
0231 }
0232
0233 SECTION("moveAssignmentTest") {
0234 const std::vector<std::string> sValues = {"foo", "fii", "fee"};
0235 edm::SoATuple<std::string, int> s;
0236 s.reserve(sValues.size());
0237 int i = 0;
0238 for (auto const& v : sValues) {
0239 s.push_back(std::make_tuple(v, i));
0240 ++i;
0241 }
0242
0243 edm::SoATuple<std::string, int> sAssign;
0244 sAssign.reserve(2);
0245 sAssign.push_back(std::make_tuple("barney", 10));
0246 sAssign.push_back(std::make_tuple("fred", 7));
0247 REQUIRE(sAssign.size() == 2);
0248
0249 sAssign = std::move(s);
0250 REQUIRE(0 == s.size());
0251 REQUIRE(sAssign.size() == sValues.size());
0252
0253 i = 0;
0254 for (auto const& v : sValues) {
0255 REQUIRE(v == sAssign.get<0>(i));
0256 REQUIRE(i == sAssign.get<1>(i));
0257 ++i;
0258 }
0259 }
0260
0261 SECTION("loopTest") {
0262 edm::SoATuple<int, int, int> s;
0263 s.reserve(50);
0264 for (int i = 0; i < 50; ++i) {
0265 s.push_back(std::make_tuple(i, i + 1, i + 2));
0266 }
0267 REQUIRE(50 == s.size());
0268 int index = 0;
0269 for (auto it = s.begin<0>(), itEnd = s.end<0>(); it != itEnd; ++it, ++index) {
0270 REQUIRE(index == *it);
0271 }
0272 index = 1;
0273 for (auto it = s.begin<1>(), itEnd = s.end<1>(); it != itEnd; ++it, ++index) {
0274 REQUIRE(index == *it);
0275 }
0276
0277 index = 2;
0278 for (auto it = s.begin<2>(), itEnd = s.end<2>(); it != itEnd; ++it, ++index) {
0279 REQUIRE(index == *it);
0280 }
0281 }
0282
0283 SECTION("emplace_backTest") {
0284 const std::vector<std::string> sValues = {"foo", "fii", "fee"};
0285 edm::SoATuple<std::string, int> s;
0286 s.reserve(sValues.size());
0287 int i = 0;
0288 for (auto const& v : sValues) {
0289 s.emplace_back(v, i);
0290 ++i;
0291 }
0292 i = 0;
0293 for (auto const& v : sValues) {
0294 REQUIRE(v == s.get<0>(i));
0295 REQUIRE(i == s.get<1>(i));
0296 ++i;
0297 }
0298 }
0299
0300 SECTION("alignmentTest") {
0301 REQUIRE((alignof(double) == edm::soahelper::SoATupleHelper<2, double, bool>::max_alignment));
0302 REQUIRE((alignof(double) == edm::soahelper::SoATupleHelper<2, bool, double>::max_alignment));
0303 REQUIRE((alignof(float) == edm::soahelper::SoATupleHelper<2, float, bool>::max_alignment));
0304 REQUIRE((alignof(float) == edm::soahelper::SoATupleHelper<2, bool, float>::max_alignment));
0305 REQUIRE((alignof(CharDummy) == edm::soahelper::SoATupleHelper<2, char, CharDummy>::max_alignment));
0306 REQUIRE((alignof(CharDummy) == edm::soahelper::SoATupleHelper<2, CharDummy, char>::max_alignment));
0307 REQUIRE((alignof(ComplexDummy) == edm::soahelper::SoATupleHelper<2, char, ComplexDummy>::max_alignment));
0308 REQUIRE((alignof(ComplexDummy) == edm::soahelper::SoATupleHelper<2, ComplexDummy, char>::max_alignment));
0309
0310 REQUIRE((alignof(float) == edm::soahelper::SoATupleHelper<2, float, float>::max_alignment));
0311 REQUIRE((16 == edm::soahelper::SoATupleHelper<2, edm::AlignedVec<float>, edm::AlignedVec<float>>::max_alignment));
0312
0313 REQUIRE((alignof(double) == edm::soahelper::SoATupleHelper<2, double, double>::max_alignment));
0314 REQUIRE((16 == edm::soahelper::SoATupleHelper<2, edm::AlignedVec<double>, edm::AlignedVec<double>>::max_alignment));
0315
0316 edm::SoATuple<edm::AlignedVec<float>, edm::AlignedVec<float>, edm::AlignedVec<float>> vFloats;
0317 vFloats.reserve(50);
0318 for (unsigned int i = 0; i < 50; ++i) {
0319 vFloats.emplace_back(1.0f, 2.0f, 3.0f);
0320 }
0321 REQUIRE(reinterpret_cast<std::intptr_t>(vFloats.begin<0>()) % 16 == 0);
0322 REQUIRE(reinterpret_cast<std::intptr_t>(vFloats.begin<1>()) % 16 == 0);
0323 REQUIRE(reinterpret_cast<std::intptr_t>(vFloats.begin<2>()) % 16 == 0);
0324 }
0325 }