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