1 #ifndef ANDROID_PDX_UTILITY_H_
2 #define ANDROID_PDX_UTILITY_H_
3
4 #include <cstdint>
5 #include <iterator>
6
7 #include <pdx/rpc/sequence.h>
8
9 // Utilities for testing object serialization.
10
11 namespace android {
12 namespace pdx {
13
14 class ByteBuffer {
15 public:
16 using iterator = uint8_t*;
17 using const_iterator = const uint8_t*;
18 using size_type = size_t;
19
20 ByteBuffer() = default;
ByteBuffer(const ByteBuffer & other)21 ByteBuffer(const ByteBuffer& other) {
22 resize(other.size());
23 if (other.size())
24 memcpy(data_, other.data(), other.size());
25 }
26
27 ByteBuffer& operator=(const ByteBuffer& other) {
28 resize(other.size());
29 if (other.size())
30 memcpy(data_, other.data(), other.size());
31 return *this;
32 }
33
34 ByteBuffer& operator=(ByteBuffer&& other) {
35 std::swap(data_, other.data_);
36 std::swap(size_, other.size_);
37 std::swap(capacity_, other.capacity_);
38 other.clear();
39 return *this;
40 }
41
data()42 inline const uint8_t* data() const { return data_; }
data()43 inline uint8_t* data() { return data_; }
size()44 inline size_t size() const { return size_; }
capacity()45 inline size_t capacity() const { return capacity_; }
46
begin()47 iterator begin() { return data_; }
begin()48 const_iterator begin() const { return data_; }
end()49 iterator end() { return data_ + size_; }
end()50 const_iterator end() const { return data_ + size_; }
51
52 inline bool operator==(const ByteBuffer& other) const {
53 return size_ == other.size_ &&
54 (size_ == 0 || memcmp(data_, other.data_, size_) == 0);
55 }
56
57 inline bool operator!=(const ByteBuffer& other) const {
58 return !operator==(other);
59 }
60
reserve(size_t size)61 inline void reserve(size_t size) {
62 if (size <= capacity_)
63 return;
64 // Find next power of 2 (assuming the size is 32 bits for now).
65 size--;
66 size |= size >> 1;
67 size |= size >> 2;
68 size |= size >> 4;
69 size |= size >> 8;
70 size |= size >> 16;
71 size++;
72 void* new_data = data_ ? realloc(data_, size) : malloc(size);
73 // TODO(avakulenko): Check for allocation failures.
74 data_ = static_cast<uint8_t*>(new_data);
75 capacity_ = size;
76 }
77
resize(size_t size)78 inline void resize(size_t size) {
79 reserve(size);
80 size_ = size;
81 }
82
grow_by(size_t size_delta)83 inline uint8_t* grow_by(size_t size_delta) {
84 size_t old_size = size_;
85 resize(old_size + size_delta);
86 return data_ + old_size;
87 }
88
clear()89 inline void clear() { size_ = 0; }
90
91 private:
92 uint8_t* data_{nullptr};
93 size_t size_{0};
94 size_t capacity_{0};
95 };
96
97 // Utility functions to increment/decrement void pointers to data buffers.
98 template <typename OFFSET_T>
AdvancePointer(const void * ptr,OFFSET_T offset)99 inline const void* AdvancePointer(const void* ptr, OFFSET_T offset) {
100 return static_cast<const uint8_t*>(ptr) + offset;
101 }
102
103 template <typename OFFSET_T>
AdvancePointer(void * ptr,OFFSET_T offset)104 inline void* AdvancePointer(void* ptr, OFFSET_T offset) {
105 return static_cast<uint8_t*>(ptr) + offset;
106 }
107
PointerDistance(const void * end,const void * begin)108 inline ptrdiff_t PointerDistance(const void* end, const void* begin) {
109 return static_cast<const uint8_t*>(end) - static_cast<const uint8_t*>(begin);
110 }
111
112 // Utility to build sequences of types.
113 template <typename, typename>
114 struct AppendTypeSequence;
115
116 template <typename T, typename... S, template <typename...> class TT>
117 struct AppendTypeSequence<T, TT<S...>> {
118 using type = TT<S..., T>;
119 };
120
121 // Utility to generate repeated types.
122 template <typename T, std::size_t N, template <typename...> class TT>
123 struct RepeatedType {
124 using type = typename AppendTypeSequence<
125 T, typename RepeatedType<T, N - 1, TT>::type>::type;
126 };
127
128 template <typename T, template <typename...> class TT>
129 struct RepeatedType<T, 0, TT> {
130 using type = TT<>;
131 };
132
133 template <typename V, typename S>
134 inline V ReturnValueHelper(V value, S /*ignore*/) {
135 return value;
136 }
137
138 template <typename R, typename V, size_t... S>
139 inline R GetNTupleHelper(V value, rpc::IndexSequence<S...>) {
140 return std::make_tuple(ReturnValueHelper(value, S)...);
141 }
142
143 // Returns an N-tuple of type std::tuple<T,...T> containing |value| in each
144 // element.
145 template <size_t N, typename T,
146 typename R = typename RepeatedType<T, N, std::tuple>::type>
147 inline R GetNTuple(T value) {
148 return GetNTupleHelper<R>(value, rpc::MakeIndexSequence<N>{});
149 }
150
151 class NoOpOutputResourceMapper : public OutputResourceMapper {
152 public:
153 Status<FileReference> PushFileHandle(const LocalHandle& handle) override {
154 return handle.Get();
155 }
156
157 Status<FileReference> PushFileHandle(const BorrowedHandle& handle) override {
158 return handle.Get();
159 }
160
161 Status<FileReference> PushFileHandle(const RemoteHandle& handle) override {
162 return handle.Get();
163 }
164
165 Status<ChannelReference> PushChannelHandle(
166 const LocalChannelHandle& handle) override {
167 return handle.value();
168 }
169
170 Status<ChannelReference> PushChannelHandle(
171 const BorrowedChannelHandle& handle) override {
172 return handle.value();
173 }
174
175 Status<ChannelReference> PushChannelHandle(
176 const RemoteChannelHandle& handle) override {
177 return handle.value();
178 }
179 };
180
181 class NoOpInputResourceMapper : public InputResourceMapper {
182 public:
183 bool GetFileHandle(FileReference ref, LocalHandle* handle) override {
184 *handle = LocalHandle{ref};
185 return true;
186 }
187
188 bool GetChannelHandle(ChannelReference ref,
189 LocalChannelHandle* handle) override {
190 *handle = LocalChannelHandle{nullptr, ref};
191 return true;
192 }
193 };
194
195 class NoOpResourceMapper : public NoOpOutputResourceMapper,
196 public NoOpInputResourceMapper {};
197
198 // Simple implementation of the payload interface, required by
199 // Serialize/Deserialize. This is intended for test cases, where compatibility
200 // with std::vector is helpful.
201 class Payload : public MessageWriter,
202 public MessageReader,
203 public OutputResourceMapper {
204 public:
205 using BaseType = ByteBuffer;
206 using iterator = typename BaseType::iterator;
207 using const_iterator = typename BaseType::const_iterator;
208 using size_type = typename BaseType::size_type;
209
210 Payload() = default;
211 explicit Payload(size_type count, uint8_t value = 0) { Append(count, value); }
212 Payload(const Payload& other) : buffer_(other.buffer_) {}
213 Payload(const std::initializer_list<uint8_t>& initializer) {
214 buffer_.resize(initializer.size());
215 std::copy(initializer.begin(), initializer.end(), buffer_.begin());
216 }
217
218 Payload& operator=(const Payload& other) {
219 buffer_ = other.buffer_;
220 read_pos_ = 0;
221 return *this;
222 }
223 Payload& operator=(const std::initializer_list<uint8_t>& initializer) {
224 buffer_.resize(initializer.size());
225 std::copy(initializer.begin(), initializer.end(), buffer_.begin());
226 read_pos_ = 0;
227 return *this;
228 }
229
230 // Compares Payload with Payload.
231 bool operator==(const Payload& other) const {
232 return buffer_ == other.buffer_;
233 }
234 bool operator!=(const Payload& other) const {
235 return buffer_ != other.buffer_;
236 }
237
238 // Compares Payload with std::vector.
239 template <typename Type, typename AllocatorType>
240 typename std::enable_if<sizeof(Type) == sizeof(uint8_t), bool>::type
241 operator==(const std::vector<Type, AllocatorType>& other) const {
242 return buffer_.size() == other.size() &&
243 memcmp(buffer_.data(), other.data(), other.size()) == 0;
244 }
245 template <typename Type, typename AllocatorType>
246 typename std::enable_if<sizeof(Type) == sizeof(uint8_t), bool>::type
247 operator!=(const std::vector<Type, AllocatorType>& other) const {
248 return !operator!=(other);
249 }
250
251 iterator begin() { return buffer_.begin(); }
252 const_iterator begin() const { return buffer_.begin(); }
253 iterator end() { return buffer_.end(); }
254 const_iterator end() const { return buffer_.end(); }
255
256 void Append(size_type count, uint8_t value) {
257 auto* data = buffer_.grow_by(count);
258 std::fill(data, data + count, value);
259 }
260
261 void Clear() {
262 buffer_.clear();
263 file_handles_.clear();
264 read_pos_ = 0;
265 }
266
267 void Rewind() { read_pos_ = 0; }
268
269 uint8_t* Data() { return buffer_.data(); }
270 const uint8_t* Data() const { return buffer_.data(); }
271 size_type Size() const { return buffer_.size(); }
272
273 // MessageWriter
274 void* GetNextWriteBufferSection(size_t size) override {
275 return buffer_.grow_by(size);
276 }
277
278 OutputResourceMapper* GetOutputResourceMapper() override { return this; }
279
280 // OutputResourceMapper
281 Status<FileReference> PushFileHandle(const LocalHandle& handle) override {
282 if (handle) {
283 const int ref = file_handles_.size();
284 file_handles_.push_back(handle.Get());
285 return ref;
286 } else {
287 return handle.Get();
288 }
289 }
290
291 Status<FileReference> PushFileHandle(const BorrowedHandle& handle) override {
292 if (handle) {
293 const int ref = file_handles_.size();
294 file_handles_.push_back(handle.Get());
295 return ref;
296 } else {
297 return handle.Get();
298 }
299 }
300
301 Status<FileReference> PushFileHandle(const RemoteHandle& handle) override {
302 return handle.Get();
303 }
304
305 Status<ChannelReference> PushChannelHandle(
306 const LocalChannelHandle& handle) override {
307 if (handle) {
308 const int ref = file_handles_.size();
309 file_handles_.push_back(handle.value());
310 return ref;
311 } else {
312 return handle.value();
313 }
314 }
315
316 Status<ChannelReference> PushChannelHandle(
317 const BorrowedChannelHandle& handle) override {
318 if (handle) {
319 const int ref = file_handles_.size();
320 file_handles_.push_back(handle.value());
321 return ref;
322 } else {
323 return handle.value();
324 }
325 }
326
327 Status<ChannelReference> PushChannelHandle(
328 const RemoteChannelHandle& handle) override {
329 return handle.value();
330 }
331
332 // MessageReader
333 BufferSection GetNextReadBufferSection() override {
334 return {buffer_.data() + read_pos_, &*buffer_.end()};
335 }
336
337 void ConsumeReadBufferSectionData(const void* new_start) override {
338 read_pos_ = PointerDistance(new_start, buffer_.data());
339 }
340
341 InputResourceMapper* GetInputResourceMapper() override {
342 return &input_resource_mapper_;
343 }
344
345 const int* FdArray() const { return file_handles_.data(); }
346 std::size_t FdCount() const { return file_handles_.size(); }
347
348 private:
349 NoOpInputResourceMapper input_resource_mapper_;
350 ByteBuffer buffer_;
351 std::vector<int> file_handles_;
352 size_t read_pos_{0};
353 };
354
355 } // namespace pdx
356 } // namespace android
357
358 // Helper macros for branch prediction hinting.
359 #ifdef __GNUC__
360 #define PDX_LIKELY(x) __builtin_expect(!!(x), true)
361 #define PDX_UNLIKELY(x) __builtin_expect(!!(x), false)
362 #else
363 #define PDX_LIKELY(x) (x)
364 #define PDX_UNLIKELY(x) (x)
365 #endif
366
367 #endif // ANDROID_PDX_UTILITY_H_
368