1 /* 2 * Copyright 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 #pragma once 18 19 #include <numeric> 20 #include <optional> 21 #include <type_traits> 22 #include <vector> 23 24 #include <utils/Flattenable.h> 25 26 #define RETURN_IF_ERROR(op) \ 27 if (const status_t status = (op); status != OK) return status; 28 29 namespace android { 30 31 struct FlattenableHelpers { 32 // Helpers for reading and writing POD structures which are not LightFlattenable. 33 template <class T, 34 typename = std::enable_if_t< 35 std::conjunction_v<std::is_trivially_copyable<T>, 36 std::negation<std::is_base_of<LightFlattenable<T>, T>>>>> getFlattenedSizeFlattenableHelpers37 static constexpr size_t getFlattenedSize(const T&) { 38 return sizeof(T); 39 } 40 41 template <class T, 42 typename = std::enable_if_t< 43 std::conjunction_v<std::is_trivially_copyable<T>, 44 std::negation<std::is_base_of<LightFlattenable<T>, T>>>>> flattenFlattenableHelpers45 static status_t flatten(void** buffer, size_t* size, const T& value) { 46 if (*size < sizeof(T)) return NO_MEMORY; 47 FlattenableUtils::write(*buffer, *size, value); 48 return OK; 49 } 50 51 template <class T, 52 typename = std::enable_if_t< 53 std::conjunction_v<std::is_trivially_copyable<T>, 54 std::negation<std::is_base_of<LightFlattenable<T>, T>>>>> unflattenFlattenableHelpers55 static status_t unflatten(const void** buffer, size_t* size, T* value) { 56 if (*size < sizeof(T)) return NO_MEMORY; 57 FlattenableUtils::read(*buffer, *size, *value); 58 return OK; 59 } 60 61 // Helpers for reading and writing std::string getFlattenedSizeFlattenableHelpers62 static size_t getFlattenedSize(const std::string& str) { 63 return sizeof(uint64_t) + str.length(); 64 } 65 flattenFlattenableHelpers66 static status_t flatten(void** buffer, size_t* size, const std::string& str) { 67 if (*size < getFlattenedSize(str)) return NO_MEMORY; 68 flatten(buffer, size, (uint64_t)str.length()); 69 memcpy(reinterpret_cast<char*>(*buffer), str.c_str(), str.length()); 70 FlattenableUtils::advance(*buffer, *size, str.length()); 71 return OK; 72 } 73 unflattenFlattenableHelpers74 static status_t unflatten(const void** buffer, size_t* size, std::string* str) { 75 uint64_t length; 76 RETURN_IF_ERROR(unflatten(buffer, size, &length)); 77 if (*size < length) return NO_MEMORY; 78 str->assign(reinterpret_cast<const char*>(*buffer), length); 79 FlattenableUtils::advance(*buffer, *size, length); 80 return OK; 81 } 82 83 // Helpers for reading and writing LightFlattenable 84 template <class T> getFlattenedSizeFlattenableHelpers85 static size_t getFlattenedSize(const LightFlattenable<T>& value) { 86 return value.getFlattenedSize(); 87 } 88 89 template <class T> flattenFlattenableHelpers90 static status_t flatten(void** buffer, size_t* size, const LightFlattenable<T>& value) { 91 RETURN_IF_ERROR(value.flatten(*buffer, *size)); 92 FlattenableUtils::advance(*buffer, *size, value.getFlattenedSize()); 93 return OK; 94 } 95 96 template <class T> unflattenFlattenableHelpers97 static status_t unflatten(const void** buffer, size_t* size, LightFlattenable<T>* value) { 98 RETURN_IF_ERROR(value->unflatten(*buffer, *size)); 99 FlattenableUtils::advance(*buffer, *size, value->getFlattenedSize()); 100 return OK; 101 } 102 103 // Helpers for reading and writing std::optional 104 template <class T, typename = std::enable_if_t<std::negation_v<std::is_trivially_copyable<T>>>> getFlattenedSizeFlattenableHelpers105 static size_t getFlattenedSize(const std::optional<T>& value) { 106 return sizeof(bool) + (value ? getFlattenedSize(*value) : 0); 107 } 108 109 template <class T, typename = std::enable_if_t<std::negation_v<std::is_trivially_copyable<T>>>> flattenFlattenableHelpers110 static status_t flatten(void** buffer, size_t* size, const std::optional<T>& value) { 111 if (value) { 112 RETURN_IF_ERROR(flatten(buffer, size, true)); 113 RETURN_IF_ERROR(flatten(buffer, size, *value)); 114 } else { 115 RETURN_IF_ERROR(flatten(buffer, size, false)); 116 } 117 return OK; 118 } 119 120 template <class T, typename = std::enable_if_t<std::negation_v<std::is_trivially_copyable<T>>>> unflattenFlattenableHelpers121 static status_t unflatten(const void** buffer, size_t* size, std::optional<T>* value) { 122 bool isPresent; 123 RETURN_IF_ERROR(unflatten(buffer, size, &isPresent)); 124 if (isPresent) { 125 *value = T(); 126 RETURN_IF_ERROR(unflatten(buffer, size, &(**value))); 127 } else { 128 value->reset(); 129 } 130 return OK; 131 } 132 133 // Helpers for reading and writing std::vector 134 template <class T> getFlattenedSizeFlattenableHelpers135 static size_t getFlattenedSize(const std::vector<T>& value) { 136 return std::accumulate(value.begin(), value.end(), sizeof(uint64_t), 137 [](size_t sum, const T& element) { 138 return sum + getFlattenedSize(element); 139 }); 140 } 141 142 template <class T> flattenFlattenableHelpers143 static status_t flatten(void** buffer, size_t* size, const std::vector<T>& value) { 144 RETURN_IF_ERROR(flatten(buffer, size, (uint64_t)value.size())); 145 for (const auto& element : value) { 146 RETURN_IF_ERROR(flatten(buffer, size, element)); 147 } 148 return OK; 149 } 150 151 template <class T> unflattenFlattenableHelpers152 static status_t unflatten(const void** buffer, size_t* size, std::vector<T>* value) { 153 uint64_t numElements; 154 RETURN_IF_ERROR(unflatten(buffer, size, &numElements)); 155 // We don't need an extra size check since each iteration of the loop does that 156 std::vector<T> elements; 157 for (size_t i = 0; i < numElements; i++) { 158 T element; 159 RETURN_IF_ERROR(unflatten(buffer, size, &element)); 160 elements.push_back(element); 161 } 162 *value = std::move(elements); 163 return OK; 164 } 165 }; 166 167 } // namespace android 168 169 #undef RETURN_IF_ERROR