BinaryStreamRef.h revision 321369
1//===- BinaryStreamRef.h - A copyable reference to a stream -----*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#ifndef LLVM_SUPPORT_BINARYSTREAMREF_H
11#define LLVM_SUPPORT_BINARYSTREAMREF_H
12
13#include "llvm/ADT/ArrayRef.h"
14#include "llvm/Support/BinaryStream.h"
15#include "llvm/Support/BinaryStreamError.h"
16#include "llvm/Support/Error.h"
17#include <algorithm>
18#include <cstdint>
19#include <memory>
20
21namespace llvm {
22
23/// Common stuff for mutable and immutable StreamRefs.
24template <class RefType, class StreamType> class BinaryStreamRefBase {
25protected:
26  BinaryStreamRefBase() = default;
27  BinaryStreamRefBase(std::shared_ptr<StreamType> SharedImpl, uint32_t Offset,
28                      uint32_t Length)
29      : SharedImpl(SharedImpl), BorrowedImpl(SharedImpl.get()),
30        ViewOffset(Offset), Length(Length) {}
31  BinaryStreamRefBase(StreamType &BorrowedImpl, uint32_t Offset,
32                      uint32_t Length)
33      : BorrowedImpl(&BorrowedImpl), ViewOffset(Offset), Length(Length) {}
34  BinaryStreamRefBase(const BinaryStreamRefBase &Other) {
35    SharedImpl = Other.SharedImpl;
36    BorrowedImpl = Other.BorrowedImpl;
37    ViewOffset = Other.ViewOffset;
38    Length = Other.Length;
39  }
40
41public:
42  llvm::support::endianness getEndian() const {
43    return BorrowedImpl->getEndian();
44  }
45
46  uint32_t getLength() const { return Length; }
47
48  /// Return a new BinaryStreamRef with the first \p N elements removed.
49  RefType drop_front(uint32_t N) const {
50    if (!BorrowedImpl)
51      return RefType();
52
53    N = std::min(N, Length);
54    RefType Result(static_cast<const RefType &>(*this));
55    Result.ViewOffset += N;
56    Result.Length -= N;
57    return Result;
58  }
59
60  /// Return a new BinaryStreamRef with the first \p N elements removed.
61  RefType drop_back(uint32_t N) const {
62    if (!BorrowedImpl)
63      return RefType();
64
65    N = std::min(N, Length);
66    RefType Result(static_cast<const RefType &>(*this));
67    Result.Length -= N;
68    return Result;
69  }
70
71  /// Return a new BinaryStreamRef with only the first \p N elements remaining.
72  RefType keep_front(uint32_t N) const {
73    assert(N <= getLength());
74    return drop_back(getLength() - N);
75  }
76
77  /// Return a new BinaryStreamRef with only the last \p N elements remaining.
78  RefType keep_back(uint32_t N) const {
79    assert(N <= getLength());
80    return drop_front(getLength() - N);
81  }
82
83  /// Return a new BinaryStreamRef with the first and last \p N elements
84  /// removed.
85  RefType drop_symmetric(uint32_t N) const {
86    return drop_front(N).drop_back(N);
87  }
88
89  /// Return a new BinaryStreamRef with the first \p Offset elements removed,
90  /// and retaining exactly \p Len elements.
91  RefType slice(uint32_t Offset, uint32_t Len) const {
92    return drop_front(Offset).keep_front(Len);
93  }
94
95  bool valid() const { return BorrowedImpl != nullptr; }
96
97  bool operator==(const RefType &Other) const {
98    if (BorrowedImpl != Other.BorrowedImpl)
99      return false;
100    if (ViewOffset != Other.ViewOffset)
101      return false;
102    if (Length != Other.Length)
103      return false;
104    return true;
105  }
106
107protected:
108  Error checkOffset(uint32_t Offset, uint32_t DataSize) const {
109    if (Offset > getLength())
110      return make_error<BinaryStreamError>(stream_error_code::invalid_offset);
111    if (getLength() < DataSize + Offset)
112      return make_error<BinaryStreamError>(stream_error_code::stream_too_short);
113    return Error::success();
114  }
115
116  std::shared_ptr<StreamType> SharedImpl;
117  StreamType *BorrowedImpl = nullptr;
118  uint32_t ViewOffset = 0;
119  uint32_t Length = 0;
120};
121
122/// \brief BinaryStreamRef is to BinaryStream what ArrayRef is to an Array.  It
123/// provides copy-semantics and read only access to a "window" of the underlying
124/// BinaryStream. Note that BinaryStreamRef is *not* a BinaryStream.  That is to
125/// say, it does not inherit and override the methods of BinaryStream.  In
126/// general, you should not pass around pointers or references to BinaryStreams
127/// and use inheritance to achieve polymorphism.  Instead, you should pass
128/// around BinaryStreamRefs by value and achieve polymorphism that way.
129class BinaryStreamRef
130    : public BinaryStreamRefBase<BinaryStreamRef, BinaryStream> {
131  friend BinaryStreamRefBase<BinaryStreamRef, BinaryStream>;
132  friend class WritableBinaryStreamRef;
133  BinaryStreamRef(std::shared_ptr<BinaryStream> Impl, uint32_t ViewOffset,
134                  uint32_t Length)
135      : BinaryStreamRefBase(Impl, ViewOffset, Length) {}
136
137public:
138  BinaryStreamRef() = default;
139  BinaryStreamRef(BinaryStream &Stream);
140  BinaryStreamRef(BinaryStream &Stream, uint32_t Offset, uint32_t Length);
141  explicit BinaryStreamRef(ArrayRef<uint8_t> Data,
142                           llvm::support::endianness Endian);
143  explicit BinaryStreamRef(StringRef Data, llvm::support::endianness Endian);
144
145  BinaryStreamRef(const BinaryStreamRef &Other);
146
147  // Use BinaryStreamRef.slice() instead.
148  BinaryStreamRef(BinaryStreamRef &S, uint32_t Offset,
149                  uint32_t Length) = delete;
150
151  /// Given an Offset into this StreamRef and a Size, return a reference to a
152  /// buffer owned by the stream.
153  ///
154  /// \returns a success error code if the entire range of data is within the
155  /// bounds of this BinaryStreamRef's view and the implementation could read
156  /// the data, and an appropriate error code otherwise.
157  Error readBytes(uint32_t Offset, uint32_t Size,
158                  ArrayRef<uint8_t> &Buffer) const;
159
160  /// Given an Offset into this BinaryStreamRef, return a reference to the
161  /// largest buffer the stream could support without necessitating a copy.
162  ///
163  /// \returns a success error code if implementation could read the data,
164  /// and an appropriate error code otherwise.
165  Error readLongestContiguousChunk(uint32_t Offset,
166                                   ArrayRef<uint8_t> &Buffer) const;
167};
168
169struct BinarySubstreamRef {
170  uint32_t Offset;            // Offset in the parent stream
171  BinaryStreamRef StreamData; // Stream Data
172
173  BinarySubstreamRef slice(uint32_t Off, uint32_t Size) const {
174    BinaryStreamRef SubSub = StreamData.slice(Off, Size);
175    return {Off + Offset, SubSub};
176  }
177  BinarySubstreamRef drop_front(uint32_t N) const {
178    return slice(N, size() - N);
179  }
180  BinarySubstreamRef keep_front(uint32_t N) const { return slice(0, N); }
181
182  std::pair<BinarySubstreamRef, BinarySubstreamRef>
183  split(uint32_t Offset) const {
184    return std::make_pair(keep_front(Offset), drop_front(Offset));
185  }
186
187  uint32_t size() const { return StreamData.getLength(); }
188  bool empty() const { return size() == 0; }
189};
190
191class WritableBinaryStreamRef
192    : public BinaryStreamRefBase<WritableBinaryStreamRef,
193                                 WritableBinaryStream> {
194  friend BinaryStreamRefBase<WritableBinaryStreamRef, WritableBinaryStream>;
195  WritableBinaryStreamRef(std::shared_ptr<WritableBinaryStream> Impl,
196                          uint32_t ViewOffset, uint32_t Length)
197      : BinaryStreamRefBase(Impl, ViewOffset, Length) {}
198
199public:
200  WritableBinaryStreamRef() = default;
201  WritableBinaryStreamRef(WritableBinaryStream &Stream);
202  WritableBinaryStreamRef(WritableBinaryStream &Stream, uint32_t Offset,
203                          uint32_t Length);
204  explicit WritableBinaryStreamRef(MutableArrayRef<uint8_t> Data,
205                                   llvm::support::endianness Endian);
206  WritableBinaryStreamRef(const WritableBinaryStreamRef &Other);
207
208  // Use WritableBinaryStreamRef.slice() instead.
209  WritableBinaryStreamRef(WritableBinaryStreamRef &S, uint32_t Offset,
210                          uint32_t Length) = delete;
211
212  /// Given an Offset into this WritableBinaryStreamRef and some input data,
213  /// writes the data to the underlying stream.
214  ///
215  /// \returns a success error code if the data could fit within the underlying
216  /// stream at the specified location and the implementation could write the
217  /// data, and an appropriate error code otherwise.
218  Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Data) const;
219
220  /// Conver this WritableBinaryStreamRef to a read-only BinaryStreamRef.
221  operator BinaryStreamRef() const;
222
223  /// \brief For buffered streams, commits changes to the backing store.
224  Error commit();
225};
226
227} // end namespace llvm
228
229#endif // LLVM_SUPPORT_BINARYSTREAMREF_H
230