Changeset View
Changeset View
Standalone View
Standalone View
llvm/unittests/Support/BinaryStreamTest.cpp
Show All 19 Lines | |||||
using namespace llvm; | using namespace llvm; | ||||
using namespace llvm::support; | using namespace llvm::support; | ||||
namespace { | namespace { | ||||
class BrokenStream : public WritableBinaryStream { | class BrokenStream : public WritableBinaryStream { | ||||
public: | public: | ||||
BrokenStream(MutableArrayRef<uint8_t> Data, endianness Endian, | BrokenStream(MutableArrayRef<uint8_t> Data, endianness Endian, uint32_t Align) | ||||
uint32_t Align) | |||||
: Data(Data), PartitionIndex(alignDown(Data.size() / 2, Align)), | : Data(Data), PartitionIndex(alignDown(Data.size() / 2, Align)), | ||||
Endian(Endian) {} | Endian(Endian) {} | ||||
endianness getEndian() const override { return Endian; } | endianness getEndian() const override { return Endian; } | ||||
Error readBytes(uint32_t Offset, uint32_t Size, | Error readBytes(uint64_t Offset, uint64_t Size, | ||||
ArrayRef<uint8_t> &Buffer) override { | ArrayRef<uint8_t> &Buffer) override { | ||||
if (auto EC = checkOffsetForRead(Offset, Size)) | if (auto EC = checkOffsetForRead(Offset, Size)) | ||||
return EC; | return EC; | ||||
uint32_t S = startIndex(Offset); | uint64_t S = startIndex(Offset); | ||||
auto Ref = Data.drop_front(S); | auto Ref = Data.drop_front(S); | ||||
if (Ref.size() >= Size) { | if (Ref.size() >= Size) { | ||||
Buffer = Ref.take_front(Size); | Buffer = Ref.take_front(Size); | ||||
return Error::success(); | return Error::success(); | ||||
} | } | ||||
uint32_t BytesLeft = Size - Ref.size(); | uint64_t BytesLeft = Size - Ref.size(); | ||||
uint8_t *Ptr = Allocator.Allocate<uint8_t>(Size); | uint8_t *Ptr = Allocator.Allocate<uint8_t>(Size); | ||||
::memcpy(Ptr, Ref.data(), Ref.size()); | ::memcpy(Ptr, Ref.data(), Ref.size()); | ||||
::memcpy(Ptr + Ref.size(), Data.data(), BytesLeft); | ::memcpy(Ptr + Ref.size(), Data.data(), BytesLeft); | ||||
Buffer = makeArrayRef<uint8_t>(Ptr, Size); | Buffer = makeArrayRef<uint8_t>(Ptr, Size); | ||||
return Error::success(); | return Error::success(); | ||||
} | } | ||||
Error readLongestContiguousChunk(uint32_t Offset, | Error readLongestContiguousChunk(uint64_t Offset, | ||||
ArrayRef<uint8_t> &Buffer) override { | ArrayRef<uint8_t> &Buffer) override { | ||||
if (auto EC = checkOffsetForRead(Offset, 1)) | if (auto EC = checkOffsetForRead(Offset, 1)) | ||||
return EC; | return EC; | ||||
uint32_t S = startIndex(Offset); | uint64_t S = startIndex(Offset); | ||||
Buffer = Data.drop_front(S); | Buffer = Data.drop_front(S); | ||||
return Error::success(); | return Error::success(); | ||||
} | } | ||||
uint32_t getLength() override { return Data.size(); } | uint64_t getLength() override { return Data.size(); } | ||||
Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> SrcData) override { | Error writeBytes(uint64_t Offset, ArrayRef<uint8_t> SrcData) override { | ||||
if (auto EC = checkOffsetForWrite(Offset, SrcData.size())) | if (auto EC = checkOffsetForWrite(Offset, SrcData.size())) | ||||
return EC; | return EC; | ||||
if (SrcData.empty()) | if (SrcData.empty()) | ||||
return Error::success(); | return Error::success(); | ||||
uint32_t S = startIndex(Offset); | uint64_t S = startIndex(Offset); | ||||
MutableArrayRef<uint8_t> Ref(Data); | MutableArrayRef<uint8_t> Ref(Data); | ||||
Ref = Ref.drop_front(S); | Ref = Ref.drop_front(S); | ||||
if (Ref.size() >= SrcData.size()) { | if (Ref.size() >= SrcData.size()) { | ||||
::memcpy(Ref.data(), SrcData.data(), SrcData.size()); | ::memcpy(Ref.data(), SrcData.data(), SrcData.size()); | ||||
return Error::success(); | return Error::success(); | ||||
} | } | ||||
uint32_t BytesLeft = SrcData.size() - Ref.size(); | uint64_t BytesLeft = SrcData.size() - Ref.size(); | ||||
::memcpy(Ref.data(), SrcData.data(), Ref.size()); | ::memcpy(Ref.data(), SrcData.data(), Ref.size()); | ||||
::memcpy(&Data[0], SrcData.data() + Ref.size(), BytesLeft); | ::memcpy(&Data[0], SrcData.data() + Ref.size(), BytesLeft); | ||||
return Error::success(); | return Error::success(); | ||||
} | } | ||||
Error commit() override { return Error::success(); } | Error commit() override { return Error::success(); } | ||||
private: | private: | ||||
uint32_t startIndex(uint32_t Offset) const { | uint64_t startIndex(uint64_t Offset) const { | ||||
return (Offset + PartitionIndex) % Data.size(); | return (Offset + PartitionIndex) % Data.size(); | ||||
} | } | ||||
uint32_t endIndex(uint32_t Offset, uint32_t Size) const { | uint64_t endIndex(uint64_t Offset, uint64_t Size) const { | ||||
return (startIndex(Offset) + Size - 1) % Data.size(); | return (startIndex(Offset) + Size - 1) % Data.size(); | ||||
} | } | ||||
// Buffer is organized like this: | // Buffer is organized like this: | ||||
// ------------------------------------------------- | // ------------------------------------------------- | ||||
// | N/2 | N/2+1 | ... | N-1 | 0 | 1 | ... | N/2-1 | | // | N/2 | N/2+1 | ... | N-1 | 0 | 1 | ... | N/2-1 | | ||||
// ------------------------------------------------- | // ------------------------------------------------- | ||||
// So reads from the beginning actually come from the middle. | // So reads from the beginning actually come from the middle. | ||||
Show All 29 Lines | struct StreamPair { | ||||
std::unique_ptr<WritableBinaryStream> Output; | std::unique_ptr<WritableBinaryStream> Output; | ||||
}; | }; | ||||
void initializeInput(ArrayRef<uint8_t> Input, uint32_t Align) { | void initializeInput(ArrayRef<uint8_t> Input, uint32_t Align) { | ||||
InputData = Input; | InputData = Input; | ||||
BrokenInputData.resize(InputData.size()); | BrokenInputData.resize(InputData.size()); | ||||
if (!Input.empty()) { | if (!Input.empty()) { | ||||
uint32_t PartitionIndex = alignDown(InputData.size() / 2, Align); | uint64_t PartitionIndex = alignDown(InputData.size() / 2, Align); | ||||
uint32_t RightBytes = InputData.size() - PartitionIndex; | uint64_t RightBytes = InputData.size() - PartitionIndex; | ||||
uint32_t LeftBytes = PartitionIndex; | uint64_t LeftBytes = PartitionIndex; | ||||
if (RightBytes > 0) | if (RightBytes > 0) | ||||
::memcpy(&BrokenInputData[PartitionIndex], Input.data(), RightBytes); | ::memcpy(&BrokenInputData[PartitionIndex], Input.data(), RightBytes); | ||||
if (LeftBytes > 0) | if (LeftBytes > 0) | ||||
::memcpy(&BrokenInputData[0], Input.data() + RightBytes, LeftBytes); | ::memcpy(&BrokenInputData[0], Input.data() + RightBytes, LeftBytes); | ||||
} | } | ||||
for (uint32_t I = 0; I < NumEndians; ++I) { | for (uint32_t I = 0; I < NumEndians; ++I) { | ||||
auto InByteStream = | auto InByteStream = | ||||
std::make_unique<BinaryByteStream>(InputData, Endians[I]); | std::make_unique<BinaryByteStream>(InputData, Endians[I]); | ||||
auto InBrokenStream = std::make_unique<BrokenStream>( | auto InBrokenStream = std::make_unique<BrokenStream>( | ||||
BrokenInputData, Endians[I], Align); | BrokenInputData, Endians[I], Align); | ||||
Streams[I * 2].Input = std::move(InByteStream); | Streams[I * 2].Input = std::move(InByteStream); | ||||
Streams[I * 2 + 1].Input = std::move(InBrokenStream); | Streams[I * 2 + 1].Input = std::move(InBrokenStream); | ||||
} | } | ||||
} | } | ||||
void initializeOutput(uint32_t Size, uint32_t Align) { | void initializeOutput(uint64_t Size, uint32_t Align) { | ||||
OutputData.resize(Size); | OutputData.resize(Size); | ||||
BrokenOutputData.resize(Size); | BrokenOutputData.resize(Size); | ||||
for (uint32_t I = 0; I < NumEndians; ++I) { | for (uint32_t I = 0; I < NumEndians; ++I) { | ||||
Streams[I * 2].Output = | Streams[I * 2].Output = | ||||
std::make_unique<MutableBinaryByteStream>(OutputData, Endians[I]); | std::make_unique<MutableBinaryByteStream>(OutputData, Endians[I]); | ||||
Streams[I * 2 + 1].Output = std::make_unique<BrokenStream>( | Streams[I * 2 + 1].Output = std::make_unique<BrokenStream>( | ||||
BrokenOutputData, Endians[I], Align); | BrokenOutputData, Endians[I], Align); | ||||
▲ Show 20 Lines • Show All 197 Lines • ▼ Show 20 Lines | TEST_F(BinaryStreamTest, MutableBinaryByteStreamBounds) { | ||||
// For every combination of input stream and output stream. | // For every combination of input stream and output stream. | ||||
for (auto &Stream : Streams) { | for (auto &Stream : Streams) { | ||||
ASSERT_EQ(InputData.size(), Stream.Input->getLength()); | ASSERT_EQ(InputData.size(), Stream.Input->getLength()); | ||||
// 1. Try two reads that are supposed to work. One from offset 0, and one | // 1. Try two reads that are supposed to work. One from offset 0, and one | ||||
// from the middle. | // from the middle. | ||||
uint32_t Offsets[] = {0, 3}; | uint32_t Offsets[] = {0, 3}; | ||||
for (auto Offset : Offsets) { | for (auto Offset : Offsets) { | ||||
uint32_t ExpectedSize = Stream.Input->getLength() - Offset; | uint64_t ExpectedSize = Stream.Input->getLength() - Offset; | ||||
// Read everything from Offset until the end of the input data. | // Read everything from Offset until the end of the input data. | ||||
ArrayRef<uint8_t> Data; | ArrayRef<uint8_t> Data; | ||||
ASSERT_THAT_ERROR(Stream.Input->readBytes(Offset, ExpectedSize, Data), | ASSERT_THAT_ERROR(Stream.Input->readBytes(Offset, ExpectedSize, Data), | ||||
Succeeded()); | Succeeded()); | ||||
ASSERT_EQ(ExpectedSize, Data.size()); | ASSERT_EQ(ExpectedSize, Data.size()); | ||||
// Then write it to the destination. | // Then write it to the destination. | ||||
▲ Show 20 Lines • Show All 528 Lines • Show Last 20 Lines |