blob: 87ba3fdb1bfddde00988a151ffd3899f2256449a [file] [log] [blame]
/*
* Copyright (C) 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.
*/
#ifndef MINIKIN_BUFFER_H
#define MINIKIN_BUFFER_H
#include <cstring>
#include <string_view>
#include <type_traits>
#include <utility>
namespace minikin {
// This is a helper class to read data from a memory buffer.
// This class does not copy memory, and may return pointers to parts of the memory buffer.
// Thus the memory buffer should outlive objects created using this class.
class BufferReader {
public:
BufferReader(const void* buffer) : BufferReader(buffer, 0) {}
BufferReader(const void* buffer, uint32_t pos)
: mData(reinterpret_cast<const uint8_t*>(buffer)), mPos(pos) {}
template <typename T>
static uint32_t align(uint32_t pos) {
// This should be true for all types, unless custom alignment attributes are set.
static_assert(sizeof(T) % alignof(T) == 0, "sizeof(T) must be a multiple of alignof(T)");
// We align to sizeof(T) instead of alignof(T), because the buffer may be shared between
// 32-bit processes and 64-bit processes. alignof(T) may change between the two.
// We assume that T is a type whose size is fixed (e.g. uint32_t).
return (pos + sizeof(T) - 1) / sizeof(T) * sizeof(T);
}
template <typename T>
const T& read() {
static_assert(std::is_pod<T>::value, "T must be a POD");
mPos = BufferReader::align<T>(mPos);
const T* data = reinterpret_cast<const T*>(mData + mPos);
mPos += sizeof(T);
return *data;
}
template <typename T>
void skip() {
static_assert(std::is_pod<T>::value, "T must be a POD");
mPos = BufferReader::align<T>(mPos);
mPos += sizeof(T);
}
// Return a pointer to an array and its number of elements.
template <typename T>
std::pair<const T*, uint32_t> readArray() {
static_assert(std::is_pod<T>::value, "T must be a POD");
uint32_t size = read<uint32_t>();
mPos = BufferReader::align<T>(mPos);
const T* data = reinterpret_cast<const T*>(mData + mPos);
mPos += size * sizeof(T);
return std::make_pair(data, size);
}
template <typename T>
void skipArray() {
static_assert(std::is_pod<T>::value, "T must be a POD");
uint32_t size = read<uint32_t>();
mPos = BufferReader::align<T>(mPos);
mPos += size * sizeof(T);
}
std::string_view readString() {
auto [data, size] = readArray<char>();
return std::string_view(data, size);
}
void skipString() { skipArray<char>(); }
const void* data() const { return mData; }
size_t pos() const { return mPos; }
private:
const uint8_t* mData;
size_t mPos;
};
// This is a helper class to write data to a memory buffer.
class BufferWriter {
public:
// Create a buffer writer. Passing nullptr creates a fake writer,
// which can be used to measure the buffer size needed.
BufferWriter(void* buffer) : mData(reinterpret_cast<uint8_t*>(buffer)), mPos(0) {}
BufferWriter(BufferWriter&&) = default;
BufferWriter& operator=(BufferWriter&&) = default;
// Write a single data of type T.
// Please always specify T explicitly using <>. std::common_type_t<T> resolves to T, but
// disables template argument deduction.
// TODO: use std::type_identity_t when C++20 is available.
template <typename T>
void write(const std::common_type_t<T>& data) {
static_assert(std::is_pod<T>::value, "T must be a POD");
mPos = BufferReader::align<T>(mPos);
if (mData != nullptr) {
memcpy(mData + mPos, &data, sizeof(T));
}
mPos += sizeof(T);
}
// Write an array of type T.
// Please always specify T explicitly using <>. std::common_type_t<T> resolves to T, but
// disables template argument deduction.
// TODO: use std::type_identity_t when C++20 is available.
template <typename T>
void writeArray(const std::common_type_t<T>* data, uint32_t size) {
static_assert(std::is_pod<T>::value, "T must be a POD");
write<uint32_t>(size);
mPos = BufferReader::align<T>(mPos);
if (mData != nullptr) {
memcpy(mData + mPos, data, size * sizeof(T));
}
mPos += size * sizeof(T);
}
void writeString(std::string_view string) { writeArray<char>(string.data(), string.size()); }
// Return the number of bytes written.
size_t size() const { return mPos; }
private:
uint8_t* mData;
size_t mPos;
// Forbid copy and assign.
BufferWriter(const BufferWriter&) = delete;
void operator=(const BufferWriter&) = delete;
};
} // namespace minikin
#endif // MINIKIN_BUFFER_H