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