blob: 9c6da8d070915663010152b80eea37d8ee5edd13 [file] [log] [blame]
/*
* Copyright (C) 2019 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_PROTOZERO_FIELD_H_
#define INCLUDE_PERFETTO_PROTOZERO_FIELD_H_
#include <stdint.h>
#include <string>
#include "perfetto/base/logging.h"
#include "perfetto/protozero/contiguous_memory_range.h"
#include "perfetto/protozero/proto_utils.h"
namespace protozero {
struct ConstBytes {
const uint8_t* data;
size_t size;
};
struct ConstChars {
// Allow implicit conversion to perfetto's base::StringView without depending
// on perfetto/base or viceversa.
static constexpr bool kConvertibleToStringView = true;
std::string ToStdString() const { return std::string(data, size); }
const char* data;
size_t size;
};
// A protobuf field decoded by the protozero proto decoders. It exposes
// convenience accessors with minimal debug checks.
// This class is used both by the iterator-based ProtoDecoder and by the
// one-shot TypedProtoDecoder.
// If the field is not valid the accessors consistently return zero-integers or
// null strings.
class Field {
public:
inline bool valid() const { return id_ != 0; }
inline uint16_t id() const { return id_; }
explicit inline operator bool() const { return valid(); }
inline proto_utils::ProtoWireType type() const {
auto res = static_cast<proto_utils::ProtoWireType>(type_);
PERFETTO_DCHECK(res == proto_utils::ProtoWireType::kVarInt ||
res == proto_utils::ProtoWireType::kLengthDelimited ||
res == proto_utils::ProtoWireType::kFixed32 ||
res == proto_utils::ProtoWireType::kFixed64);
return res;
}
inline bool as_bool() const {
PERFETTO_DCHECK(!valid() || type() == proto_utils::ProtoWireType::kVarInt);
return static_cast<bool>(int_value_);
}
inline uint32_t as_uint32() const {
PERFETTO_DCHECK(!valid() || type() == proto_utils::ProtoWireType::kVarInt ||
type() == proto_utils::ProtoWireType::kFixed32);
return static_cast<uint32_t>(int_value_);
}
inline int32_t as_int32() const {
PERFETTO_DCHECK(!valid() || type() == proto_utils::ProtoWireType::kVarInt ||
type() == proto_utils::ProtoWireType::kFixed32);
return static_cast<int32_t>(int_value_);
}
inline uint64_t as_uint64() const {
PERFETTO_DCHECK(!valid() || type() == proto_utils::ProtoWireType::kVarInt ||
type() == proto_utils::ProtoWireType::kFixed32 ||
type() == proto_utils::ProtoWireType::kFixed64);
return int_value_;
}
inline int64_t as_int64() const {
PERFETTO_DCHECK(!valid() || type() == proto_utils::ProtoWireType::kVarInt ||
type() == proto_utils::ProtoWireType::kFixed32 ||
type() == proto_utils::ProtoWireType::kFixed64);
return static_cast<int64_t>(int_value_);
}
inline float as_float() const {
PERFETTO_DCHECK(!valid() || type() == proto_utils::ProtoWireType::kFixed32);
float res;
uint32_t value32 = static_cast<uint32_t>(int_value_);
memcpy(&res, &value32, sizeof(res));
return res;
}
inline double as_double() const {
PERFETTO_DCHECK(!valid() || type() == proto_utils::ProtoWireType::kFixed64);
double res;
memcpy(&res, &int_value_, sizeof(res));
return res;
}
inline ConstChars as_string() const {
PERFETTO_DCHECK(!valid() ||
type() == proto_utils::ProtoWireType::kLengthDelimited);
return ConstChars{reinterpret_cast<const char*>(data()), size_};
}
inline std::string as_std_string() const { return as_string().ToStdString(); }
inline ConstBytes as_bytes() const {
PERFETTO_DCHECK(!valid() ||
type() == proto_utils::ProtoWireType::kLengthDelimited);
return ConstBytes{data(), size_};
}
inline const uint8_t* data() const {
PERFETTO_DCHECK(!valid() ||
type() == proto_utils::ProtoWireType::kLengthDelimited);
return reinterpret_cast<const uint8_t*>(int_value_);
}
inline size_t size() const {
PERFETTO_DCHECK(!valid() ||
type() == proto_utils::ProtoWireType::kLengthDelimited);
return size_;
}
inline uint64_t raw_int_value() const { return int_value_; }
inline void initialize(uint16_t id,
uint8_t type,
uint64_t int_value,
uint32_t size) {
id_ = id;
type_ = type;
int_value_ = int_value;
size_ = size;
}
private:
// Fields are deliberately not initialized to keep the class trivially
// constructible. It makes a large perf difference for ProtoDecoder.
uint64_t int_value_; // In kLengthDelimited this contains the data() addr.
uint32_t size_; // Only valid when when type == kLengthDelimited.
uint16_t id_; // Proto field ordinal.
uint8_t type_; // proto_utils::ProtoWireType.
};
// The Field struct is used in a lot of perf-sensitive contexts.
static_assert(sizeof(Field) == 16, "Field struct too big");
} // namespace protozero
#endif // INCLUDE_PERFETTO_PROTOZERO_FIELD_H_