Home | History | Annotate | Download | only in pdx
      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