1 //===- BinaryItemStream.h ---------------------------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_SUPPORT_BINARYITEMSTREAM_H
10 #define LLVM_SUPPORT_BINARYITEMSTREAM_H
12 #include "llvm/ADT/ArrayRef.h"
13 #include "llvm/Support/BinaryStream.h"
14 #include "llvm/Support/BinaryStreamError.h"
15 #include "llvm/Support/Error.h"
21 template <typename T
> struct BinaryItemTraits
{
22 static size_t length(const T
&Item
) = delete;
23 static ArrayRef
<uint8_t> bytes(const T
&Item
) = delete;
26 /// BinaryItemStream represents a sequence of objects stored in some kind of
27 /// external container but for which it is useful to view as a stream of
28 /// contiguous bytes. An example of this might be if you have a collection of
29 /// records and you serialize each one into a buffer, and store these serialized
30 /// records in a container. The pointers themselves are not laid out
31 /// contiguously in memory, but we may wish to read from or write to these
32 /// records as if they were.
33 template <typename T
, typename Traits
= BinaryItemTraits
<T
>>
34 class BinaryItemStream
: public BinaryStream
{
36 explicit BinaryItemStream(llvm::support::endianness Endian
)
39 llvm::support::endianness
getEndian() const override
{ return Endian
; }
41 Error
readBytes(uint32_t Offset
, uint32_t Size
,
42 ArrayRef
<uint8_t> &Buffer
) override
{
43 auto ExpectedIndex
= translateOffsetIndex(Offset
);
45 return ExpectedIndex
.takeError();
46 const auto &Item
= Items
[*ExpectedIndex
];
47 if (auto EC
= checkOffsetForRead(Offset
, Size
))
49 if (Size
> Traits::length(Item
))
50 return make_error
<BinaryStreamError
>(stream_error_code::stream_too_short
);
51 Buffer
= Traits::bytes(Item
).take_front(Size
);
52 return Error::success();
55 Error
readLongestContiguousChunk(uint32_t Offset
,
56 ArrayRef
<uint8_t> &Buffer
) override
{
57 auto ExpectedIndex
= translateOffsetIndex(Offset
);
59 return ExpectedIndex
.takeError();
60 Buffer
= Traits::bytes(Items
[*ExpectedIndex
]);
61 return Error::success();
64 void setItems(ArrayRef
<T
> ItemArray
) {
69 uint32_t getLength() override
{
70 return ItemEndOffsets
.empty() ? 0 : ItemEndOffsets
.back();
74 void computeItemOffsets() {
75 ItemEndOffsets
.clear();
76 ItemEndOffsets
.reserve(Items
.size());
77 uint32_t CurrentOffset
= 0;
78 for (const auto &Item
: Items
) {
79 uint32_t Len
= Traits::length(Item
);
80 assert(Len
> 0 && "no empty items");
82 ItemEndOffsets
.push_back(CurrentOffset
);
86 Expected
<uint32_t> translateOffsetIndex(uint32_t Offset
) {
87 // Make sure the offset is somewhere in our items array.
88 if (Offset
>= getLength())
89 return make_error
<BinaryStreamError
>(stream_error_code::stream_too_short
);
92 std::lower_bound(ItemEndOffsets
.begin(), ItemEndOffsets
.end(), Offset
);
93 size_t Idx
= std::distance(ItemEndOffsets
.begin(), Iter
);
94 assert(Idx
< Items
.size() && "binary search for offset failed");
98 llvm::support::endianness Endian
;
101 // Sorted vector of offsets to accelerate lookup.
102 std::vector
<uint32_t> ItemEndOffsets
;
105 } // end namespace llvm
107 #endif // LLVM_SUPPORT_BINARYITEMSTREAM_H