xref: /freebsd-src/contrib/llvm-project/llvm/include/llvm/Support/BinaryStreamWriter.h (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
10b57cec5SDimitry Andric //===- BinaryStreamWriter.h - Writes objects to a BinaryStream ---*- C++-*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #ifndef LLVM_SUPPORT_BINARYSTREAMWRITER_H
100b57cec5SDimitry Andric #define LLVM_SUPPORT_BINARYSTREAMWRITER_H
110b57cec5SDimitry Andric 
120b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h"
130b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
140b57cec5SDimitry Andric #include "llvm/Support/BinaryStreamArray.h"
150b57cec5SDimitry Andric #include "llvm/Support/BinaryStreamError.h"
160b57cec5SDimitry Andric #include "llvm/Support/BinaryStreamRef.h"
170b57cec5SDimitry Andric #include "llvm/Support/Endian.h"
180b57cec5SDimitry Andric #include "llvm/Support/Error.h"
190b57cec5SDimitry Andric #include <cstdint>
200b57cec5SDimitry Andric #include <type_traits>
210b57cec5SDimitry Andric #include <utility>
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric namespace llvm {
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric /// Provides write only access to a subclass of `WritableBinaryStream`.
260b57cec5SDimitry Andric /// Provides bounds checking and helpers for writing certain common data types
270b57cec5SDimitry Andric /// such as null-terminated strings, integers in various flavors of endianness,
280b57cec5SDimitry Andric /// etc.  Can be subclassed to provide reading and writing of custom datatypes,
290b57cec5SDimitry Andric /// although no methods are overridable.
300b57cec5SDimitry Andric class BinaryStreamWriter {
310b57cec5SDimitry Andric public:
320b57cec5SDimitry Andric   BinaryStreamWriter() = default;
330b57cec5SDimitry Andric   explicit BinaryStreamWriter(WritableBinaryStreamRef Ref);
340b57cec5SDimitry Andric   explicit BinaryStreamWriter(WritableBinaryStream &Stream);
350b57cec5SDimitry Andric   explicit BinaryStreamWriter(MutableArrayRef<uint8_t> Data,
36*5f757f3fSDimitry Andric                               llvm::endianness Endian);
370b57cec5SDimitry Andric 
381fd87a68SDimitry Andric   BinaryStreamWriter(const BinaryStreamWriter &Other) = default;
390b57cec5SDimitry Andric 
401fd87a68SDimitry Andric   BinaryStreamWriter &operator=(const BinaryStreamWriter &Other) = default;
410b57cec5SDimitry Andric 
421fd87a68SDimitry Andric   virtual ~BinaryStreamWriter() = default;
430b57cec5SDimitry Andric 
440b57cec5SDimitry Andric   /// Write the bytes specified in \p Buffer to the underlying stream.
450b57cec5SDimitry Andric   /// On success, updates the offset so that subsequent writes will occur
460b57cec5SDimitry Andric   /// at the next unwritten position.
470b57cec5SDimitry Andric   ///
480b57cec5SDimitry Andric   /// \returns a success error code if the data was successfully written,
490b57cec5SDimitry Andric   /// otherwise returns an appropriate error code.
500b57cec5SDimitry Andric   Error writeBytes(ArrayRef<uint8_t> Buffer);
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric   /// Write the integer \p Value to the underlying stream in the
530b57cec5SDimitry Andric   /// specified endianness.  On success, updates the offset so that
540b57cec5SDimitry Andric   /// subsequent writes occur at the next unwritten position.
550b57cec5SDimitry Andric   ///
560b57cec5SDimitry Andric   /// \returns a success error code if the data was successfully written,
570b57cec5SDimitry Andric   /// otherwise returns an appropriate error code.
writeInteger(T Value)580b57cec5SDimitry Andric   template <typename T> Error writeInteger(T Value) {
59bdd1243dSDimitry Andric     static_assert(std::is_integral_v<T>,
600b57cec5SDimitry Andric                   "Cannot call writeInteger with non-integral value!");
610b57cec5SDimitry Andric     uint8_t Buffer[sizeof(T)];
62*5f757f3fSDimitry Andric     llvm::support::endian::write<T>(Buffer, Value, Stream.getEndian());
630b57cec5SDimitry Andric     return writeBytes(Buffer);
640b57cec5SDimitry Andric   }
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric   /// Similar to writeInteger
writeEnum(T Num)670b57cec5SDimitry Andric   template <typename T> Error writeEnum(T Num) {
680b57cec5SDimitry Andric     static_assert(std::is_enum<T>::value,
690b57cec5SDimitry Andric                   "Cannot call writeEnum with non-Enum type");
700b57cec5SDimitry Andric 
715ffd83dbSDimitry Andric     using U = std::underlying_type_t<T>;
720b57cec5SDimitry Andric     return writeInteger<U>(static_cast<U>(Num));
730b57cec5SDimitry Andric   }
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric   /// Write the unsigned integer Value to the underlying stream using ULEB128
760b57cec5SDimitry Andric   /// encoding.
770b57cec5SDimitry Andric   ///
780b57cec5SDimitry Andric   /// \returns a success error code if the data was successfully written,
790b57cec5SDimitry Andric   /// otherwise returns an appropriate error code.
800b57cec5SDimitry Andric   Error writeULEB128(uint64_t Value);
810b57cec5SDimitry Andric 
820b57cec5SDimitry Andric   /// Write the unsigned integer Value to the underlying stream using ULEB128
830b57cec5SDimitry Andric   /// encoding.
840b57cec5SDimitry Andric   ///
850b57cec5SDimitry Andric   /// \returns a success error code if the data was successfully written,
860b57cec5SDimitry Andric   /// otherwise returns an appropriate error code.
870b57cec5SDimitry Andric   Error writeSLEB128(int64_t Value);
880b57cec5SDimitry Andric 
890b57cec5SDimitry Andric   /// Write the string \p Str to the underlying stream followed by a null
900b57cec5SDimitry Andric   /// terminator.  On success, updates the offset so that subsequent writes
910b57cec5SDimitry Andric   /// occur at the next unwritten position.  \p Str need not be null terminated
920b57cec5SDimitry Andric   /// on input.
930b57cec5SDimitry Andric   ///
940b57cec5SDimitry Andric   /// \returns a success error code if the data was successfully written,
950b57cec5SDimitry Andric   /// otherwise returns an appropriate error code.
960b57cec5SDimitry Andric   Error writeCString(StringRef Str);
970b57cec5SDimitry Andric 
980b57cec5SDimitry Andric   /// Write the string \p Str to the underlying stream without a null
990b57cec5SDimitry Andric   /// terminator.  On success, updates the offset so that subsequent writes
1000b57cec5SDimitry Andric   /// occur at the next unwritten position.
1010b57cec5SDimitry Andric   ///
1020b57cec5SDimitry Andric   /// \returns a success error code if the data was successfully written,
1030b57cec5SDimitry Andric   /// otherwise returns an appropriate error code.
1040b57cec5SDimitry Andric   Error writeFixedString(StringRef Str);
1050b57cec5SDimitry Andric 
1060b57cec5SDimitry Andric   /// Efficiently reads all data from \p Ref, and writes it to this stream.
1070b57cec5SDimitry Andric   /// This operation will not invoke any copies of the source data, regardless
1080b57cec5SDimitry Andric   /// of the source stream's implementation.
1090b57cec5SDimitry Andric   ///
1100b57cec5SDimitry Andric   /// \returns a success error code if the data was successfully written,
1110b57cec5SDimitry Andric   /// otherwise returns an appropriate error code.
1120b57cec5SDimitry Andric   Error writeStreamRef(BinaryStreamRef Ref);
1130b57cec5SDimitry Andric 
1140b57cec5SDimitry Andric   /// Efficiently reads \p Size bytes from \p Ref, and writes it to this stream.
1150b57cec5SDimitry Andric   /// This operation will not invoke any copies of the source data, regardless
1160b57cec5SDimitry Andric   /// of the source stream's implementation.
1170b57cec5SDimitry Andric   ///
1180b57cec5SDimitry Andric   /// \returns a success error code if the data was successfully written,
1190b57cec5SDimitry Andric   /// otherwise returns an appropriate error code.
120349cc55cSDimitry Andric   Error writeStreamRef(BinaryStreamRef Ref, uint64_t Size);
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric   /// Writes the object \p Obj to the underlying stream, as if by using memcpy.
1230b57cec5SDimitry Andric   /// It is up to the caller to ensure that type of \p Obj can be safely copied
1240b57cec5SDimitry Andric   /// in this fashion, as no checks are made to ensure that this is safe.
1250b57cec5SDimitry Andric   ///
1260b57cec5SDimitry Andric   /// \returns a success error code if the data was successfully written,
1270b57cec5SDimitry Andric   /// otherwise returns an appropriate error code.
writeObject(const T & Obj)1280b57cec5SDimitry Andric   template <typename T> Error writeObject(const T &Obj) {
1290b57cec5SDimitry Andric     static_assert(!std::is_pointer<T>::value,
1300b57cec5SDimitry Andric                   "writeObject should not be used with pointers, to write "
1310b57cec5SDimitry Andric                   "the pointed-to value dereference the pointer before calling "
1320b57cec5SDimitry Andric                   "writeObject");
1330b57cec5SDimitry Andric     return writeBytes(
1340b57cec5SDimitry Andric         ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&Obj), sizeof(T)));
1350b57cec5SDimitry Andric   }
1360b57cec5SDimitry Andric 
1370b57cec5SDimitry Andric   /// Writes an array of objects of type T to the underlying stream, as if by
1380b57cec5SDimitry Andric   /// using memcpy.  It is up to the caller to ensure that type of \p Obj can
1390b57cec5SDimitry Andric   /// be safely copied in this fashion, as no checks are made to ensure that
1400b57cec5SDimitry Andric   /// this is safe.
1410b57cec5SDimitry Andric   ///
1420b57cec5SDimitry Andric   /// \returns a success error code if the data was successfully written,
1430b57cec5SDimitry Andric   /// otherwise returns an appropriate error code.
writeArray(ArrayRef<T> Array)1440b57cec5SDimitry Andric   template <typename T> Error writeArray(ArrayRef<T> Array) {
1450b57cec5SDimitry Andric     if (Array.empty())
1460b57cec5SDimitry Andric       return Error::success();
1470b57cec5SDimitry Andric     if (Array.size() > UINT32_MAX / sizeof(T))
1480b57cec5SDimitry Andric       return make_error<BinaryStreamError>(
1490b57cec5SDimitry Andric           stream_error_code::invalid_array_size);
1500b57cec5SDimitry Andric 
1510b57cec5SDimitry Andric     return writeBytes(
1520b57cec5SDimitry Andric         ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(Array.data()),
1530b57cec5SDimitry Andric                           Array.size() * sizeof(T)));
1540b57cec5SDimitry Andric   }
1550b57cec5SDimitry Andric 
1560b57cec5SDimitry Andric   /// Writes all data from the array \p Array to the underlying stream.
1570b57cec5SDimitry Andric   ///
1580b57cec5SDimitry Andric   /// \returns a success error code if the data was successfully written,
1590b57cec5SDimitry Andric   /// otherwise returns an appropriate error code.
1600b57cec5SDimitry Andric   template <typename T, typename U>
writeArray(VarStreamArray<T,U> Array)1610b57cec5SDimitry Andric   Error writeArray(VarStreamArray<T, U> Array) {
1620b57cec5SDimitry Andric     return writeStreamRef(Array.getUnderlyingStream());
1630b57cec5SDimitry Andric   }
1640b57cec5SDimitry Andric 
1650b57cec5SDimitry Andric   /// Writes all elements from the array \p Array to the underlying stream.
1660b57cec5SDimitry Andric   ///
1670b57cec5SDimitry Andric   /// \returns a success error code if the data was successfully written,
1680b57cec5SDimitry Andric   /// otherwise returns an appropriate error code.
writeArray(FixedStreamArray<T> Array)1690b57cec5SDimitry Andric   template <typename T> Error writeArray(FixedStreamArray<T> Array) {
1700b57cec5SDimitry Andric     return writeStreamRef(Array.getUnderlyingStream());
1710b57cec5SDimitry Andric   }
1720b57cec5SDimitry Andric 
1730b57cec5SDimitry Andric   /// Splits the Writer into two Writers at a given offset.
174349cc55cSDimitry Andric   std::pair<BinaryStreamWriter, BinaryStreamWriter> split(uint64_t Off) const;
1750b57cec5SDimitry Andric 
setOffset(uint64_t Off)176349cc55cSDimitry Andric   void setOffset(uint64_t Off) { Offset = Off; }
getOffset()177349cc55cSDimitry Andric   uint64_t getOffset() const { return Offset; }
getLength()178349cc55cSDimitry Andric   uint64_t getLength() const { return Stream.getLength(); }
bytesRemaining()179349cc55cSDimitry Andric   uint64_t bytesRemaining() const { return getLength() - getOffset(); }
1800b57cec5SDimitry Andric   Error padToAlignment(uint32_t Align);
1810b57cec5SDimitry Andric 
1820b57cec5SDimitry Andric protected:
1830b57cec5SDimitry Andric   WritableBinaryStreamRef Stream;
184349cc55cSDimitry Andric   uint64_t Offset = 0;
1850b57cec5SDimitry Andric };
1860b57cec5SDimitry Andric 
1870b57cec5SDimitry Andric } // end namespace llvm
1880b57cec5SDimitry Andric 
1890b57cec5SDimitry Andric #endif // LLVM_SUPPORT_BINARYSTREAMWRITER_H
190