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