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