Skip to content

Commit 9994ce9

Browse files
committed
[ntuple] fix up vector resize for over-aligned values
1 parent 6ab801f commit 9994ce9

3 files changed

Lines changed: 36 additions & 3 deletions

File tree

tree/ntuple/inc/ROOT/RField/RFieldSequenceContainer.hxx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,9 @@ protected:
260260
void CommitClusterImpl() final { fNWritten = 0; }
261261

262262
public:
263+
/// Maximum alignment of the vector's value type
264+
static constexpr std::size_t kMaxItemAlignment = 4096;
265+
263266
RVectorField(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField);
264267
RVectorField(RVectorField &&other) = default;
265268
RVectorField &operator=(RVectorField &&other) = default;

tree/ntuple/src/RFieldSequenceContainer.cxx

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -567,7 +567,38 @@ void ROOT::RVectorField::ResizeVector(void *vec, std::size_t nItems, std::size_t
567567
itemDeleter->operator()(typedValue->data() + (i * itemSize), true /* dtorOnly */);
568568
}
569569
}
570-
typedValue->resize(nItems * itemSize);
570+
571+
// Resize the vector with correct alignment
572+
const auto itemAlignment = itemField.GetAlignment();
573+
const auto nbytes = nItems * itemSize;
574+
if ((oldNItems >= nItems) || (itemAlignment <= sizeof(std::max_align_t))) {
575+
typedValue->resize(nbytes);
576+
} else {
577+
auto fnAlignedResize = [](auto &vecOfAlignedStorage, std::size_t targetSize) {
578+
constexpr auto valueTypeSize = sizeof(typename std::decay_t<decltype(vecOfAlignedStorage)>::value_type);
579+
constexpr auto valueTypeAlignment = alignof(typename std::decay_t<decltype(vecOfAlignedStorage)>::value_type);
580+
static_assert(valueTypeSize == valueTypeAlignment);
581+
assert(targetSize % valueTypeAlignment == 0);
582+
vecOfAlignedStorage.resize(targetSize / valueTypeSize);
583+
};
584+
585+
static_assert(sizeof(std::max_align_t) >= 8 && kMaxItemAlignment == 4096);
586+
// clang-format off
587+
switch (itemAlignment) {
588+
case 16: fnAlignedResize(*static_cast<std::vector<Internal::RAlignedStorage< 16>> *>(vec), nbytes); break;
589+
case 32: fnAlignedResize(*static_cast<std::vector<Internal::RAlignedStorage< 32>> *>(vec), nbytes); break;
590+
case 64: fnAlignedResize(*static_cast<std::vector<Internal::RAlignedStorage< 64>> *>(vec), nbytes); break;
591+
case 128: fnAlignedResize(*static_cast<std::vector<Internal::RAlignedStorage< 128>> *>(vec), nbytes); break;
592+
case 256: fnAlignedResize(*static_cast<std::vector<Internal::RAlignedStorage< 256>> *>(vec), nbytes); break;
593+
case 512: fnAlignedResize(*static_cast<std::vector<Internal::RAlignedStorage< 512>> *>(vec), nbytes); break;
594+
case 1024: fnAlignedResize(*static_cast<std::vector<Internal::RAlignedStorage<1024>> *>(vec), nbytes); break;
595+
case 2048: fnAlignedResize(*static_cast<std::vector<Internal::RAlignedStorage<2048>> *>(vec), nbytes); break;
596+
case 4096: fnAlignedResize(*static_cast<std::vector<Internal::RAlignedStorage<4096>> *>(vec), nbytes); break;
597+
default: throw RException(R__FAIL(std::string("Unsupported alignment: ") + std::to_string(itemAlignment)));
598+
}
599+
// clang-format on
600+
}
601+
571602
if (!(itemField.GetTraits() & kTraitTriviallyConstructible)) {
572603
for (std::size_t i = allDeallocated ? 0 : oldNItems; i < nItems; ++i) {
573604
CallConstructValueOn(itemField, typedValue->data() + (i * itemSize));

tree/ntuple/test/rfield_class.cxx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,5 @@ TEST(RNTuple, AlignmentCornerCases)
540540

541541
auto view = reader->GetView<AlignmentEnvelope>("f");
542542
EXPECT_EQ(1u, view(0).fVec.size());
543-
// TODO(jblomer): FIXME
544-
// EXPECT_EQ(0, reinterpret_cast<std::uintptr_t>(view(0).fVec.data()) % alignof(OverAligned));
543+
EXPECT_EQ(0, reinterpret_cast<std::uintptr_t>(view(0).fVec.data()) % alignof(OverAligned));
545544
}

0 commit comments

Comments
 (0)