1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef MINIKIN_BUFFER_H 18 #define MINIKIN_BUFFER_H 19 20 #include <cstring> 21 #include <string_view> 22 #include <type_traits> 23 #include <utility> 24 25 namespace minikin { 26 27 // This is a helper class to read data from a memory buffer. 28 // This class does not copy memory, and may return pointers to parts of the memory buffer. 29 // Thus the memory buffer should outlive objects created using this class. 30 class BufferReader { 31 public: BufferReader(const void * buffer)32 BufferReader(const void* buffer) : BufferReader(buffer, 0) {} BufferReader(const void * buffer,uint32_t pos)33 BufferReader(const void* buffer, uint32_t pos) 34 : mData(reinterpret_cast<const uint8_t*>(buffer)), mPos(pos) {} 35 36 template <typename T> align(uint32_t pos)37 static uint32_t align(uint32_t pos) { 38 // This should be true for all types, unless custom alignment attributes are set. 39 static_assert(sizeof(T) % alignof(T) == 0, "sizeof(T) must be a multiple of alignof(T)"); 40 // We align to sizeof(T) instead of alignof(T), because the buffer may be shared between 41 // 32-bit processes and 64-bit processes. alignof(T) may change between the two. 42 // We assume that T is a type whose size is fixed (e.g. uint32_t). 43 return (pos + sizeof(T) - 1) / sizeof(T) * sizeof(T); 44 } 45 46 template <typename T> read()47 const T& read() { 48 static_assert(std::is_pod<T>::value, "T must be a POD"); 49 mPos = BufferReader::align<T>(mPos); 50 const T* data = reinterpret_cast<const T*>(mData + mPos); 51 mPos += sizeof(T); 52 return *data; 53 } 54 55 template <typename T> skip()56 void skip() { 57 static_assert(std::is_pod<T>::value, "T must be a POD"); 58 mPos = BufferReader::align<T>(mPos); 59 mPos += sizeof(T); 60 } 61 62 // Return a pointer to an array and its number of elements. 63 template <typename T> readArray()64 std::pair<const T*, uint32_t> readArray() { 65 static_assert(std::is_pod<T>::value, "T must be a POD"); 66 uint32_t size = read<uint32_t>(); 67 mPos = BufferReader::align<T>(mPos); 68 const T* data = reinterpret_cast<const T*>(mData + mPos); 69 mPos += size * sizeof(T); 70 return std::make_pair(data, size); 71 } 72 73 template <typename T> skipArray()74 void skipArray() { 75 static_assert(std::is_pod<T>::value, "T must be a POD"); 76 uint32_t size = read<uint32_t>(); 77 mPos = BufferReader::align<T>(mPos); 78 mPos += size * sizeof(T); 79 } 80 readString()81 std::string_view readString() { 82 auto [data, size] = readArray<char>(); 83 return std::string_view(data, size); 84 } 85 skipString()86 void skipString() { skipArray<char>(); } 87 data()88 const void* data() const { return mData; } pos()89 size_t pos() const { return mPos; } 90 91 private: 92 const uint8_t* mData; 93 size_t mPos; 94 }; 95 96 // This is a helper class to write data to a memory buffer. 97 class BufferWriter { 98 public: 99 // Create a buffer writer. Passing nullptr creates a fake writer, 100 // which can be used to measure the buffer size needed. BufferWriter(void * buffer)101 BufferWriter(void* buffer) : mData(reinterpret_cast<uint8_t*>(buffer)), mPos(0) {} 102 103 BufferWriter(BufferWriter&&) = default; 104 BufferWriter& operator=(BufferWriter&&) = default; 105 106 // Write a single data of type T. 107 // Please always specify T explicitly using <>. std::common_type_t<T> resolves to T, but 108 // disables template argument deduction. 109 // TODO: use std::type_identity_t when C++20 is available. 110 template <typename T> write(const std::common_type_t<T> & data)111 void write(const std::common_type_t<T>& data) { 112 static_assert(std::is_pod<T>::value, "T must be a POD"); 113 mPos = BufferReader::align<T>(mPos); 114 if (mData != nullptr) { 115 memcpy(mData + mPos, &data, sizeof(T)); 116 } 117 mPos += sizeof(T); 118 } 119 120 // Write an array of type T. 121 // Please always specify T explicitly using <>. std::common_type_t<T> resolves to T, but 122 // disables template argument deduction. 123 // TODO: use std::type_identity_t when C++20 is available. 124 template <typename T> writeArray(const std::common_type_t<T> * data,uint32_t size)125 void writeArray(const std::common_type_t<T>* data, uint32_t size) { 126 static_assert(std::is_pod<T>::value, "T must be a POD"); 127 write<uint32_t>(size); 128 mPos = BufferReader::align<T>(mPos); 129 if (mData != nullptr) { 130 memcpy(mData + mPos, data, size * sizeof(T)); 131 } 132 mPos += size * sizeof(T); 133 } 134 writeString(std::string_view string)135 void writeString(std::string_view string) { writeArray<char>(string.data(), string.size()); } 136 137 // Return the number of bytes written. size()138 size_t size() const { return mPos; } 139 140 private: 141 uint8_t* mData; 142 size_t mPos; 143 144 // Forbid copy and assign. 145 BufferWriter(const BufferWriter&) = delete; 146 void operator=(const BufferWriter&) = delete; 147 }; 148 149 } // namespace minikin 150 151 #endif // MINIKIN_BUFFER_H 152