diff options
Diffstat (limited to 'libs/ui/include_private/ui/FlattenableHelpers.h')
-rw-r--r-- | libs/ui/include_private/ui/FlattenableHelpers.h | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/libs/ui/include_private/ui/FlattenableHelpers.h b/libs/ui/include_private/ui/FlattenableHelpers.h new file mode 100644 index 0000000000..378f37f077 --- /dev/null +++ b/libs/ui/include_private/ui/FlattenableHelpers.h @@ -0,0 +1,169 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <numeric> +#include <optional> +#include <type_traits> +#include <vector> + +#include <utils/Flattenable.h> + +#define RETURN_IF_ERROR(op) \ + if (const status_t status = (op); status != OK) return status; + +namespace android { + +struct FlattenableHelpers { + // Helpers for reading and writing POD structures which are not LightFlattenable. + template <class T, + typename = std::enable_if_t< + std::conjunction_v<std::is_trivially_copyable<T>, + std::negation<std::is_base_of<LightFlattenable<T>, T>>>>> + static constexpr size_t getFlattenedSize(const T&) { + return sizeof(T); + } + + template <class T, + typename = std::enable_if_t< + std::conjunction_v<std::is_trivially_copyable<T>, + std::negation<std::is_base_of<LightFlattenable<T>, T>>>>> + static status_t flatten(void** buffer, size_t* size, const T& value) { + if (*size < sizeof(T)) return NO_MEMORY; + FlattenableUtils::write(*buffer, *size, value); + return OK; + } + + template <class T, + typename = std::enable_if_t< + std::conjunction_v<std::is_trivially_copyable<T>, + std::negation<std::is_base_of<LightFlattenable<T>, T>>>>> + static status_t unflatten(const void** buffer, size_t* size, T* value) { + if (*size < sizeof(T)) return NO_MEMORY; + FlattenableUtils::read(*buffer, *size, *value); + return OK; + } + + // Helpers for reading and writing std::string + static size_t getFlattenedSize(const std::string& str) { + return sizeof(uint64_t) + str.length(); + } + + static status_t flatten(void** buffer, size_t* size, const std::string& str) { + if (*size < getFlattenedSize(str)) return NO_MEMORY; + flatten(buffer, size, (uint64_t)str.length()); + memcpy(reinterpret_cast<char*>(*buffer), str.c_str(), str.length()); + FlattenableUtils::advance(*buffer, *size, str.length()); + return OK; + } + + static status_t unflatten(const void** buffer, size_t* size, std::string* str) { + uint64_t length; + RETURN_IF_ERROR(unflatten(buffer, size, &length)); + if (*size < length) return NO_MEMORY; + str->assign(reinterpret_cast<const char*>(*buffer), length); + FlattenableUtils::advance(*buffer, *size, length); + return OK; + } + + // Helpers for reading and writing LightFlattenable + template <class T> + static size_t getFlattenedSize(const LightFlattenable<T>& value) { + return value.getFlattenedSize(); + } + + template <class T> + static status_t flatten(void** buffer, size_t* size, const LightFlattenable<T>& value) { + RETURN_IF_ERROR(value.flatten(*buffer, *size)); + FlattenableUtils::advance(*buffer, *size, value.getFlattenedSize()); + return OK; + } + + template <class T> + static status_t unflatten(const void** buffer, size_t* size, LightFlattenable<T>* value) { + RETURN_IF_ERROR(value->unflatten(*buffer, *size)); + FlattenableUtils::advance(*buffer, *size, value->getFlattenedSize()); + return OK; + } + + // Helpers for reading and writing std::optional + template <class T, typename = std::enable_if_t<std::negation_v<std::is_trivially_copyable<T>>>> + static size_t getFlattenedSize(const std::optional<T>& value) { + return sizeof(bool) + (value ? getFlattenedSize(*value) : 0); + } + + template <class T, typename = std::enable_if_t<std::negation_v<std::is_trivially_copyable<T>>>> + static status_t flatten(void** buffer, size_t* size, const std::optional<T>& value) { + if (value) { + RETURN_IF_ERROR(flatten(buffer, size, true)); + RETURN_IF_ERROR(flatten(buffer, size, *value)); + } else { + RETURN_IF_ERROR(flatten(buffer, size, false)); + } + return OK; + } + + template <class T, typename = std::enable_if_t<std::negation_v<std::is_trivially_copyable<T>>>> + static status_t unflatten(const void** buffer, size_t* size, std::optional<T>* value) { + bool isPresent; + RETURN_IF_ERROR(unflatten(buffer, size, &isPresent)); + if (isPresent) { + *value = T(); + RETURN_IF_ERROR(unflatten(buffer, size, &(**value))); + } else { + value->reset(); + } + return OK; + } + + // Helpers for reading and writing std::vector + template <class T> + static size_t getFlattenedSize(const std::vector<T>& value) { + return std::accumulate(value.begin(), value.end(), sizeof(uint64_t), + [](size_t sum, const T& element) { + return sum + getFlattenedSize(element); + }); + } + + template <class T> + static status_t flatten(void** buffer, size_t* size, const std::vector<T>& value) { + RETURN_IF_ERROR(flatten(buffer, size, (uint64_t)value.size())); + for (const auto& element : value) { + RETURN_IF_ERROR(flatten(buffer, size, element)); + } + return OK; + } + + template <class T> + static status_t unflatten(const void** buffer, size_t* size, std::vector<T>* value) { + uint64_t numElements; + RETURN_IF_ERROR(unflatten(buffer, size, &numElements)); + // We don't need an extra size check since each iteration of the loop does that + std::vector<T> elements; + for (size_t i = 0; i < numElements; i++) { + T element; + RETURN_IF_ERROR(unflatten(buffer, size, &element)); + elements.push_back(element); + } + *value = std::move(elements); + return OK; + } +}; + +} // namespace android + +#undef RETURN_IF_ERROR
\ No newline at end of file |