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