| /* |
| * 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_ |