blob: 49ae20041cb86fe5f2134fa574df353432d4c041 [file]
/*
* Copyright (C) 2026 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 SRC_TRACE_PROCESSOR_UTIL_FLATBUFFER_WRITER_H_
#define SRC_TRACE_PROCESSOR_UTIL_FLATBUFFER_WRITER_H_
#include <cstdint>
#include <cstring>
#include <string_view>
#include <vector>
namespace perfetto::trace_processor::util {
// Minimal FlatBuffer writer. Builds a valid flatbuffer back-to-front (the
// standard approach) so all offsets are naturally forward-pointing.
//
// Exists so trace processor can emit small flatbuffer-encoded metadata (e.g.
// Arrow IPC framing) without depending on the flatbuffers library.
//
// Usage:
// FlatBufferWriter w;
// auto name = w.WriteString("hello");
// w.StartTable();
// w.FieldOffset(0, name);
// w.FieldI32(1, 42);
// auto root = w.EndTable();
// w.Finish(root);
// auto buf = w.Release();
//
// Buffers produced by this writer can be parsed by
// FlatBufferReader::GetRoot() (see flatbuffer_reader.h).
class FlatBufferWriter {
public:
// Opaque handle to a previously written object's position, expressed as
// "bytes from the end of the buffer".
struct Offset {
uint32_t o = 0;
};
explicit FlatBufferWriter(uint32_t initial_capacity = 256);
// Writes a length-prefixed UTF-8 string. Returns an offset handle.
Offset WriteString(std::string_view s);
// Writes a vector of offset elements (for vectors of tables or strings).
Offset WriteVecOffsets(const Offset* offsets, uint32_t count);
// Writes a vector of inline structs. |data| points to |count| packed
// structs of |elem_size| bytes each, aligned to |elem_align|.
Offset WriteVecStruct(const void* data,
uint32_t elem_size,
uint32_t count,
uint32_t elem_align);
// Begins building a table. All Field* calls between StartTable/EndTable add
// fields to this table. Tables cannot be nested: finish the child table
// first, then reference it via FieldOffset.
void StartTable();
// Adds scalar fields to the table under construction.
void FieldBool(uint32_t index, bool val);
void FieldU8(uint32_t index, uint8_t val);
void FieldI16(uint32_t index, int16_t val);
void FieldI32(uint32_t index, int32_t val);
void FieldI64(uint32_t index, int64_t val);
// Adds an offset field (string, sub-table, or vector).
void FieldOffset(uint32_t index, Offset off);
// Finishes the current table. Returns an offset handle.
Offset EndTable();
// Finalizes the buffer by writing the root table offset prefix.
void Finish(Offset root);
// Access the finished buffer.
const uint8_t* data() const { return buf_.data() + head_; }
uint32_t size() const { return static_cast<uint32_t>(buf_.size()) - head_; }
// Takes ownership of the finished buffer as a tight vector.
std::vector<uint8_t> Release();
private:
// Ensures at least |bytes| of space is available before head_.
void GrowIfNeeded(uint32_t bytes);
// Pads so that the current written size is a multiple of |alignment|.
void Align(uint32_t alignment);
// Prepends raw bytes (order preserved in the final buffer).
void PrependBytes(const void* src, uint32_t len);
// Prepends a single scalar value.
template <typename T>
void Prepend(T val) {
GrowIfNeeded(sizeof(T));
head_ -= sizeof(T);
memcpy(&buf_[head_], &val, sizeof(T));
}
std::vector<uint8_t> buf_;
uint32_t head_ = 0;
// Largest alignment any element requested. Element positions are aligned
// relative to the buffer end, so Finish() pads the total size to a
// multiple of this to make them aligned relative to the start too (which
// is what strict flatbuffers verifiers check).
uint32_t min_align_ = 4;
// State for the table currently being built.
uint32_t table_body_start_ = 0;
struct FieldLoc {
uint32_t index;
uint32_t off_from_end;
};
std::vector<FieldLoc> fields_;
};
} // namespace perfetto::trace_processor::util
#endif // SRC_TRACE_PROCESSOR_UTIL_FLATBUFFER_WRITER_H_