1 : // Copyright 2012 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 : //
15 : // Utility class for constructing a buffer of binary data. There are two
16 : // implementations provided:
17 : //
18 : // 1. BufferWriter: for writing to fixed-size preallocated buffers; and,
19 : // 2. VectorBufferWriter: for writing to growable std::vector<uint8>-backed
20 : // buffers.
21 : //
22 : // Intended usage:
23 : //
24 : // uint8 buffer[1024];
25 : // FixedBufferWriter writer(buffer, sizeof(buffer));
26 : // writer.WriteString(some_string);
27 : // writer.AlignUp(sizeof(uint32));
28 : // writer.Write(number_of_elements, array_of_uint32s);
29 : // writer.Write(some_complex_object);
30 :
31 : #ifndef SYZYGY_COMMON_BUFFER_WRITER_H_
32 : #define SYZYGY_COMMON_BUFFER_WRITER_H_
33 :
34 : #include <vector>
35 :
36 : #include "base/strings/string_piece.h"
37 :
38 : namespace common {
39 :
40 : // A helper class for creating buffers of binary data. This allows writing of
41 : // arbitrary binary objects with helpers for controlling alignment, etc. This is
42 : // a pure virtual base class, allowing this class to easily be extended for
43 : // targeting other growable buffer types. Derived classes need only provide a
44 : // constructor and implement the GrowBuffer function.
45 : class BufferWriter {
46 : public:
47 : // Constructor.
48 : // @param buffer the initial destination buffer.
49 : // @param buffer_length the initial length of the buffer, in bytes.
50 : BufferWriter(void* buffer, size_t buffer_length);
51 :
52 : // @{
53 : // Simple accessors and mutators.
54 E : size_t pos() const { return pos_; }
55 E : void set_pos(size_t pos) { pos_ = pos; }
56 E : size_t length() const { return buffer_length_; }
57 : // @}
58 :
59 : // Returns the remaining bytes in the buffer. If we're using an expandable
60 : // vector and this returns zero, the next write will cause the vector to
61 : // grow.
62 : // @returns the number of allocated bytes remaining.
63 : size_t RemainingBytes() const;
64 :
65 : // Advance the write position by @p bytes. This skips over the existing data.
66 : // @param bytes the number of bytes to skip.
67 : // @returns true if there was sufficient room for the seek, false otherwise.
68 : bool Consume(size_t bytes);
69 :
70 : // Advances the output position to the next multiple of @p bytes.
71 : // @param bytes the alignment, which must be a power of two.
72 : // @returns true if there was sufficient room for the align, false otherwise.
73 : bool Align(size_t bytes);
74 :
75 : // Determines if the current output position is aligned.
76 : // @param bytes the alignment to confirm, which must be a multiple of two.
77 : // @returns true if aligned, false otherwise.
78 : bool IsAligned(size_t bytes) const;
79 :
80 : // Writes the given data to the buffer, advancing the write pointer.
81 : // @param data_len the data length in bytes.
82 : // @param data the buffer of data to write.
83 : // @returns true if there was sufficient room for the write, false otherwise.
84 : bool Write(size_t data_len, const void* data);
85 :
86 : // Writes the given data to the buffer, advancing the write pointer. Writes
87 : // sizeof(T) * element_count bytes.
88 : // @param element_count the number of elements to write.
89 : // @param elements the array of elements to write.
90 : // @returns true if there was sufficient room for the write, false otherwise.
91 : template<typename T> bool Write(size_t element_count, const T* elements);
92 :
93 : // Writes the given data to the buffer, advancing the write pointer. Writes
94 : // sizeof(T) bytes.
95 : // @param element the element to write.
96 : // @returns true if there was sufficient room for the write, false otherwise.
97 : template<typename T> bool Write(const T& element);
98 :
99 : // @{
100 : // Writes the given zero terminated string to the buffer. Writes
101 : // (string.size() + 1) * sizeof(string[0]) bytes.
102 : // @param string the string to write.
103 : // @returns true if there was sufficient room for the write, false otherwise.
104 : bool WriteString(const base::StringPiece& string);
105 : bool WriteString(const base::StringPiece16& string);
106 : // @}
107 :
108 : protected:
109 : // This is intended to be called by the constructors of derived classes.
110 : // @param buffer the initial destination buffer.
111 : // @param buffer_length the initial length of the buffer, in bytes.
112 : void SetBuffer(uint8* buffer, size_t buffer_length);
113 :
114 : // This function is responsible for ensuring that the buffer has the expected
115 : // size. It should return a pointer to the buffer with sufficient size, or
116 : // return NULL if the resize is not possible. If the resize causes a
117 : // reallocation, this routine is also responsible for copying all data up to
118 : // and the current position pos_ into the new buffer. Upon success this is
119 : // also responsible for cleaning up the memory used by the old buffer if a
120 : // resize was required. Upon failure to resize the old buffer must be
121 : // maintained as the BufferWriter will keep a pointer to it.
122 : //
123 : // NOTE: Implementations of this function should be careful not to cause an
124 : // O(N^2) algorithm. They should generally do something like vector
125 : // and actually double the buffer size when a reallocation is needed.
126 : // Further calls to GrowBuffer can simply return the same buffer as long
127 : // as new_length < the actual allocated length.
128 : //
129 : // @param new_length the new buffer length requested.
130 : // @returns a pointer to the buffer of size at least @p new_length bytes on
131 : // success, a NULL pointer on failure.
132 : virtual uint8* GrowBuffer(size_t new_length);
133 :
134 : private:
135 : // This handles overflow checking, determines if the buffer needs to be
136 : // grown, delegates to GrowBuffer, and updates internal structures as
137 : // necessary. Upon a successful call buffer_ points to a buffer of size at
138 : // least @p new_length, and buffer_length_ is set to @p new_length.
139 : // @param new_length the new buffer length requested.
140 : // @returns true on success, false otherwise.
141 : bool EnsureCanWriteFromCurrentPosition(size_t new_length);
142 :
143 : uint8* buffer_;
144 : size_t buffer_length_;
145 : size_t pos_;
146 : };
147 :
148 : class VectorBufferWriter : public BufferWriter {
149 : public:
150 : // Constructor for writing to an expandable buffer based on a vector.
151 : // @param vector the vector to be written to. Writing will start at position
152 : // zero, and once we've exceeded the current size of the vector writes
153 : // will cause it to grow.
154 : explicit VectorBufferWriter(std::vector<uint8>* vector);
155 :
156 : protected:
157 : virtual uint8* GrowBuffer(size_t size);
158 :
159 : std::vector<uint8>* vector_;
160 : };
161 :
162 : template<typename T> bool BufferWriter::Write(size_t element_count,
163 E : const T* elements) {
164 : return Write(element_count * sizeof(T),
165 E : static_cast<const void*>(elements));
166 E : }
167 :
168 E : template<typename T> bool BufferWriter::Write(const T& element) {
169 E : return Write(sizeof(T), static_cast<const void*>(&element));
170 E : }
171 :
172 : } // namespace common
173 :
174 : #endif // SYZYGY_COMMON_BUFFER_WRITER_H_
|