blob: 542653d153ab289e08bc6273b0e3ae4279512a01 [file] [log] [blame]
// Copyright 2022 The Pigweed Authors
//
// 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
//
// https://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.
#include "proto_bloat.h"
#include <array>
#include <cstdint>
#include <string_view>
#include "pw_containers/vector.h"
#include "pw_preprocessor/concat.h"
#include "pw_protobuf/decoder.h"
#include "pw_protobuf/encoder.h"
#include "pw_protobuf/stream_decoder.h"
#include "pw_status/status.h"
#include "pw_stream/null_stream.h"
#include "pw_stream/stream.h"
namespace pw::protobuf_size_report {
namespace {
template <typename T>
constexpr std::array<T, 4> GetIntegerArray() {
return std::array<T, 4>{958736, 2085792374, 0, 42};
}
template <typename T>
constexpr Vector<T, 4> GetIntegerVector() {
return Vector<T, 4>{958736, 2085792374, 0, 42};
}
constexpr std::array<bool, 5> GetBoolArray() {
return std::array<bool, 5>{true, false, false, true, true};
}
Vector<bool, 5> GetBoolVector() {
return Vector<bool, 5>{true, false, false, true, true};
}
constexpr std::array<float, 5> GetFloatArray() {
return std::array<float, 5>{1.2f, 3.4f, 5.6e20f, 0.0789f, 0.0f};
}
Vector<float, 5> GetFloatVector() {
return Vector<float, 5>{1.2f, 3.4f, 5.6e20f, 0.0789f, 0.0f};
}
constexpr std::array<double, 5> GetDoubleArray() {
return std::array<double, 5>{1.2, 3.4, 5.6e20, 0.0789, 0.0};
}
Vector<double, 5> GetDoubleVector() {
return Vector<double, 5>{1.2, 3.4, 5.6e20, 0.0789, 0.0};
}
constexpr std::string_view kTestString("I eat chips too often");
constexpr protobuf::internal::MessageField kFakeTable[] = {
{4567,
protobuf::WireType::kDelimited,
234567,
protobuf::internal::VarintType::kNormal,
false,
true,
true,
true,
true,
260,
840245,
nullptr},
{4567,
protobuf::WireType::kDelimited,
234567,
protobuf::internal::VarintType::kNormal,
false,
true,
true,
true,
true,
260,
840245,
nullptr}};
class FakeMessageEncoder : public protobuf::StreamEncoder {
public:
FakeMessageEncoder(stream::Writer& writer)
: protobuf::StreamEncoder(writer, ByteSpan()) {}
void DoBloat() { Write(ByteSpan(), kFakeTable); }
};
class FakeMessageDecoder : public protobuf::StreamDecoder {
public:
FakeMessageDecoder(stream::Reader& reader)
: protobuf::StreamDecoder(reader) {}
void DoBloat() { Read(ByteSpan(), kFakeTable); }
};
void CodeToSetUpSizeReportEnvironment() {
[[maybe_unused]] volatile auto arr1 = GetIntegerArray<uint32_t>();
[[maybe_unused]] volatile auto arr2 = GetIntegerArray<int32_t>();
[[maybe_unused]] volatile auto arr3 = GetIntegerArray<uint64_t>();
[[maybe_unused]] volatile auto arr4 = GetIntegerArray<int64_t>();
[[maybe_unused]] volatile auto vec1 = GetIntegerVector<uint32_t>();
[[maybe_unused]] volatile auto vec2 = GetIntegerVector<int32_t>();
[[maybe_unused]] volatile auto vec3 = GetIntegerVector<uint64_t>();
[[maybe_unused]] volatile auto vec4 = GetIntegerVector<int64_t>();
[[maybe_unused]] volatile auto bool1 = GetBoolArray();
[[maybe_unused]] volatile auto bool2 = GetBoolVector();
[[maybe_unused]] volatile auto float1 = GetFloatArray();
[[maybe_unused]] volatile auto float2 = GetFloatVector();
[[maybe_unused]] volatile auto double1 = GetDoubleArray();
[[maybe_unused]] volatile auto double2 = GetDoubleVector();
[[maybe_unused]] volatile std::string_view test_string = kTestString;
[[maybe_unused]] volatile stream::NullStream null_stream;
}
void Dependencies() {
std::array<std::byte, 2> buffer;
stream::NullStream null_stream;
stream::MemoryWriter memory_writer(buffer);
memory_writer.Write(buffer);
null_stream.Write(buffer);
stream::MemoryReader memory_reader(buffer);
memory_reader.Read(buffer).IgnoreError();
}
void CodeToPullInProtoEncoder() {
std::array<std::byte, 1024> buffer;
protobuf::MemoryEncoder encoder(buffer);
encoder.WriteUint32(1, 1);
encoder.WritePackedUint32(1, GetIntegerArray<uint32_t>());
encoder.WriteRepeatedUint32(1, GetIntegerVector<uint32_t>());
encoder.WriteInt32(1, 1);
encoder.WritePackedInt32(1, GetIntegerArray<int32_t>());
encoder.WriteRepeatedInt32(1, GetIntegerVector<int32_t>());
encoder.WriteUint64(1, 1);
encoder.WritePackedUint64(1, GetIntegerArray<uint64_t>());
encoder.WriteRepeatedUint64(1, GetIntegerVector<uint64_t>());
encoder.WriteInt64(1, 1);
encoder.WritePackedInt64(1, GetIntegerArray<int64_t>());
encoder.WriteRepeatedInt64(1, GetIntegerVector<int64_t>());
encoder.WriteSint32(1, 1);
encoder.WritePackedSint32(1, GetIntegerArray<int32_t>());
encoder.WriteRepeatedSint32(1, GetIntegerVector<int32_t>());
encoder.WriteSint64(1, 1);
encoder.WritePackedSint64(1, GetIntegerArray<int64_t>());
encoder.WriteRepeatedSint64(1, GetIntegerVector<int64_t>());
encoder.WriteFixed32(1, 1);
encoder.WritePackedFixed32(1, GetIntegerArray<uint32_t>());
encoder.WriteRepeatedFixed32(1, GetIntegerVector<uint32_t>());
encoder.WriteFixed64(1, 1);
encoder.WritePackedFixed64(1, GetIntegerArray<uint64_t>());
encoder.WriteRepeatedFixed64(1, GetIntegerVector<uint64_t>());
encoder.WriteSfixed32(1, 1);
encoder.WritePackedSfixed32(1, GetIntegerArray<int32_t>());
encoder.WriteRepeatedSfixed32(1, GetIntegerVector<int32_t>());
encoder.WriteSfixed64(1, 1);
encoder.WritePackedSfixed64(1, GetIntegerArray<int64_t>());
encoder.WriteRepeatedSfixed64(1, GetIntegerVector<int64_t>());
{
protobuf::StreamEncoder child = encoder.GetNestedEncoder(0xc01dfee7);
child.WriteFloat(234, 3.14f);
child.WritePackedFloat(234, GetFloatArray());
child.WriteRepeatedFloat(234, GetFloatVector());
child.WriteFloat(234, 3.14);
child.WritePackedDouble(234, GetDoubleArray());
child.WriteRepeatedDouble(234, GetDoubleVector());
child.WriteBool(7, true);
child.WritePackedBool(8, GetBoolArray());
child.WriteRepeatedBool(8, GetBoolVector());
encoder.WriteBytes(93, as_bytes(span(GetDoubleArray())));
encoder.WriteString(21343, kTestString);
}
stream::NullStream null_stream;
protobuf::StreamEncoder stream_encoder(null_stream, buffer);
stream_encoder.WriteBytesFromStream(3636, null_stream, 10824, buffer);
}
void CodeToPullInTableEncoder() {
stream::NullStream stream;
FakeMessageEncoder fake_encoder(stream);
fake_encoder.DoBloat();
}
void CodeToPullInTableDecoder() {
stream::NullStream stream;
FakeMessageDecoder fake_decoder(stream);
fake_decoder.DoBloat();
}
#define _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(type_camel_case, underlying_type) \
do { \
Status status; \
Vector<underlying_type, 3> vec; \
span<underlying_type> packed_span; \
status.Update(decoder.PW_CONCAT(Read, type_camel_case)().status()); \
status.Update( \
decoder.PW_CONCAT(ReadPacked, type_camel_case)(packed_span).status()); \
status.Update(decoder.PW_CONCAT(ReadRepeated, type_camel_case)(vec)); \
[[maybe_unused]] volatile bool ok = status.ok(); \
} while (0)
void CodeToPullInProtoStreamDecoder() {
stream::NullStream null_stream;
protobuf::StreamDecoder decoder(null_stream);
decoder.Next().IgnoreError();
_PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Int32, int32_t);
_PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Uint32, uint32_t);
_PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Int64, int64_t);
_PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Uint64, uint64_t);
_PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Sint32, int32_t);
_PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Sint64, int64_t);
_PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Bool, bool);
_PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Fixed32, uint32_t);
_PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Fixed64, uint64_t);
_PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Sfixed32, int32_t);
_PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Sfixed64, int64_t);
_PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Float, float);
_PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Double, double);
{
Status status;
span<char> str_out;
span<std::byte> bytes_out;
status.Update(decoder.ReadString(str_out).status());
status.Update(decoder.ReadBytes(bytes_out).status());
status.Update(decoder.GetLengthDelimitedPayloadBounds().status());
[[maybe_unused]] volatile Result<uint32_t> field_number =
decoder.FieldNumber();
[[maybe_unused]] volatile protobuf::StreamDecoder::BytesReader
bytes_reader = decoder.GetBytesReader();
[[maybe_unused]] volatile bool ok = status.ok();
}
}
#define _PW_USE_FUNCTIONS_FOR_DECODER(type_camel_case, underlying_type) \
do { \
Status status; \
underlying_type val; \
status.Update(decoder.PW_CONCAT(Read, type_camel_case)(&val)); \
[[maybe_unused]] volatile bool ok = status.ok(); \
} while (0)
void CodeToPullInProtoDecoder() {
std::array<std::byte, 3> buffer = {
std::byte(0x01), std::byte(0xff), std::byte(0x08)};
protobuf::Decoder decoder(buffer);
decoder.Next().IgnoreError();
_PW_USE_FUNCTIONS_FOR_DECODER(Int32, int32_t);
_PW_USE_FUNCTIONS_FOR_DECODER(Uint32, uint32_t);
_PW_USE_FUNCTIONS_FOR_DECODER(Int64, int64_t);
_PW_USE_FUNCTIONS_FOR_DECODER(Uint64, uint64_t);
_PW_USE_FUNCTIONS_FOR_DECODER(Sint32, int32_t);
_PW_USE_FUNCTIONS_FOR_DECODER(Sint64, int64_t);
_PW_USE_FUNCTIONS_FOR_DECODER(Bool, bool);
_PW_USE_FUNCTIONS_FOR_DECODER(Fixed32, uint32_t);
_PW_USE_FUNCTIONS_FOR_DECODER(Fixed64, uint64_t);
_PW_USE_FUNCTIONS_FOR_DECODER(Sfixed32, int32_t);
_PW_USE_FUNCTIONS_FOR_DECODER(Sfixed64, int64_t);
_PW_USE_FUNCTIONS_FOR_DECODER(Float, float);
_PW_USE_FUNCTIONS_FOR_DECODER(Double, double);
{
Status status;
std::string_view str_out;
span<const std::byte> bytes_out;
status.Update(decoder.ReadString(&str_out));
status.Update(decoder.ReadBytes(&bytes_out));
decoder.Reset(buffer);
[[maybe_unused]] volatile uint32_t field_number = decoder.FieldNumber();
[[maybe_unused]] volatile bool ok = status.ok();
}
}
} // namespace
void BloatWithBase() {
CodeToSetUpSizeReportEnvironment();
Dependencies();
}
void BloatWithEncoder() {
BloatWithBase();
CodeToPullInProtoEncoder();
}
void BloatWithTableEncoder() {
BloatWithBase();
CodeToPullInTableEncoder();
}
void BloatWithTableDecoder() {
BloatWithBase();
CodeToPullInTableDecoder();
}
void BloatWithStreamDecoder() {
BloatWithBase();
CodeToPullInProtoStreamDecoder();
}
void BloatWithDecoder() {
BloatWithBase();
CodeToPullInProtoDecoder();
}
} // namespace pw::protobuf_size_report