blob: 5e21be8183714de86ef8a3d6b4470059e62ff3f9 [file] [log] [blame]
/*
* Copyright (C) 2022 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 INCLUDE_PERFETTO_PUBLIC_PB_UTILS_H_
#define INCLUDE_PERFETTO_PUBLIC_PB_UTILS_H_
#include <stdint.h>
#include "perfetto/public/compiler.h"
// Type of fields that can be found in a protobuf serialized message.
enum PerfettoPbWireType {
PERFETTO_PB_WIRE_TYPE_VARINT = 0,
PERFETTO_PB_WIRE_TYPE_FIXED64 = 1,
PERFETTO_PB_WIRE_TYPE_DELIMITED = 2,
PERFETTO_PB_WIRE_TYPE_FIXED32 = 5,
};
// Creates a field tag, which encodes the field type and the field id.
static inline uint32_t PerfettoPbMakeTag(int32_t field_id,
enum PerfettoPbWireType wire_type) {
return ((PERFETTO_STATIC_CAST(uint32_t, field_id)) << 3) |
PERFETTO_STATIC_CAST(uint32_t, wire_type);
}
enum {
// Maximum bytes size of a 64-bit integer encoded as a VarInt.
PERFETTO_PB_VARINT_MAX_SIZE_64 = 10,
// Maximum bytes size of a 32-bit integer encoded as a VarInt.
PERFETTO_PB_VARINT_MAX_SIZE_32 = 5,
};
// Encodes `value` as a VarInt into `*dst`.
//
// `dst` must point into a buffer big enough to represent `value`:
// PERFETTO_PB_VARINT_MAX_SIZE_* can help.
static inline uint8_t* PerfettoPbWriteVarInt(uint64_t value, uint8_t* dst) {
uint8_t byte;
while (value >= 0x80) {
byte = (value & 0x7f) | 0x80;
*dst++ = byte;
value >>= 7;
}
byte = value & 0x7f;
*dst++ = byte;
return dst;
}
// Parses a VarInt from the encoded buffer [start, end). |end| is STL-style and
// points one byte past the end of buffer.
// The parsed int value is stored in the output arg |value|. Returns a pointer
// to the next unconsumed byte (so start < retval <= end) or |start| if the
// VarInt could not be fully parsed because there was not enough space in the
// buffer.
static inline const uint8_t* PerfettoPbParseVarInt(const uint8_t* start,
const uint8_t* end,
uint64_t* out_value) {
const uint8_t* pos = start;
uint64_t value = 0;
for (uint32_t shift = 0; pos < end && shift < 64u; shift += 7) {
// Cache *pos into |cur_byte| to prevent that the compiler dereferences the
// pointer twice (here and in the if() below) due to char* aliasing rules.
uint8_t cur_byte = *pos++;
value |= PERFETTO_STATIC_CAST(uint64_t, cur_byte & 0x7f) << shift;
if ((cur_byte & 0x80) == 0) {
// In valid cases we get here.
*out_value = value;
return pos;
}
}
*out_value = 0;
return start;
}
#endif // INCLUDE_PERFETTO_PUBLIC_PB_UTILS_H_