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
12namespace android {
13namespace pdx {
14
15class 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;
22  ByteBuffer(const ByteBuffer& other) {
23    resize(other.size());
24    if (other.size())
25      memcpy(data_, other.data(), other.size());
26  }
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) {
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
44  inline const uint8_t* data() const { return data_; }
45  inline uint8_t* data() { return data_; }
46  inline size_t size() const { return size_; }
47  inline size_t capacity() const { return capacity_; }
48
49  iterator begin() { return data_; }
50  const_iterator begin() const { return data_; }
51  iterator end() { return data_ + size_; }
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
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
80  inline void resize(size_t size) {
81    reserve(size);
82    size_ = size;
83  }
84
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
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.
100template <typename OFFSET_T>
101inline const void* AdvancePointer(const void* ptr, OFFSET_T offset) {
102  return static_cast<const uint8_t*>(ptr) + offset;
103}
104
105template <typename OFFSET_T>
106inline void* AdvancePointer(void* ptr, OFFSET_T offset) {
107  return static_cast<uint8_t*>(ptr) + offset;
108}
109
110inline 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.
115template <typename, typename>
116struct AppendTypeSequence;
117
118template <typename T, typename... S, template <typename...> class TT>
119struct AppendTypeSequence<T, TT<S...>> {
120  using type = TT<S..., T>;
121};
122
123// Utility to generate repeated types.
124template <typename T, std::size_t N, template <typename...> class TT>
125struct RepeatedType {
126  using type = typename AppendTypeSequence<
127      T, typename RepeatedType<T, N - 1, TT>::type>::type;
128};
129
130template <typename T, template <typename...> class TT>
131struct RepeatedType<T, 0, TT> {
132  using type = TT<>;
133};
134
135template <typename V, typename S>
136inline V ReturnValueHelper(V value, S /*ignore*/) {
137  return value;
138}
139
140template <typename R, typename V, size_t... S>
141inline 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.
147template <size_t N, typename T,
148          typename R = typename RepeatedType<T, N, std::tuple>::type>
149inline R GetNTuple(T value) {
150  return GetNTupleHelper<R>(value, rpc::MakeIndexSequence<N>{});
151}
152
153class 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
183class 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
197class 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.
203class 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