Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:44:28

0001 //===- BinaryStreamRef.h - A copyable reference to a stream -----*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 
0009 #ifndef LLVM_SUPPORT_BINARYSTREAMREF_H
0010 #define LLVM_SUPPORT_BINARYSTREAMREF_H
0011 
0012 #include "llvm/ADT/ArrayRef.h"
0013 #include "llvm/Support/BinaryStream.h"
0014 #include "llvm/Support/BinaryStreamError.h"
0015 #include "llvm/Support/Error.h"
0016 #include <cstdint>
0017 #include <memory>
0018 #include <optional>
0019 
0020 namespace llvm {
0021 
0022 /// Common stuff for mutable and immutable StreamRefs.
0023 template <class RefType, class StreamType> class BinaryStreamRefBase {
0024 protected:
0025   BinaryStreamRefBase() = default;
0026   explicit BinaryStreamRefBase(StreamType &BorrowedImpl)
0027       : BorrowedImpl(&BorrowedImpl), ViewOffset(0) {
0028     if (!(BorrowedImpl.getFlags() & BSF_Append))
0029       Length = BorrowedImpl.getLength();
0030   }
0031 
0032   BinaryStreamRefBase(std::shared_ptr<StreamType> SharedImpl, uint64_t Offset,
0033                       std::optional<uint64_t> Length)
0034       : SharedImpl(SharedImpl), BorrowedImpl(SharedImpl.get()),
0035         ViewOffset(Offset), Length(Length) {}
0036   BinaryStreamRefBase(StreamType &BorrowedImpl, uint64_t Offset,
0037                       std::optional<uint64_t> Length)
0038       : BorrowedImpl(&BorrowedImpl), ViewOffset(Offset), Length(Length) {}
0039   BinaryStreamRefBase(const BinaryStreamRefBase &Other) = default;
0040   BinaryStreamRefBase &operator=(const BinaryStreamRefBase &Other) = default;
0041 
0042   BinaryStreamRefBase &operator=(BinaryStreamRefBase &&Other) = default;
0043   BinaryStreamRefBase(BinaryStreamRefBase &&Other) = default;
0044 
0045 public:
0046   llvm::endianness getEndian() const { return BorrowedImpl->getEndian(); }
0047 
0048   uint64_t getLength() const {
0049     if (Length)
0050       return *Length;
0051 
0052     return BorrowedImpl ? (BorrowedImpl->getLength() - ViewOffset) : 0;
0053   }
0054 
0055   /// Return a new BinaryStreamRef with the first \p N elements removed.  If
0056   /// this BinaryStreamRef is length-tracking, then the resulting one will be
0057   /// too.
0058   RefType drop_front(uint64_t N) const {
0059     if (!BorrowedImpl)
0060       return RefType();
0061 
0062     N = std::min(N, getLength());
0063     RefType Result(static_cast<const RefType &>(*this));
0064     if (N == 0)
0065       return Result;
0066 
0067     Result.ViewOffset += N;
0068     if (Result.Length)
0069       *Result.Length -= N;
0070     return Result;
0071   }
0072 
0073   /// Return a new BinaryStreamRef with the last \p N elements removed.  If
0074   /// this BinaryStreamRef is length-tracking and \p N is greater than 0, then
0075   /// this BinaryStreamRef will no longer length-track.
0076   RefType drop_back(uint64_t N) const {
0077     if (!BorrowedImpl)
0078       return RefType();
0079 
0080     RefType Result(static_cast<const RefType &>(*this));
0081     N = std::min(N, getLength());
0082 
0083     if (N == 0)
0084       return Result;
0085 
0086     // Since we're dropping non-zero bytes from the end, stop length-tracking
0087     // by setting the length of the resulting StreamRef to an explicit value.
0088     if (!Result.Length)
0089       Result.Length = getLength();
0090 
0091     *Result.Length -= N;
0092     return Result;
0093   }
0094 
0095   /// Return a new BinaryStreamRef with only the first \p N elements remaining.
0096   RefType keep_front(uint64_t N) const {
0097     assert(N <= getLength());
0098     return drop_back(getLength() - N);
0099   }
0100 
0101   /// Return a new BinaryStreamRef with only the last \p N elements remaining.
0102   RefType keep_back(uint64_t N) const {
0103     assert(N <= getLength());
0104     return drop_front(getLength() - N);
0105   }
0106 
0107   /// Return a new BinaryStreamRef with the first and last \p N elements
0108   /// removed.
0109   RefType drop_symmetric(uint64_t N) const {
0110     return drop_front(N).drop_back(N);
0111   }
0112 
0113   /// Return a new BinaryStreamRef with the first \p Offset elements removed,
0114   /// and retaining exactly \p Len elements.
0115   RefType slice(uint64_t Offset, uint64_t Len) const {
0116     return drop_front(Offset).keep_front(Len);
0117   }
0118 
0119   bool valid() const { return BorrowedImpl != nullptr; }
0120 
0121   friend bool operator==(const RefType &LHS, const RefType &RHS) {
0122     if (LHS.BorrowedImpl != RHS.BorrowedImpl)
0123       return false;
0124     if (LHS.ViewOffset != RHS.ViewOffset)
0125       return false;
0126     if (LHS.Length != RHS.Length)
0127       return false;
0128     return true;
0129   }
0130 
0131 protected:
0132   Error checkOffsetForRead(uint64_t Offset, uint64_t DataSize) const {
0133     if (Offset > getLength())
0134       return make_error<BinaryStreamError>(stream_error_code::invalid_offset);
0135     if (getLength() < DataSize + Offset)
0136       return make_error<BinaryStreamError>(stream_error_code::stream_too_short);
0137     return Error::success();
0138   }
0139 
0140   std::shared_ptr<StreamType> SharedImpl;
0141   StreamType *BorrowedImpl = nullptr;
0142   uint64_t ViewOffset = 0;
0143   std::optional<uint64_t> Length;
0144 };
0145 
0146 /// BinaryStreamRef is to BinaryStream what ArrayRef is to an Array.  It
0147 /// provides copy-semantics and read only access to a "window" of the underlying
0148 /// BinaryStream. Note that BinaryStreamRef is *not* a BinaryStream.  That is to
0149 /// say, it does not inherit and override the methods of BinaryStream.  In
0150 /// general, you should not pass around pointers or references to BinaryStreams
0151 /// and use inheritance to achieve polymorphism.  Instead, you should pass
0152 /// around BinaryStreamRefs by value and achieve polymorphism that way.
0153 class BinaryStreamRef
0154     : public BinaryStreamRefBase<BinaryStreamRef, BinaryStream> {
0155   friend BinaryStreamRefBase<BinaryStreamRef, BinaryStream>;
0156   friend class WritableBinaryStreamRef;
0157   BinaryStreamRef(std::shared_ptr<BinaryStream> Impl, uint64_t ViewOffset,
0158                   std::optional<uint64_t> Length)
0159       : BinaryStreamRefBase(Impl, ViewOffset, Length) {}
0160 
0161 public:
0162   BinaryStreamRef() = default;
0163   BinaryStreamRef(BinaryStream &Stream);
0164   BinaryStreamRef(BinaryStream &Stream, uint64_t Offset,
0165                   std::optional<uint64_t> Length);
0166   explicit BinaryStreamRef(ArrayRef<uint8_t> Data, llvm::endianness Endian);
0167   explicit BinaryStreamRef(StringRef Data, llvm::endianness Endian);
0168 
0169   BinaryStreamRef(const BinaryStreamRef &Other) = default;
0170   BinaryStreamRef &operator=(const BinaryStreamRef &Other) = default;
0171   BinaryStreamRef(BinaryStreamRef &&Other) = default;
0172   BinaryStreamRef &operator=(BinaryStreamRef &&Other) = default;
0173 
0174   // Use BinaryStreamRef.slice() instead.
0175   BinaryStreamRef(BinaryStreamRef &S, uint64_t Offset,
0176                   uint64_t Length) = delete;
0177 
0178   /// Given an Offset into this StreamRef and a Size, return a reference to a
0179   /// buffer owned by the stream.
0180   ///
0181   /// \returns a success error code if the entire range of data is within the
0182   /// bounds of this BinaryStreamRef's view and the implementation could read
0183   /// the data, and an appropriate error code otherwise.
0184   Error readBytes(uint64_t Offset, uint64_t Size,
0185                   ArrayRef<uint8_t> &Buffer) const;
0186 
0187   /// Given an Offset into this BinaryStreamRef, return a reference to the
0188   /// largest buffer the stream could support without necessitating a copy.
0189   ///
0190   /// \returns a success error code if implementation could read the data,
0191   /// and an appropriate error code otherwise.
0192   Error readLongestContiguousChunk(uint64_t Offset,
0193                                    ArrayRef<uint8_t> &Buffer) const;
0194 };
0195 
0196 struct BinarySubstreamRef {
0197   uint64_t Offset = 0;        // Offset in the parent stream
0198   BinaryStreamRef StreamData; // Stream Data
0199 
0200   BinarySubstreamRef slice(uint64_t Off, uint64_t Size) const {
0201     BinaryStreamRef SubSub = StreamData.slice(Off, Size);
0202     return {Off + Offset, SubSub};
0203   }
0204   BinarySubstreamRef drop_front(uint64_t N) const {
0205     return slice(N, size() - N);
0206   }
0207   BinarySubstreamRef keep_front(uint64_t N) const { return slice(0, N); }
0208 
0209   std::pair<BinarySubstreamRef, BinarySubstreamRef> split(uint64_t Off) const {
0210     return std::make_pair(keep_front(Off), drop_front(Off));
0211   }
0212 
0213   uint64_t size() const { return StreamData.getLength(); }
0214   bool empty() const { return size() == 0; }
0215 };
0216 
0217 class WritableBinaryStreamRef
0218     : public BinaryStreamRefBase<WritableBinaryStreamRef,
0219                                  WritableBinaryStream> {
0220   friend BinaryStreamRefBase<WritableBinaryStreamRef, WritableBinaryStream>;
0221   WritableBinaryStreamRef(std::shared_ptr<WritableBinaryStream> Impl,
0222                           uint64_t ViewOffset, std::optional<uint64_t> Length)
0223       : BinaryStreamRefBase(Impl, ViewOffset, Length) {}
0224 
0225   Error checkOffsetForWrite(uint64_t Offset, uint64_t DataSize) const {
0226     if (!(BorrowedImpl->getFlags() & BSF_Append))
0227       return checkOffsetForRead(Offset, DataSize);
0228 
0229     if (Offset > getLength())
0230       return make_error<BinaryStreamError>(stream_error_code::invalid_offset);
0231     return Error::success();
0232   }
0233 
0234 public:
0235   WritableBinaryStreamRef() = default;
0236   WritableBinaryStreamRef(WritableBinaryStream &Stream);
0237   WritableBinaryStreamRef(WritableBinaryStream &Stream, uint64_t Offset,
0238                           std::optional<uint64_t> Length);
0239   explicit WritableBinaryStreamRef(MutableArrayRef<uint8_t> Data,
0240                                    llvm::endianness Endian);
0241   WritableBinaryStreamRef(const WritableBinaryStreamRef &Other) = default;
0242   WritableBinaryStreamRef &
0243   operator=(const WritableBinaryStreamRef &Other) = default;
0244 
0245   WritableBinaryStreamRef(WritableBinaryStreamRef &&Other) = default;
0246   WritableBinaryStreamRef &operator=(WritableBinaryStreamRef &&Other) = default;
0247 
0248   // Use WritableBinaryStreamRef.slice() instead.
0249   WritableBinaryStreamRef(WritableBinaryStreamRef &S, uint64_t Offset,
0250                           uint64_t Length) = delete;
0251 
0252   /// Given an Offset into this WritableBinaryStreamRef and some input data,
0253   /// writes the data to the underlying stream.
0254   ///
0255   /// \returns a success error code if the data could fit within the underlying
0256   /// stream at the specified location and the implementation could write the
0257   /// data, and an appropriate error code otherwise.
0258   Error writeBytes(uint64_t Offset, ArrayRef<uint8_t> Data) const;
0259 
0260   /// Conver this WritableBinaryStreamRef to a read-only BinaryStreamRef.
0261   operator BinaryStreamRef() const;
0262 
0263   /// For buffered streams, commits changes to the backing store.
0264   Error commit();
0265 };
0266 
0267 } // end namespace llvm
0268 
0269 #endif // LLVM_SUPPORT_BINARYSTREAMREF_H