BinaryStreamRef.h revision 317017
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
20namespace llvm {
21
22/// Common stuff for mutable and immutable StreamRefs.
23template <class StreamType, class RefType> class BinaryStreamRefBase {
24public:
25  BinaryStreamRefBase() : Stream(nullptr), ViewOffset(0), Length(0) {}
26  BinaryStreamRefBase(StreamType &Stream, uint32_t Offset, uint32_t Length)
27      : Stream(&Stream), ViewOffset(Offset), Length(Length) {}
28
29  llvm::support::endianness getEndian() const { return Stream->getEndian(); }
30
31  uint32_t getLength() const { return Length; }
32  const StreamType *getStream() const { return Stream; }
33
34  /// Return a new BinaryStreamRef with the first \p N elements removed.
35  RefType drop_front(uint32_t N) const {
36    if (!Stream)
37      return RefType();
38
39    N = std::min(N, Length);
40    return RefType(*Stream, ViewOffset + N, Length - N);
41  }
42
43  /// Return a new BinaryStreamRef with only the first \p N elements remaining.
44  RefType keep_front(uint32_t N) const {
45    if (!Stream)
46      return RefType();
47    N = std::min(N, Length);
48    return RefType(*Stream, ViewOffset, N);
49  }
50
51  /// Return a new BinaryStreamRef with the first \p Offset elements removed,
52  /// and retaining exactly \p Len elements.
53  RefType slice(uint32_t Offset, uint32_t Len) const {
54    return drop_front(Offset).keep_front(Len);
55  }
56
57  bool operator==(const RefType &Other) const {
58    if (Stream != Other.Stream)
59      return false;
60    if (ViewOffset != Other.ViewOffset)
61      return false;
62    if (Length != Other.Length)
63      return false;
64    return true;
65  }
66
67protected:
68  Error checkOffset(uint32_t Offset, uint32_t DataSize) const {
69    if (Offset > getLength())
70      return make_error<BinaryStreamError>(stream_error_code::invalid_offset);
71    if (getLength() < DataSize + Offset)
72      return make_error<BinaryStreamError>(stream_error_code::stream_too_short);
73    return Error::success();
74  }
75
76  StreamType *Stream;
77  uint32_t ViewOffset;
78  uint32_t Length;
79};
80
81/// \brief BinaryStreamRef is to BinaryStream what ArrayRef is to an Array.  It
82/// provides copy-semantics and read only access to a "window" of the underlying
83/// BinaryStream. Note that BinaryStreamRef is *not* a BinaryStream.  That is to
84/// say, it does not inherit and override the methods of BinaryStream.  In
85/// general, you should not pass around pointers or references to BinaryStreams
86/// and use inheritance to achieve polymorphism.  Instead, you should pass
87/// around BinaryStreamRefs by value and achieve polymorphism that way.
88class BinaryStreamRef
89    : public BinaryStreamRefBase<BinaryStream, BinaryStreamRef> {
90public:
91  BinaryStreamRef() = default;
92  BinaryStreamRef(BinaryStream &Stream)
93      : BinaryStreamRefBase(Stream, 0, Stream.getLength()) {}
94  BinaryStreamRef(BinaryStream &Stream, uint32_t Offset, uint32_t Length)
95      : BinaryStreamRefBase(Stream, Offset, Length) {}
96
97  // Use BinaryStreamRef.slice() instead.
98  BinaryStreamRef(BinaryStreamRef &S, uint32_t Offset,
99                  uint32_t Length) = delete;
100
101  /// Given an Offset into this StreamRef and a Size, return a reference to a
102  /// buffer owned by the stream.
103  ///
104  /// \returns a success error code if the entire range of data is within the
105  /// bounds of this BinaryStreamRef's view and the implementation could read
106  /// the data, and an appropriate error code otherwise.
107  Error readBytes(uint32_t Offset, uint32_t Size,
108                  ArrayRef<uint8_t> &Buffer) const {
109    if (auto EC = checkOffset(Offset, Size))
110      return EC;
111
112    return Stream->readBytes(ViewOffset + Offset, Size, Buffer);
113  }
114
115  /// Given an Offset into this BinaryStreamRef, return a reference to the
116  /// largest buffer the stream could support without necessitating a copy.
117  ///
118  /// \returns a success error code if implementation could read the data,
119  /// and an appropriate error code otherwise.
120  Error readLongestContiguousChunk(uint32_t Offset,
121                                   ArrayRef<uint8_t> &Buffer) const {
122    if (auto EC = checkOffset(Offset, 1))
123      return EC;
124
125    if (auto EC =
126            Stream->readLongestContiguousChunk(ViewOffset + Offset, Buffer))
127      return EC;
128    // This StreamRef might refer to a smaller window over a larger stream.  In
129    // that case we will have read out more bytes than we should return, because
130    // we should not read past the end of the current view.
131    uint32_t MaxLength = Length - Offset;
132    if (Buffer.size() > MaxLength)
133      Buffer = Buffer.slice(0, MaxLength);
134    return Error::success();
135  }
136};
137
138class WritableBinaryStreamRef
139    : public BinaryStreamRefBase<WritableBinaryStream,
140                                 WritableBinaryStreamRef> {
141public:
142  WritableBinaryStreamRef() = default;
143  WritableBinaryStreamRef(WritableBinaryStream &Stream)
144      : BinaryStreamRefBase(Stream, 0, Stream.getLength()) {}
145  WritableBinaryStreamRef(WritableBinaryStream &Stream, uint32_t Offset,
146                          uint32_t Length)
147      : BinaryStreamRefBase(Stream, Offset, Length) {}
148
149  // Use WritableBinaryStreamRef.slice() instead.
150  WritableBinaryStreamRef(WritableBinaryStreamRef &S, uint32_t Offset,
151                          uint32_t Length) = delete;
152
153  /// Given an Offset into this WritableBinaryStreamRef and some input data,
154  /// writes the data to the underlying stream.
155  ///
156  /// \returns a success error code if the data could fit within the underlying
157  /// stream at the specified location and the implementation could write the
158  /// data, and an appropriate error code otherwise.
159  Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Data) const {
160    if (auto EC = checkOffset(Offset, Data.size()))
161      return EC;
162
163    return Stream->writeBytes(ViewOffset + Offset, Data);
164  }
165
166  operator BinaryStreamRef() { return BinaryStreamRef(*Stream); }
167
168  /// \brief For buffered streams, commits changes to the backing store.
169  Error commit() { return Stream->commit(); }
170};
171
172} // end namespace llvm
173
174#endif // LLVM_SUPPORT_BINARYSTREAMREF_H
175