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
11namespace android {
12namespace pdx {
13
14class 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;
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
42  inline const uint8_t* data() const { return data_; }
43  inline uint8_t* data() { return data_; }
44  inline size_t size() const { return size_; }
45  inline size_t capacity() const { return capacity_; }
46
47  iterator begin() { return data_; }
48  const_iterator begin() const { return data_; }
49  iterator end() { return data_ + size_; }
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
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
78  inline void resize(size_t size) {
79    reserve(size);
80    size_ = size;
81  }
82
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
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.
98template <typename OFFSET_T>
99inline const void* AdvancePointer(const void* ptr, OFFSET_T offset) {
100  return static_cast<const uint8_t*>(ptr) + offset;
101}
102
103template <typename OFFSET_T>
104inline void* AdvancePointer(void* ptr, OFFSET_T offset) {
105  return static_cast<uint8_t*>(ptr) + offset;
106}
107
108inline 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.
113template <typename, typename>
114struct AppendTypeSequence;
115
116template <typename T, typename... S, template <typename...> class TT>
117struct AppendTypeSequence<T, TT<S...>> {
118  using type = TT<S..., T>;
119};
120
121// Utility to generate repeated types.
122template <typename T, std::size_t N, template <typename...> class TT>
123struct RepeatedType {
124  using type = typename AppendTypeSequence<
125      T, typename RepeatedType<T, N - 1, TT>::type>::type;
126};
127
128template <typename T, template <typename...> class TT>
129struct RepeatedType<T, 0, TT> {
130  using type = TT<>;
131};
132
133template <typename V, typename S>
134inline V ReturnValueHelper(V value, S /*ignore*/) {
135  return value;
136}
137
138template <typename R, typename V, size_t... S>
139inline 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.
145template <size_t N, typename T,
146          typename R = typename RepeatedType<T, N, std::tuple>::type>
147inline R GetNTuple(T value) {
148  return GetNTupleHelper<R>(value, rpc::MakeIndexSequence<N>{});
149}
150
151class 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
181class 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
195class 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.
201class 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