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) {
     35     SharedImpl = Other.SharedImpl;
     36     BorrowedImpl = Other.BorrowedImpl;
     37     ViewOffset = Other.ViewOffset;
     38     Length = Other.Length;
     39   }
     40 
     41 public:
     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 
    107 protected:
    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.
    129 class 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 
    137 public:
    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 
    169 class WritableBinaryStreamRef
    170     : public BinaryStreamRefBase<WritableBinaryStreamRef,
    171                                  WritableBinaryStream> {
    172   friend BinaryStreamRefBase<WritableBinaryStreamRef, WritableBinaryStream>;
    173   WritableBinaryStreamRef(std::shared_ptr<WritableBinaryStream> Impl,
    174                           uint32_t ViewOffset, uint32_t Length)
    175       : BinaryStreamRefBase(Impl, ViewOffset, Length) {}
    176 
    177 public:
    178   WritableBinaryStreamRef() = default;
    179   WritableBinaryStreamRef(WritableBinaryStream &Stream);
    180   WritableBinaryStreamRef(WritableBinaryStream &Stream, uint32_t Offset,
    181                           uint32_t Length);
    182   explicit WritableBinaryStreamRef(MutableArrayRef<uint8_t> Data,
    183                                    llvm::support::endianness Endian);
    184   WritableBinaryStreamRef(const WritableBinaryStreamRef &Other);
    185 
    186   // Use WritableBinaryStreamRef.slice() instead.
    187   WritableBinaryStreamRef(WritableBinaryStreamRef &S, uint32_t Offset,
    188                           uint32_t Length) = delete;
    189 
    190   /// Given an Offset into this WritableBinaryStreamRef and some input data,
    191   /// writes the data to the underlying stream.
    192   ///
    193   /// \returns a success error code if the data could fit within the underlying
    194   /// stream at the specified location and the implementation could write the
    195   /// data, and an appropriate error code otherwise.
    196   Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Data) const;
    197 
    198   /// Conver this WritableBinaryStreamRef to a read-only BinaryStreamRef.
    199   operator BinaryStreamRef() const;
    200 
    201   /// \brief For buffered streams, commits changes to the backing store.
    202   Error commit();
    203 };
    204 
    205 } // end namespace llvm
    206 
    207 #endif // LLVM_SUPPORT_BINARYSTREAMREF_H
    208