C/C++ API Reference
Loading...
Searching...
No Matches
serialized_size.h
1// Copyright 2020 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14#pragma once
15
16#include <cstdint>
17
18#include "pw_protobuf/wire_format.h"
19#include "pw_varint/varint.h"
20
21namespace pw::protobuf {
22
24
25// Field types that directly map to fixed wire types:
26inline constexpr size_t kMaxSizeBytesFixed32 = 4;
27inline constexpr size_t kMaxSizeBytesFixed64 = 8;
28inline constexpr size_t kMaxSizeBytesSfixed32 = 4;
29inline constexpr size_t kMaxSizeBytesSfixed64 = 8;
30inline constexpr size_t kMaxSizeBytesFloat = kMaxSizeBytesFixed32;
31inline constexpr size_t kMaxSizeBytesDouble = kMaxSizeBytesFixed64;
32
33// Field types that map to varint:
34inline constexpr size_t kMaxSizeBytesUint32 = varint::kMaxVarint32SizeBytes;
35inline constexpr size_t kMaxSizeBytesUint64 = varint::kMaxVarint64SizeBytes;
36inline constexpr size_t kMaxSizeBytesSint32 = varint::kMaxVarint32SizeBytes;
37inline constexpr size_t kMaxSizeBytesSint64 = varint::kMaxVarint64SizeBytes;
38// The int32 field type does not use zigzag encoding, ergo negative values
39// can result in the worst case varint size.
40inline constexpr size_t kMaxSizeBytesInt32 = varint::kMaxVarint64SizeBytes;
41inline constexpr size_t kMaxSizeBytesInt64 = varint::kMaxVarint64SizeBytes;
42// The bool field type is backed by a varint, but has a limited value range.
43inline constexpr size_t kMaxSizeBytesBool = 1;
44
45inline constexpr size_t kMaxSizeBytesEnum = kMaxSizeBytesInt32;
46
47inline constexpr size_t kMaxSizeOfFieldNumber = varint::kMaxVarint32SizeBytes;
48
49inline constexpr size_t kMaxSizeOfLength = varint::kMaxVarint32SizeBytes;
50
51// Calculate the serialized size of a proto tag (field number + wire type).
52//
53// Args:
54// field_number: The field number for the field.
55//
56// Returns:
57// The size of the field's encoded tag.
58//
59// Precondition: The field_number must be a ValidFieldNumber.
60template <typename T>
61constexpr size_t TagSizeBytes(T field_number) {
62 static_assert((std::is_enum<T>() || std::is_integral<T>()) &&
63 sizeof(T) <= sizeof(uint32_t),
64 "Field numbers must be 32-bit enums or integers");
65 // The wiretype does not impact the serialized size, so use kVarint (0), which
66 // will be optimized out by the compiler.
68 FieldKey(static_cast<uint32_t>(field_number), WireType::kVarint));
69}
70
71// Calculates the size of a varint field (uint32/64, int32/64, sint32/64, enum).
72template <typename T, typename U>
73constexpr size_t SizeOfVarintField(T field_number, U value) {
74 return TagSizeBytes(field_number) +
75 varint::EncodedSize(static_cast<uint64_t>(value));
76}
77
78// Calculates the size of a delimited field (string, bytes, nested message,
79// packed repeated), excluding the data itself. This accounts for the field
80// tag and length varint only. The default value for length_bytes assumes
81// the length is kMaxSizeOfLength bytes long.
82template <typename T>
83constexpr size_t SizeOfDelimitedFieldWithoutValue(
84 T field_number,
85 uint32_t length_bytes = std::numeric_limits<uint32_t>::max()) {
86 return TagSizeBytes(field_number) + varint::EncodedSize(length_bytes);
87}
88
89// Calculates the total size of a delimited field (string, bytes, nested
90// message, packed repeated), including the data itself.
91template <typename T>
92constexpr size_t SizeOfDelimitedField(T field_number, uint32_t length_bytes) {
93 return SizeOfDelimitedFieldWithoutValue(field_number, length_bytes) +
94 length_bytes;
95}
96
97// Calculates the size of a proto field in the wire format. This is the size of
98// a final serialized protobuf entry, including the key (field number + wire
99// type), encoded payload size (for length-delimited types), and data.
100//
101// Args:
102// field_number: The field number for the field.
103// type: The wire type of the field
104// data_size: The size of the payload.
105//
106// Returns:
107// The size of the field.
108//
109// Precondition: The field_number must be a ValidFieldNumber.
110// Precondition: `data_size_bytes` must be smaller than
111// std::numeric_limits<uint32_t>::max()
112template <typename T>
113constexpr size_t SizeOfField(T field_number,
114 WireType type,
115 size_t data_size_bytes) {
116 if (type == WireType::kDelimited) {
117 PW_DASSERT(data_size_bytes <= std::numeric_limits<uint32_t>::max());
118 return SizeOfDelimitedField(field_number,
119 static_cast<uint32_t>(data_size_bytes));
120 }
121 return TagSizeBytes(field_number) + data_size_bytes;
122}
123
124// Functions for calculating the size of each type of protobuf field. Varint
125// fields (int32, uint64, etc.) accept a value argument that defaults to the
126// largest-to-encode value for the type.
127template <typename T>
128constexpr size_t SizeOfFieldFloat(T field_number) {
129 return TagSizeBytes(field_number) + sizeof(float);
130}
131template <typename T>
132constexpr size_t SizeOfFieldDouble(T field_number) {
133 return TagSizeBytes(field_number) + sizeof(double);
134}
135template <typename T>
136constexpr size_t SizeOfFieldInt32(T field_number, int32_t value = -1) {
137 return SizeOfVarintField(field_number, value);
138}
139template <typename T>
140constexpr size_t SizeOfFieldInt64(T field_number, int64_t value = -1) {
141 return SizeOfVarintField(field_number, value);
142}
143template <typename T>
144constexpr size_t SizeOfFieldSint32(
145 T field_number, int32_t value = std::numeric_limits<int32_t>::min()) {
146 return SizeOfVarintField(field_number, varint::ZigZagEncode(value));
147}
148template <typename T>
149constexpr size_t SizeOfFieldSint64(
150 T field_number, int64_t value = std::numeric_limits<int64_t>::min()) {
151 return SizeOfVarintField(field_number, varint::ZigZagEncode(value));
152}
153template <typename T>
154constexpr size_t SizeOfFieldUint32(
155 T field_number, uint32_t value = std::numeric_limits<uint32_t>::max()) {
156 return SizeOfVarintField(field_number, value);
157}
158template <typename T>
159constexpr size_t SizeOfFieldUint64(
160 T field_number, uint64_t value = std::numeric_limits<uint64_t>::max()) {
161 return SizeOfVarintField(field_number, value);
162}
163template <typename T>
164constexpr size_t SizeOfFieldFixed32(T field_number) {
165 return TagSizeBytes(field_number) + sizeof(uint32_t);
166}
167template <typename T>
168constexpr size_t SizeOfFieldFixed64(T field_number) {
169 return TagSizeBytes(field_number) + sizeof(uint64_t);
170}
171template <typename T>
172constexpr size_t SizeOfFieldSfixed32(T field_number) {
173 return TagSizeBytes(field_number) + sizeof(uint32_t);
174}
175template <typename T>
176constexpr size_t SizeOfFieldSfixed64(T field_number) {
177 return TagSizeBytes(field_number) + sizeof(uint64_t);
178}
179template <typename T>
180constexpr size_t SizeOfFieldBool(T field_number) {
181 return TagSizeBytes(field_number) + 1;
182}
183template <typename T>
184constexpr size_t SizeOfFieldString(T field_number, uint32_t length_bytes) {
185 return SizeOfDelimitedField(field_number, length_bytes);
186}
187template <typename T>
188constexpr size_t SizeOfFieldBytes(T field_number, uint32_t length_bytes) {
189 return SizeOfDelimitedField(field_number, length_bytes);
190}
191template <typename T, typename U = int32_t>
192constexpr size_t SizeOfFieldEnum(T field_number, U value = static_cast<U>(-1)) {
193 static_assert((std::is_enum<U>() || std::is_integral<U>()) &&
194 sizeof(U) <= sizeof(uint32_t),
195 "Enum values must be 32-bit enums or integers");
196 return SizeOfFieldInt32(field_number, static_cast<int32_t>(value));
197}
198
200
201} // namespace pw::protobuf
constexpr size_t kMaxVarint32SizeBytes
Maximum size of a varint (LEB128) encoded uint32_t.
Definition: varint.h:74
constexpr std::make_unsigned_t< T > ZigZagEncode(T value)
Definition: varint.h:365
constexpr size_t kMaxVarint64SizeBytes
Maximum size of a varint (LEB128) encoded uint64_t.
Definition: varint.h:77
constexpr size_t EncodedSize(T value)
Computes the size of an integer when encoded as a varint.
Definition: varint.h:123