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; 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. 100 template <typename OFFSET_T> 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> 106 inline void* AdvancePointer(void* ptr, OFFSET_T offset) { 107 return static_cast<uint8_t*>(ptr) + offset; 108 } 109 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