Line data Source code
1 : //===- BinaryStreamWriter.h - Writes objects to a BinaryStream ---*- 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_BINARYSTREAMWRITER_H
11 : #define LLVM_SUPPORT_BINARYSTREAMWRITER_H
12 :
13 : #include "llvm/ADT/ArrayRef.h"
14 : #include "llvm/ADT/STLExtras.h"
15 : #include "llvm/ADT/StringRef.h"
16 : #include "llvm/Support/BinaryStreamArray.h"
17 : #include "llvm/Support/BinaryStreamError.h"
18 : #include "llvm/Support/BinaryStreamRef.h"
19 : #include "llvm/Support/Endian.h"
20 : #include "llvm/Support/Error.h"
21 : #include <cstdint>
22 : #include <type_traits>
23 : #include <utility>
24 :
25 : namespace llvm {
26 :
27 : /// Provides write only access to a subclass of `WritableBinaryStream`.
28 : /// Provides bounds checking and helpers for writing certain common data types
29 : /// such as null-terminated strings, integers in various flavors of endianness,
30 : /// etc. Can be subclassed to provide reading and writing of custom datatypes,
31 : /// although no methods are overridable.
32 : class BinaryStreamWriter {
33 : public:
34 440 : BinaryStreamWriter() = default;
35 : explicit BinaryStreamWriter(WritableBinaryStreamRef Ref);
36 : explicit BinaryStreamWriter(WritableBinaryStream &Stream);
37 : explicit BinaryStreamWriter(MutableArrayRef<uint8_t> Data,
38 : llvm::support::endianness Endian);
39 :
40 1760 : BinaryStreamWriter(const BinaryStreamWriter &Other)
41 3520 : : Stream(Other.Stream), Offset(Other.Offset) {}
42 :
43 : BinaryStreamWriter &operator=(const BinaryStreamWriter &Other) {
44 : Stream = Other.Stream;
45 880 : Offset = Other.Offset;
46 : return *this;
47 : }
48 :
49 6671 : virtual ~BinaryStreamWriter() {}
50 :
51 : /// Write the bytes specified in \p Buffer to the underlying stream.
52 : /// On success, updates the offset so that subsequent writes will occur
53 : /// at the next unwritten position.
54 : ///
55 : /// \returns a success error code if the data was successfully written,
56 : /// otherwise returns an appropriate error code.
57 : Error writeBytes(ArrayRef<uint8_t> Buffer);
58 :
59 : /// Write the integer \p Value to the underlying stream in the
60 : /// specified endianness. On success, updates the offset so that
61 : /// subsequent writes occur at the next unwritten position.
62 : ///
63 : /// \returns a success error code if the data was successfully written,
64 : /// otherwise returns an appropriate error code.
65 47923 : template <typename T> Error writeInteger(T Value) {
66 : static_assert(std::is_integral<T>::value,
67 : "Cannot call writeInteger with non-integral value!");
68 : uint8_t Buffer[sizeof(T)];
69 47923 : llvm::support::endian::write<T, llvm::support::unaligned>(
70 : Buffer, Value, Stream.getEndian());
71 47923 : return writeBytes(Buffer);
72 : }
73 6886 :
74 : /// Similar to writeInteger
75 : template <typename T> Error writeEnum(T Num) {
76 : static_assert(std::is_enum<T>::value,
77 6886 : "Cannot call writeEnum with non-Enum type");
78 :
79 6886 : using U = typename std::underlying_type<T>::type;
80 2 : return writeInteger<U>(static_cast<U>(Num));
81 4886 : }
82 :
83 : /// Write the string \p Str to the underlying stream followed by a null
84 : /// terminator. On success, updates the offset so that subsequent writes
85 4886 : /// occur at the next unwritten position. \p Str need not be null terminated
86 : /// on input.
87 4886 : ///
88 : /// \returns a success error code if the data was successfully written,
89 2320 : /// otherwise returns an appropriate error code.
90 : Error writeCString(StringRef Str);
91 :
92 : /// Write the string \p Str to the underlying stream without a null
93 2320 : /// terminator. On success, updates the offset so that subsequent writes
94 : /// occur at the next unwritten position.
95 2320 : ///
96 6794 : /// \returns a success error code if the data was successfully written,
97 1852 : /// otherwise returns an appropriate error code.
98 : Error writeFixedString(StringRef Str);
99 :
100 : /// Efficiently reads all data from \p Ref, and writes it to this stream.
101 1852 : /// This operation will not invoke any copies of the source data, regardless
102 : /// of the source stream's implementation.
103 1852 : ///
104 : /// \returns a success error code if the data was successfully written,
105 0 : /// otherwise returns an appropriate error code.
106 : Error writeStreamRef(BinaryStreamRef Ref);
107 :
108 : /// Efficiently reads \p Size bytes from \p Ref, and writes it to this stream.
109 0 : /// This operation will not invoke any copies of the source data, regardless
110 : /// of the source stream's implementation.
111 0 : ///
112 18 : /// \returns a success error code if the data was successfully written,
113 6873 : /// otherwise returns an appropriate error code.
114 : Error writeStreamRef(BinaryStreamRef Ref, uint32_t Size);
115 :
116 : /// Writes the object \p Obj to the underlying stream, as if by using memcpy.
117 6873 : /// It is up to the caller to ensure that type of \p Obj can be safely copied
118 : /// in this fashion, as no checks are made to ensure that this is safe.
119 6873 : ///
120 : /// \returns a success error code if the data was successfully written,
121 89 : /// otherwise returns an appropriate error code.
122 : template <typename T> Error writeObject(const T &Obj) {
123 : static_assert(!std::is_pointer<T>::value,
124 : "writeObject should not be used with pointers, to write "
125 89 : "the pointed-to value dereference the pointer before calling "
126 : "writeObject");
127 89 : return writeBytes(
128 17989 : ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&Obj), sizeof(T)));
129 7050 : }
130 :
131 : /// Writes an array of objects of type T to the underlying stream, as if by
132 : /// using memcpy. It is up to the caller to ensure that type of \p Obj can
133 7050 : /// be safely copied in this fashion, as no checks are made to ensure that
134 : /// this is safe.
135 7050 : ///
136 : /// \returns a success error code if the data was successfully written,
137 : /// otherwise returns an appropriate error code.
138 2668 : template <typename T> Error writeArray(ArrayRef<T> Array) {
139 2668 : if (Array.empty())
140 : return Error::success();
141 2334 : if (Array.size() > UINT32_MAX / sizeof(T))
142 : return make_error<BinaryStreamError>(
143 0 : stream_error_code::invalid_array_size);
144 551 :
145 : return writeBytes(
146 2228 : ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(Array.data()),
147 4668 : Array.size() * sizeof(T)));
148 : }
149 :
150 : /// Writes all data from the array \p Array to the underlying stream.
151 : ///
152 : /// \returns a success error code if the data was successfully written,
153 : /// otherwise returns an appropriate error code.
154 267 : template <typename T, typename U>
155 267 : Error writeArray(VarStreamArray<T, U> Array) {
156 : return writeStreamRef(Array.getUnderlyingStream());
157 267 : }
158 :
159 0 : /// Writes all elements from the array \p Array to the underlying stream.
160 45 : ///
161 : /// \returns a success error code if the data was successfully written,
162 178 : /// otherwise returns an appropriate error code.
163 534 : template <typename T> Error writeArray(FixedStreamArray<T> Array) {
164 : return writeStreamRef(Array.getUnderlyingStream());
165 89 : }
166 89 :
167 : /// Splits the Writer into two Writers at a given offset.
168 89 : std::pair<BinaryStreamWriter, BinaryStreamWriter> split(uint32_t Off) const;
169 :
170 3155 : void setOffset(uint32_t Off) { Offset = Off; }
171 6 : uint32_t getOffset() const { return Offset; }
172 : uint32_t getLength() const { return Stream.getLength(); }
173 768 : uint32_t bytesRemaining() const { return getLength() - getOffset(); }
174 178 : Error padToAlignment(uint32_t Align);
175 0 :
176 89 : protected:
177 89 : WritableBinaryStreamRef Stream;
178 6 : uint32_t Offset = 0;
179 101 : };
180 :
181 0 : } // end namespace llvm
182 :
183 : #endif // LLVM_SUPPORT_BINARYSTREAMWRITER_H
|