Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Details | Last modification | View Log | RSS feed

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