mirror of
https://gitee.com/openharmony/developtools_profiler
synced 2024-11-23 15:00:17 +00:00
ProtoEncoder框架代码
Signed-off-by:wenlong12 <wenlong12@huawei.com> Signed-off-by: wenlong12 <wenlong12@huawei.com>
This commit is contained in:
parent
5b3b29d6ae
commit
901b54cb8e
@ -21,6 +21,9 @@ OHOS_X64_OUT=$PROJECT_TOP/$2/
|
|||||||
LIBCXX_X64_OUT=$PROJECT_TOP/$1/ndk/libcxx/linux_x86_64
|
LIBCXX_X64_OUT=$PROJECT_TOP/$1/ndk/libcxx/linux_x86_64
|
||||||
SUBSYS_X64_OUT=$PROJECT_TOP/$2/developtools/profiler
|
SUBSYS_X64_OUT=$PROJECT_TOP/$2/developtools/profiler
|
||||||
PROTOC=$PROJECT_TOP/$2/developtools/profiler/protoc
|
PROTOC=$PROJECT_TOP/$2/developtools/profiler/protoc
|
||||||
|
OPT_PLUGIN_PATH=$PROJECT_TOP/$2/developtools/profiler/protoencoder_plugin
|
||||||
|
OPT_PLUGIN=--plugin=protoc-gen-opt=$PROJECT_TOP/$2/developtools/profiler/protoencoder_plugin
|
||||||
|
OPT_OUT=--opt_out
|
||||||
PYTHON_SHELL=$THIS_DIR/make_standard_proto.py # shell path
|
PYTHON_SHELL=$THIS_DIR/make_standard_proto.py # shell path
|
||||||
TMP=$2
|
TMP=$2
|
||||||
PROTO_OUT_DIR="$PROJECT_TOP/${TMP%/*}/$3" # path of the new proto file
|
PROTO_OUT_DIR="$PROJECT_TOP/${TMP%/*}/$3" # path of the new proto file
|
||||||
@ -56,5 +59,14 @@ do
|
|||||||
done
|
done
|
||||||
PARAMS_ALL="$PARAMS_SRC $PARAMS_STANDARD" # add new argument list to old argument list
|
PARAMS_ALL="$PARAMS_SRC $PARAMS_STANDARD" # add new argument list to old argument list
|
||||||
|
|
||||||
|
# avoid conflict, param4=--plugin* means ipc plugin, generate encode file if opt plugin exist
|
||||||
|
if [[ "$4" != --plugin* ]]; then
|
||||||
|
if [ -f "$OPT_PLUGIN_PATH" ]; then
|
||||||
|
echo "generate protobuf optimize code OPT_PLUGIN = $OPT_PLUGIN"
|
||||||
|
echo "optimize EXEC: LD_LIBRARY_PATH=$LIBCXX_X64_OUT:$SUBSYS_X64_OUT $PROTOC $OPT_PLUGIN $OPT_OUT $5 $PARAMS_ALL"
|
||||||
|
LD_LIBRARY_PATH=$LIBCXX_X64_OUT:$SUBSYS_X64_OUT exec $PROTOC $OPT_PLUGIN $OPT_OUT $5 $PARAMS_ALL
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
echo "EXEC: LD_LIBRARY_PATH=$LIBCXX_X64_OUT:$SUBSYS_X64_OUT $PROTOC $PARAMS_ALL"
|
echo "EXEC: LD_LIBRARY_PATH=$LIBCXX_X64_OUT:$SUBSYS_X64_OUT $PROTOC $PARAMS_ALL"
|
||||||
LD_LIBRARY_PATH=$LIBCXX_X64_OUT:$SUBSYS_X64_OUT exec $PROTOC $PARAMS_ALL
|
LD_LIBRARY_PATH=$LIBCXX_X64_OUT:$SUBSYS_X64_OUT exec $PROTOC $PARAMS_ALL
|
||||||
|
@ -82,7 +82,8 @@
|
|||||||
"//developtools/profiler/device:fuzztest",
|
"//developtools/profiler/device:fuzztest",
|
||||||
"//developtools/profiler/device:unittest",
|
"//developtools/profiler/device:unittest",
|
||||||
"//developtools/profiler/interfaces/kits/test:unittest",
|
"//developtools/profiler/interfaces/kits/test:unittest",
|
||||||
"//developtools/profiler/hidebug/test/unittest:unittest"
|
"//developtools/profiler/hidebug/test/unittest:unittest",
|
||||||
|
"//developtools/profiler/proto_encoder/test:unittest"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ const WriterStruct* WriterAdapter::GetStruct()
|
|||||||
return &writerStruct_;
|
return &writerStruct_;
|
||||||
}
|
}
|
||||||
|
|
||||||
long WriterAdapter::WriteFunc(WriterStruct* writer, const void* data, size_t size)
|
long WriterAdapter::WriteFunc(WriterStruct* writer, const char* data, size_t size)
|
||||||
{
|
{
|
||||||
static_assert(offsetof(WriterAdapter, writerStruct_) == 0, "unexpected alignment of writerStruct_!");
|
static_assert(offsetof(WriterAdapter, writerStruct_) == 0, "unexpected alignment of writerStruct_!");
|
||||||
WriterAdapter* writerAdaptor = reinterpret_cast<WriterAdapter*>(writer); // 转成 WriterAdapter*
|
WriterAdapter* writerAdaptor = reinterpret_cast<WriterAdapter*>(writer); // 转成 WriterAdapter*
|
||||||
|
@ -31,7 +31,7 @@ public:
|
|||||||
WriterPtr GetWriter();
|
WriterPtr GetWriter();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static long WriteFunc(WriterStruct* writer, const void* data, size_t size);
|
static long WriteFunc(WriterStruct* writer, const char* data, size_t size);
|
||||||
static bool FlushFunc(WriterStruct* writer);
|
static bool FlushFunc(WriterStruct* writer);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -69,3 +69,24 @@ ohos_executable("protoc_gen_ipc") {
|
|||||||
subsystem_name = "${OHOS_PROFILER_SUBSYS_NAME}"
|
subsystem_name = "${OHOS_PROFILER_SUBSYS_NAME}"
|
||||||
part_name = "${OHOS_PROFILER_PART_NAME}"
|
part_name = "${OHOS_PROFILER_PART_NAME}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ohos_executable("protoencoder_plugin") {
|
||||||
|
sources = [
|
||||||
|
"src/proto_encoder_plugin.cpp",
|
||||||
|
"src/proto_encoder_plugin_generator.cpp",
|
||||||
|
]
|
||||||
|
|
||||||
|
include_dirs = [
|
||||||
|
"include",
|
||||||
|
"${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}",
|
||||||
|
]
|
||||||
|
public_configs = [ "${OHOS_PROFILER_DIR}/device/base:hiprofiler_test_config" ]
|
||||||
|
deps = [
|
||||||
|
"${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf",
|
||||||
|
"${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite",
|
||||||
|
"${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc_lib(${host_toolchain})",
|
||||||
|
]
|
||||||
|
install_enable = false
|
||||||
|
subsystem_name = "${OHOS_PROFILER_SUBSYS_NAME}"
|
||||||
|
part_name = "${OHOS_PROFILER_PART_NAME}"
|
||||||
|
}
|
||||||
|
39
device/services/ipc/include/proto_encoder_plugin_generator.h
Executable file
39
device/services/ipc/include/proto_encoder_plugin_generator.h
Executable file
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021 Huawei Device Co., Ltd.
|
||||||
|
* 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 PROTO_ENCODER_GENERATOR_H
|
||||||
|
#define PROTO_ENCODER_GENERATOR_H
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include "google/protobuf/compiler/code_generator.h"
|
||||||
|
#include "google/protobuf/compiler/plugin.h"
|
||||||
|
#include "google/protobuf/descriptor.h"
|
||||||
|
#include "google/protobuf/io/coded_stream.h"
|
||||||
|
#include "google/protobuf/io/zero_copy_stream.h"
|
||||||
|
#include <google/protobuf/io/printer.h>
|
||||||
|
|
||||||
|
class ProtoEncoderGenerator : public google::protobuf::compiler::CodeGenerator {
|
||||||
|
public:
|
||||||
|
ProtoEncoderGenerator();
|
||||||
|
~ProtoEncoderGenerator();
|
||||||
|
bool Generate(const google::protobuf::FileDescriptor* file,
|
||||||
|
const std::string& parameter,
|
||||||
|
google::protobuf::compiler::GeneratorContext* context,
|
||||||
|
std::string* error) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
23
device/services/ipc/src/proto_encoder_plugin.cpp
Executable file
23
device/services/ipc/src/proto_encoder_plugin.cpp
Executable file
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021 Huawei Device Co., Ltd.
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include "proto_encoder_plugin_generator.h"
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
ProtoEncoderGenerator generator;
|
||||||
|
return google::protobuf::compiler::PluginMain(argc, argv, &generator);
|
||||||
|
}
|
409
device/services/ipc/src/proto_encoder_plugin_generator.cpp
Executable file
409
device/services/ipc/src/proto_encoder_plugin_generator.cpp
Executable file
@ -0,0 +1,409 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021 Huawei Device Co., Ltd.
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "proto_encoder_plugin_generator.h"
|
||||||
|
|
||||||
|
using google::protobuf::FileDescriptor;
|
||||||
|
using google::protobuf::EnumDescriptor;
|
||||||
|
using google::protobuf::Descriptor;
|
||||||
|
using google::protobuf::io::Printer;
|
||||||
|
using google::protobuf::EnumValueDescriptor;
|
||||||
|
using google::protobuf::FieldDescriptor;
|
||||||
|
|
||||||
|
class OptGeneratorImpl {
|
||||||
|
public:
|
||||||
|
explicit OptGeneratorImpl(const FileDescriptor* file) : fileContent_(file), printer_(nullptr) {}
|
||||||
|
|
||||||
|
std::string GetPrefix(std::string fileName)
|
||||||
|
{
|
||||||
|
std::string prefix = "";
|
||||||
|
for (size_t i = 0; i < fileName.length(); i++) {
|
||||||
|
if (fileName.c_str()[i] == '.') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
prefix += fileName.c_str()[i];
|
||||||
|
}
|
||||||
|
return prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string SetNames(std::string fileName, std::string packageName)
|
||||||
|
{
|
||||||
|
fileName_ = fileName;
|
||||||
|
packageName_ = packageName + "::";
|
||||||
|
headFileName_ = "";
|
||||||
|
|
||||||
|
for (size_t i = 0; i < fileName.length(); i++) {
|
||||||
|
if (fileName.c_str()[i] == '.') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
headFileName_ += fileName.c_str()[i];
|
||||||
|
}
|
||||||
|
baseName_ = SwapName(headFileName_);
|
||||||
|
return headFileName_;
|
||||||
|
}
|
||||||
|
std::string SwapName(std::string s)
|
||||||
|
{
|
||||||
|
std::string ret = "";
|
||||||
|
bool b = true;
|
||||||
|
for (size_t i = 0; i < s.length(); i++) {
|
||||||
|
char c = s[i];
|
||||||
|
if (c == '_') {
|
||||||
|
b = true;
|
||||||
|
} else if (b && c >= 'a' && c <= 'z') {
|
||||||
|
ret += (c + 'A' - 'a');
|
||||||
|
b = false;
|
||||||
|
} else {
|
||||||
|
ret += c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Tolowercase(const std::string& s)
|
||||||
|
{
|
||||||
|
std::string str = s;
|
||||||
|
std::transform(str.begin(), str.end(), str.begin(), [](char& c) {
|
||||||
|
return std::tolower(c);
|
||||||
|
});
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GenHeader()
|
||||||
|
{
|
||||||
|
GenPrefix();
|
||||||
|
GenerateEnum();
|
||||||
|
GenerateClass();
|
||||||
|
GenSurfix();
|
||||||
|
}
|
||||||
|
void GenPrefix()
|
||||||
|
{
|
||||||
|
printer_->Print("// Generated by protoencoder plugin.\n");
|
||||||
|
printer_->Print("#pragma once\n");
|
||||||
|
printer_->Print("#include \"base_message.h\"\n");
|
||||||
|
|
||||||
|
for (int i = 0; i < fileContent_->dependency_count(); ++i) {
|
||||||
|
printer_->Print("#include \"@name@.pbencoder.h\"\n", "name",
|
||||||
|
GetPrefix(fileContent_->dependency(i)->name()));
|
||||||
|
}
|
||||||
|
|
||||||
|
printer_->Print("namespace OHOS {\n");
|
||||||
|
printer_->Print("namespace Developtools {\n");
|
||||||
|
printer_->Print("namespace Profiler {\n");
|
||||||
|
printer_->Print("namespace ProtoEncoder {\n");
|
||||||
|
}
|
||||||
|
void GenerateEnum()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < fileContent_->enum_type_count(); ++i) {
|
||||||
|
printer_->Print("enum @class@ : uint32_t {\n", "class", fileContent_->enum_type(i)->name());
|
||||||
|
printer_->Indent();
|
||||||
|
|
||||||
|
for (int j = 0; j < fileContent_->enum_type(i)->value_count(); ++j) {
|
||||||
|
const EnumValueDescriptor* value = fileContent_->enum_type(i)->value(j);
|
||||||
|
const std::string value_name = value->name();
|
||||||
|
printer_->Print("@name@ = @number@,\n", "name", value_name, "number",
|
||||||
|
std::to_string(value->number()));
|
||||||
|
}
|
||||||
|
printer_->Outdent();
|
||||||
|
printer_->Print("};\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void GenerateClass()
|
||||||
|
{
|
||||||
|
// forward declaration
|
||||||
|
for (int i = 0; i < fileContent_->message_type_count(); ++i) {
|
||||||
|
const Descriptor* message = fileContent_->message_type(i);
|
||||||
|
printer_->Print("class @name@;\n", "name", message->name());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < fileContent_->message_type_count(); ++i) {
|
||||||
|
const Descriptor* message = fileContent_->message_type(i);
|
||||||
|
for (int j = 0; j < message->nested_type_count(); ++j) {
|
||||||
|
const Descriptor* nestmessage = message->nested_type(j);
|
||||||
|
printer_->Print(
|
||||||
|
"class @name@ : public BaseMessage {\n"
|
||||||
|
" public:\n",
|
||||||
|
"name", nestmessage->name());
|
||||||
|
printer_->Indent();
|
||||||
|
printer_->Print("@name@() = default;\n", "name", nestmessage->name());
|
||||||
|
printer_->Print(
|
||||||
|
"explicit @name@(RandomWriteCtx* writeCtx, MessageStack* subMessageStack = nullptr) : BaseMessage(writeCtx, subMessageStack) {}\n",
|
||||||
|
"name", nestmessage->name());
|
||||||
|
GenerateFieldsID(nestmessage);
|
||||||
|
GenerateFunction(nestmessage);
|
||||||
|
printer_->Outdent();
|
||||||
|
printer_->Print("};\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
printer_->Print(
|
||||||
|
"class @name@ : public BaseMessage {\n"
|
||||||
|
" public:\n",
|
||||||
|
"name", message->name());
|
||||||
|
printer_->Indent();
|
||||||
|
printer_->Print("@name@() = default;\n", "name", message->name());
|
||||||
|
printer_->Print(
|
||||||
|
"explicit @name@(RandomWriteCtx* writeCtx, MessageStack* subMessageStack = nullptr) : BaseMessage(writeCtx, subMessageStack) {}\n",
|
||||||
|
"name", message->name());
|
||||||
|
GenerateFieldsID(message);
|
||||||
|
GenerateFunction(message);
|
||||||
|
printer_->Outdent();
|
||||||
|
printer_->Print("};\n\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GenerateFieldsID(const Descriptor* message)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < message->field_count(); ++i) {
|
||||||
|
const FieldDescriptor* field = message->field(i);
|
||||||
|
printer_->Print("static const uint32_t FIELDID_@name@ = @id@;\n",
|
||||||
|
"name", field->name(), "id", std::to_string(field->number()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GenerateFunction(const Descriptor* message)
|
||||||
|
{
|
||||||
|
// field->is_repeated()
|
||||||
|
for (int i = 0; i < message->field_count(); ++i) {
|
||||||
|
const FieldDescriptor* field = message->field(i);
|
||||||
|
if (field->type() == FieldDescriptor::TYPE_MESSAGE) {
|
||||||
|
printer_->Print("inline @typename@* @mora@_@name@()\n",
|
||||||
|
"mora", field->is_repeated()?"add":"mutable",
|
||||||
|
"typename", field->message_type()->name(),
|
||||||
|
"name", Tolowercase(field->name()));
|
||||||
|
printer_->Print("{\n");
|
||||||
|
printer_->Indent();
|
||||||
|
printer_->Print("return AddSubMessage<@typename@>(FIELDID_@name@);\n",
|
||||||
|
"typename", field->message_type()->name(),
|
||||||
|
"name", field->name());
|
||||||
|
printer_->Outdent();
|
||||||
|
printer_->Print("}\n");
|
||||||
|
} else if (field->type() == FieldDescriptor::TYPE_BYTES) {
|
||||||
|
printer_->Print("inline void set_@name@(const void* bytes, uint32_t size)\n",
|
||||||
|
"name", Tolowercase(field->name()));
|
||||||
|
printer_->Print("{\n");
|
||||||
|
printer_->Indent();
|
||||||
|
printer_->Print("AddBytes(FIELDID_@name@, bytes, size);\n", "name", field->name());
|
||||||
|
printer_->Outdent();
|
||||||
|
printer_->Print("}\n");
|
||||||
|
printer_->Print("void set_@name@(GetDataCallback getData)\n", "name", Tolowercase(field->name()));
|
||||||
|
printer_->Print("{\n");
|
||||||
|
printer_->Indent();
|
||||||
|
printer_->Print("return AddBytesByCallBack(FIELDID_@name@, getData);\n", "name", field->name());
|
||||||
|
printer_->Outdent();
|
||||||
|
printer_->Print("}\n");
|
||||||
|
printer_->Print("inline RandomWriteCtx* startAdd_@name@()\n", "name", Tolowercase(field->name()));
|
||||||
|
printer_->Print("{\n");
|
||||||
|
printer_->Indent();
|
||||||
|
printer_->Print("return StartAddBytes(FIELDID_@name@);\n", "name", field->name());
|
||||||
|
printer_->Outdent();
|
||||||
|
printer_->Print("}\n");
|
||||||
|
printer_->Print("inline void finishAdd_@name@(int32_t size)\n", "name", Tolowercase(field->name()));
|
||||||
|
printer_->Print("{\n");
|
||||||
|
printer_->Indent();
|
||||||
|
printer_->Print("return FinishAddBytes(size);\n", "name", field->name());
|
||||||
|
printer_->Outdent();
|
||||||
|
printer_->Print("}\n");
|
||||||
|
} else if (field->type() == FieldDescriptor::TYPE_STRING) {
|
||||||
|
printer_->Print("inline void @sora@_@name@(const std::string& str)\n",
|
||||||
|
"sora", field->is_repeated()?"add":"set",
|
||||||
|
"name", Tolowercase(field->name()));
|
||||||
|
printer_->Print("{\n");
|
||||||
|
printer_->Indent();
|
||||||
|
printer_->Print("AddBytes(FIELDID_@name@, str.data(), str.size());\n", "name", field->name());
|
||||||
|
printer_->Outdent();
|
||||||
|
printer_->Print("}\n");
|
||||||
|
printer_->Print("inline void @sora@_@name@(std::string&& str)\n",
|
||||||
|
"sora", field->is_repeated()?"add":"set",
|
||||||
|
"name", Tolowercase(field->name()));
|
||||||
|
printer_->Print("{\n");
|
||||||
|
printer_->Indent();
|
||||||
|
printer_->Print("AddBytes(FIELDID_@name@, str.data(), str.size());\n", "name", field->name());
|
||||||
|
printer_->Outdent();
|
||||||
|
printer_->Print("}\n");
|
||||||
|
printer_->Print("inline void @sora@_@name@(const char* str)\n",
|
||||||
|
"sora", field->is_repeated()?"add":"set",
|
||||||
|
"name", Tolowercase(field->name()));
|
||||||
|
printer_->Print("{\n");
|
||||||
|
printer_->Indent();
|
||||||
|
printer_->Print("AddBytes(FIELDID_@name@, str, strlen(str));\n", "name", field->name());
|
||||||
|
printer_->Outdent();
|
||||||
|
printer_->Print("}\n");
|
||||||
|
printer_->Print("inline void @sora@_@name@(const char* str, uint32_t len)\n",
|
||||||
|
"sora", field->is_repeated()?"add":"set",
|
||||||
|
"name", Tolowercase(field->name()));
|
||||||
|
printer_->Print("{\n");
|
||||||
|
printer_->Indent();
|
||||||
|
printer_->Print("AddBytes(FIELDID_@name@, str, len);\n", "name", field->name());
|
||||||
|
printer_->Outdent();
|
||||||
|
printer_->Print("}\n");
|
||||||
|
} else {
|
||||||
|
// varint, fix32, fix64
|
||||||
|
printer_->Print("inline void @sora@_@name@(@paramtype@ v)\n",
|
||||||
|
"sora", field->is_repeated()?"add":"set", "name", Tolowercase(field->name()),
|
||||||
|
"paramtype", GetParamType(field));
|
||||||
|
printer_->Print("{\n");
|
||||||
|
printer_->Indent();
|
||||||
|
printer_->Print("@type@(FIELDID_@name@, v);\n", "type",
|
||||||
|
GetInnerType(field), "name", field->name());
|
||||||
|
printer_->Outdent();
|
||||||
|
printer_->Print("}\n");
|
||||||
|
// packed
|
||||||
|
if (!field->is_repeated()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (field->type() == FieldDescriptor::TYPE_SINT32 ||
|
||||||
|
field->type() == FieldDescriptor::TYPE_SINT64) {
|
||||||
|
perror("repeated signed(zigzag) fields are not supported in libprotobuf\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!field->is_packed()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
printer_->Print("inline void add_@name@(const @paramtype@* array, uint32_t size)\n",
|
||||||
|
"name", Tolowercase(field->name()),
|
||||||
|
"paramtype", GetParamType(field));
|
||||||
|
printer_->Print("{\n");
|
||||||
|
printer_->Indent();
|
||||||
|
printer_->Print("@type@(FIELDID_@name@, array, size);\n",
|
||||||
|
"type", GetInnerType(field, true), "name", field->name());
|
||||||
|
printer_->Outdent();
|
||||||
|
printer_->Print("}\n");
|
||||||
|
|
||||||
|
printer_->Print("inline void add_@name@(const std::vector<@paramtype@>& array)\n",
|
||||||
|
"name", Tolowercase(field->name()),
|
||||||
|
"paramtype", GetParamType(field));
|
||||||
|
printer_->Print("{\n");
|
||||||
|
printer_->Indent();
|
||||||
|
printer_->Print("@type@(FIELDID_@name@, array.data(), array.size());\n",
|
||||||
|
"type", GetInnerType(field, true), "name", field->name());
|
||||||
|
printer_->Outdent();
|
||||||
|
printer_->Print("}\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::string GetParamType(const FieldDescriptor* field)
|
||||||
|
{
|
||||||
|
switch (field->type()) {
|
||||||
|
case FieldDescriptor::TYPE_BOOL:
|
||||||
|
return "bool";
|
||||||
|
case FieldDescriptor::TYPE_ENUM:
|
||||||
|
case FieldDescriptor::TYPE_UINT32:
|
||||||
|
case FieldDescriptor::TYPE_FIXED32:
|
||||||
|
return "uint32_t";
|
||||||
|
case FieldDescriptor::TYPE_INT32:
|
||||||
|
case FieldDescriptor::TYPE_SINT32:
|
||||||
|
case FieldDescriptor::TYPE_SFIXED32:
|
||||||
|
return "int32_t";
|
||||||
|
case FieldDescriptor::TYPE_INT64:
|
||||||
|
case FieldDescriptor::TYPE_SINT64:
|
||||||
|
case FieldDescriptor::TYPE_SFIXED64:
|
||||||
|
return "int64_t";
|
||||||
|
case FieldDescriptor::TYPE_UINT64:
|
||||||
|
case FieldDescriptor::TYPE_FIXED64:
|
||||||
|
return "uint64_t";
|
||||||
|
case FieldDescriptor::TYPE_DOUBLE:
|
||||||
|
return "double";
|
||||||
|
case FieldDescriptor::TYPE_FLOAT:
|
||||||
|
return "float";
|
||||||
|
case FieldDescriptor::TYPE_STRING:
|
||||||
|
case FieldDescriptor::TYPE_GROUP:
|
||||||
|
case FieldDescriptor::TYPE_MESSAGE:
|
||||||
|
case FieldDescriptor::TYPE_BYTES:
|
||||||
|
return "";
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetInnerType(const FieldDescriptor* field, bool packed = false)
|
||||||
|
{
|
||||||
|
switch (field->type()) {
|
||||||
|
case FieldDescriptor::TYPE_BOOL:
|
||||||
|
case FieldDescriptor::TYPE_ENUM:
|
||||||
|
case FieldDescriptor::TYPE_INT32:
|
||||||
|
case FieldDescriptor::TYPE_INT64:
|
||||||
|
case FieldDescriptor::TYPE_UINT32:
|
||||||
|
case FieldDescriptor::TYPE_UINT64:
|
||||||
|
return packed?"AddPackedVarint":"AddVarint";
|
||||||
|
case FieldDescriptor::TYPE_SINT32:
|
||||||
|
case FieldDescriptor::TYPE_SINT64:
|
||||||
|
return "AddZigZagVarint";
|
||||||
|
case FieldDescriptor::TYPE_FIXED64:
|
||||||
|
case FieldDescriptor::TYPE_SFIXED64:
|
||||||
|
case FieldDescriptor::TYPE_DOUBLE:
|
||||||
|
return packed?"AddPackedFixed":"AddFixed64";
|
||||||
|
case FieldDescriptor::TYPE_FIXED32:
|
||||||
|
case FieldDescriptor::TYPE_SFIXED32:
|
||||||
|
case FieldDescriptor::TYPE_FLOAT:
|
||||||
|
return packed?"AddPackedFixed":"AddFixed32";
|
||||||
|
case FieldDescriptor::TYPE_STRING:
|
||||||
|
case FieldDescriptor::TYPE_GROUP:
|
||||||
|
case FieldDescriptor::TYPE_MESSAGE:
|
||||||
|
case FieldDescriptor::TYPE_BYTES:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
void CollectContext()
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
void GenSurfix()
|
||||||
|
{
|
||||||
|
printer_->Print("} // namespace ProtoEncoder\n");
|
||||||
|
printer_->Print("} // namespace Profiler\n");
|
||||||
|
printer_->Print("} // namespace Developtools\n");
|
||||||
|
printer_->Print("} // namespace OHOS\n");
|
||||||
|
}
|
||||||
|
void SetPrinter(Printer* stub_h_printer)
|
||||||
|
{
|
||||||
|
printer_ = stub_h_printer;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::string fileName_ = "";
|
||||||
|
std::string baseName_ = "";
|
||||||
|
std::string packageName_ = "";
|
||||||
|
std::string headFileName_ = "";
|
||||||
|
//std::string header_ = "";
|
||||||
|
std::vector<std::string> namespaces_;
|
||||||
|
const FileDescriptor* const fileContent_;
|
||||||
|
std::vector<const Descriptor*> stack;
|
||||||
|
std::vector<const EnumDescriptor*> enums_;
|
||||||
|
Printer* printer_;
|
||||||
|
};
|
||||||
|
|
||||||
|
ProtoEncoderGenerator::ProtoEncoderGenerator() {}
|
||||||
|
|
||||||
|
ProtoEncoderGenerator::~ProtoEncoderGenerator() {}
|
||||||
|
|
||||||
|
bool ProtoEncoderGenerator::Generate(const google::protobuf::FileDescriptor* file,
|
||||||
|
const std::string& parameter,
|
||||||
|
google::protobuf::compiler::GeneratorContext* context,
|
||||||
|
std::string* error) const
|
||||||
|
{
|
||||||
|
auto pcsp = std::make_shared<OptGeneratorImpl>(file);
|
||||||
|
std::string base_name = pcsp->SetNames(file->name(), file->package());
|
||||||
|
std::unique_ptr<::google::protobuf::io::ZeroCopyOutputStream> header_output(context->Open(base_name +
|
||||||
|
".pbencoder.h"));
|
||||||
|
std::unique_ptr<::google::protobuf::io::ZeroCopyOutputStream> source_output(context->Open(base_name +
|
||||||
|
".pbencoder.cc"));
|
||||||
|
Printer h_printer(header_output.get(), '@');
|
||||||
|
pcsp->SetPrinter(&h_printer);
|
||||||
|
pcsp->GenHeader();
|
||||||
|
|
||||||
|
Printer cc_printer(source_output.get(), '@');
|
||||||
|
cc_printer.Print("// empty\n");
|
||||||
|
return true;
|
||||||
|
}
|
@ -58,6 +58,49 @@ typedef int (*PluginSessionStartCallback)(const uint8_t* configData, uint32_t co
|
|||||||
*/
|
*/
|
||||||
typedef int (*PluginReportResultCallback)(uint8_t* bufferData, uint32_t bufferSize);
|
typedef int (*PluginReportResultCallback)(uint8_t* bufferData, uint32_t bufferSize);
|
||||||
|
|
||||||
|
typedef struct RandomWriteCtx RandomWriteCtx;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get memory of the specified length
|
||||||
|
* @param size : The byte counts to be used
|
||||||
|
* @param memory : output current target memory pointer
|
||||||
|
* @param offset : output current offset relative to the head of writing
|
||||||
|
* @return : Return true for success and false for failure
|
||||||
|
*/
|
||||||
|
typedef bool (*GetMemoryFunc)(RandomWriteCtx* ctx, uint32_t size, uint8_t** memory, uint32_t* offset);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief seek to the specified offset for writing
|
||||||
|
* @param offset : offset relative to the head of writing
|
||||||
|
* @return : Return true for success and false for failure
|
||||||
|
*/
|
||||||
|
typedef bool (*SeekFunc)(RandomWriteCtx* ctx, uint32_t offset);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RandomWriteCtx : type definition, random write context.
|
||||||
|
*/
|
||||||
|
struct RandomWriteCtx {
|
||||||
|
/**
|
||||||
|
* get the memory and current offset.
|
||||||
|
*/
|
||||||
|
GetMemoryFunc getMemory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* seek for writing.
|
||||||
|
*/
|
||||||
|
SeekFunc seek;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief interface type of Plugin result reporting interface type
|
||||||
|
* The plugin reports the bytes data by randomWrite() directly,
|
||||||
|
* or constructor proto_encoder message by randomWrite(),
|
||||||
|
* the message class code is generated by protoc using proto file.
|
||||||
|
* @param randomWrite: random write context
|
||||||
|
* @return size that has been reproted, -1 when reprot faild.
|
||||||
|
*/
|
||||||
|
typedef int32_t (*PluginReportResultOptimizeCallback)(RandomWriteCtx* randomWrite);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief interface type of plugin session stop,
|
* @brief interface type of plugin session stop,
|
||||||
* Called when stopping plugin sessions
|
* Called when stopping plugin sessions
|
||||||
@ -84,7 +127,7 @@ typedef struct WriterStruct WriterStruct;
|
|||||||
* @param size : The byte counts in the data buffer
|
* @param size : The byte counts in the data buffer
|
||||||
* @return : Return the number of bytes written for success, and returns -1 for failure
|
* @return : Return the number of bytes written for success, and returns -1 for failure
|
||||||
*/
|
*/
|
||||||
typedef long (*WriteFuncPtr)(WriterStruct* writer, const void* data, size_t size);
|
typedef long (*WriteFuncPtr)(WriterStruct* writer, const char* data, size_t size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief flush : interface type
|
* @brief flush : interface type
|
||||||
@ -93,7 +136,23 @@ typedef long (*WriteFuncPtr)(WriterStruct* writer, const void* data, size_t size
|
|||||||
typedef bool (*FlushFuncPtr)(WriterStruct* writer);
|
typedef bool (*FlushFuncPtr)(WriterStruct* writer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WriterStruct : type definition, containing two function pointers.
|
* @brief StartReport interface type
|
||||||
|
* @return : Return RandomWriteCtx for success, null for failure
|
||||||
|
* The plugin reports the bytes data by RandomWriteCtx directly,
|
||||||
|
* or constructor proto_encoder message by RandomWriteCtx,
|
||||||
|
* the message class code is generated by protoc using proto file.
|
||||||
|
*/
|
||||||
|
typedef RandomWriteCtx* (*StartReportFuncPtr)(WriterStruct* writer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief FinishReport interface type
|
||||||
|
* @param size : The byte counts of data reported
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
typedef void (*FinishReportFuncPtr)(WriterStruct* writer, int32_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WriterStruct : type definition.
|
||||||
*/
|
*/
|
||||||
struct WriterStruct {
|
struct WriterStruct {
|
||||||
/**
|
/**
|
||||||
@ -105,6 +164,21 @@ struct WriterStruct {
|
|||||||
* flush function pointer,point to the actual flush function.
|
* flush function pointer,point to the actual flush function.
|
||||||
*/
|
*/
|
||||||
FlushFuncPtr flush;
|
FlushFuncPtr flush;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* startMessage function pointer, point to the actual startMessage function.
|
||||||
|
*/
|
||||||
|
StartReportFuncPtr startReport;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* finishMessage function pointer, point to the actual finishMessage function.
|
||||||
|
*/
|
||||||
|
FinishReportFuncPtr finishReport;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* data encoding method, true is protobuf, false is protoencoder, default is true for UT.
|
||||||
|
*/
|
||||||
|
bool protobufSerialize = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -149,6 +223,12 @@ struct PluginModuleCallbacks {
|
|||||||
* report plugin basic data
|
* report plugin basic data
|
||||||
*/
|
*/
|
||||||
PluginReportBasicDataCallback onReportBasicDataCallback = 0;
|
PluginReportBasicDataCallback onReportBasicDataCallback = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data reporting callback optimized and it is used to connect the
|
||||||
|
* polling reporting results of plugin management framework.
|
||||||
|
*/
|
||||||
|
PluginReportResultOptimizeCallback onPluginReportResultOptimize;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
38
proto_encoder/BUILD.gn
Executable file
38
proto_encoder/BUILD.gn
Executable file
@ -0,0 +1,38 @@
|
|||||||
|
# Copyright (C) 2023 Huawei Device Co., Ltd.
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
import("//build/ohos.gni")
|
||||||
|
import("//developtools/profiler/device/base/config.gni")
|
||||||
|
|
||||||
|
config("proto_encoder_config") {
|
||||||
|
include_dirs = [
|
||||||
|
"include",
|
||||||
|
"//third_party/bounds_checking_function/include",
|
||||||
|
"${OHOS_PROFILER_DIR}/interfaces/kits",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
ohos_source_set("proto_encoder_source") {
|
||||||
|
output_name = "proto_encoder"
|
||||||
|
sources = [
|
||||||
|
"src/base_message.cpp",
|
||||||
|
"src/varint_encode.cpp",
|
||||||
|
]
|
||||||
|
public_configs = [
|
||||||
|
":proto_encoder_config",
|
||||||
|
"${OHOS_PROFILER_DIR}/device/base:hiprofiler_test_config",
|
||||||
|
]
|
||||||
|
public_deps = [ "//third_party/bounds_checking_function:libsec_static" ]
|
||||||
|
subsystem_name = "${OHOS_PROFILER_SUBSYS_NAME}"
|
||||||
|
part_name = "${OHOS_PROFILER_PART_NAME}"
|
||||||
|
}
|
77
proto_encoder/example/example.proto
Executable file
77
proto_encoder/example/example.proto
Executable file
@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023 Huawei Device Co., Ltd.
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option optimize_for = LITE_RUNTIME;
|
||||||
|
|
||||||
|
enum NUM {
|
||||||
|
ZERO = 0;
|
||||||
|
ONE = 1;
|
||||||
|
TWO = 2;
|
||||||
|
THREE = 3;
|
||||||
|
FOUR = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SubMessage {
|
||||||
|
int32 vint_int32 = 1;
|
||||||
|
int64 vint_int64 = 2;
|
||||||
|
uint32 vint_uint32 = 3;
|
||||||
|
uint64 vint_uint64 = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ExampleMessage {
|
||||||
|
// https://developers.google.com/protocol-buffers/docs/encoding
|
||||||
|
// ID Name Used For
|
||||||
|
// 0 VARINT int32, int64, uint32, uint64, sint32, sint64, bool, enum
|
||||||
|
int32 vint_int32 = 1;
|
||||||
|
int64 vint_int64 = 2;
|
||||||
|
uint32 vint_uint32 = 3;
|
||||||
|
uint64 vint_uint64 = 4;
|
||||||
|
sint32 vint_sint32 = 5;
|
||||||
|
sint64 vint_sint64 = 6;
|
||||||
|
bool vint_bool = 7;
|
||||||
|
NUM vint_enum = 8;
|
||||||
|
|
||||||
|
// 1 I64 fixed64, sfixed64, double
|
||||||
|
fixed64 I64_fixed64 = 11;
|
||||||
|
sfixed64 I64_sfixed64 = 12;
|
||||||
|
double I64_double = 13;
|
||||||
|
|
||||||
|
// 2 LEN string, bytes, embedded messages, packed repeated fields
|
||||||
|
string LEN_string = 21;
|
||||||
|
bytes LEN_bytes = 22; // maybe need identified by protoC
|
||||||
|
SubMessage LEN_sub = 23;
|
||||||
|
// repeated sint32 repeated_signed_vint = 24; // repeated signed(zigzag) not supported in libprotobuf
|
||||||
|
repeated int32 LEN_repeated_packed_signed_vint = 25; // [packed = true]
|
||||||
|
repeated uint32 LEN_repeated_packed_unsigned_vint = 26; // [packed = true]
|
||||||
|
repeated fixed64 LEN_repeated_packed_fixed = 27; // [packed = true]
|
||||||
|
repeated SubMessage repeated_LEN_sub = 28;
|
||||||
|
|
||||||
|
// 5 I32 fixed32, sfixed32, float
|
||||||
|
fixed32 I32_fixed32 = 51;
|
||||||
|
sfixed32 I32_sfixed32 = 52;
|
||||||
|
float I32_float = 53;
|
||||||
|
|
||||||
|
// 6 oneof
|
||||||
|
oneof oneoffield {
|
||||||
|
fixed64 oneof_fixed64 = 61;
|
||||||
|
string oneof_string = 62;
|
||||||
|
SubMessage oneof_sub = 63;
|
||||||
|
}
|
||||||
|
|
||||||
|
repeated ExampleMessage repeated_Example = 100;
|
||||||
|
|
||||||
|
}
|
431
proto_encoder/include/base_message.h
Executable file
431
proto_encoder/include/base_message.h
Executable file
@ -0,0 +1,431 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023 Huawei Device Co., Ltd.
|
||||||
|
* 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 BASE_MESSAGE_H
|
||||||
|
#define BASE_MESSAGE_H
|
||||||
|
#include <functional>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "securec.h"
|
||||||
|
#include "varint_encode.h"
|
||||||
|
// for struct RandomWriteCtx
|
||||||
|
#include "plugin_module_api.h"
|
||||||
|
|
||||||
|
namespace OHOS {
|
||||||
|
namespace Developtools {
|
||||||
|
namespace Profiler {
|
||||||
|
namespace ProtoEncoder {
|
||||||
|
// https://developers.google.com/protocol-buffers/docs/encoding
|
||||||
|
// ID Name Used For
|
||||||
|
// 0 VARINT int32, int64, uint32, uint64, sint32, sint64, bool, enum
|
||||||
|
// 1 I64 fixed64, sfixed64, double
|
||||||
|
// 2 LEN string, bytes, embedded messages, packed repeated fields
|
||||||
|
// 3 SGROUP group start (deprecated)
|
||||||
|
// 4 EGROUP group end (deprecated)
|
||||||
|
// 5 I32 fixed32, sfixed32, float
|
||||||
|
enum ProtoMessageType : uint32_t {
|
||||||
|
VARINT = 0,
|
||||||
|
I64 = 1,
|
||||||
|
LEN = 2,
|
||||||
|
I32 = 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr uint8_t FIELDID_SHIFT = 3;
|
||||||
|
constexpr uint8_t SIZE_FIXED32 = 4;
|
||||||
|
constexpr uint8_t SIZE_FIXED64 = 8;
|
||||||
|
constexpr uint8_t SIZE_RESERVED_LEN = 4;
|
||||||
|
|
||||||
|
class MessagePool;
|
||||||
|
|
||||||
|
class BaseMessage {
|
||||||
|
public:
|
||||||
|
BaseMessage()
|
||||||
|
{
|
||||||
|
Reset(nullptr, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit BaseMessage(RandomWriteCtx* writeCtx, MessagePool* subMessageStack = nullptr)
|
||||||
|
{
|
||||||
|
Reset(writeCtx, subMessageStack);
|
||||||
|
}
|
||||||
|
|
||||||
|
~BaseMessage()
|
||||||
|
{
|
||||||
|
if (isWriting_) {
|
||||||
|
Finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reset(RandomWriteCtx* writeCtx = nullptr, MessagePool* subMessageStack = nullptr)
|
||||||
|
{
|
||||||
|
if (subMessage_ != nullptr) {
|
||||||
|
FinishSubMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
writeCtx_ = writeCtx;
|
||||||
|
subMessageStack_ = subMessageStack;
|
||||||
|
backfillOffset_ = 0;
|
||||||
|
if (writeCtx == nullptr) {
|
||||||
|
// can not write
|
||||||
|
isWriting_ = false;
|
||||||
|
size_ = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
size_ = 0;
|
||||||
|
isWriting_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return current size of message has wrote, < 0 if writing failed
|
||||||
|
inline int32_t Size()
|
||||||
|
{
|
||||||
|
return size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// finish message and return size of message, < 0 if writing failed
|
||||||
|
inline int32_t Finish()
|
||||||
|
{
|
||||||
|
if (!isWriting_) {
|
||||||
|
return size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subMessage_ != nullptr) {
|
||||||
|
FinishSubMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
isWriting_ = false;
|
||||||
|
return size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ID Name Used For
|
||||||
|
// 5 I32 fixed32, sfixed32, float
|
||||||
|
template<typename T>
|
||||||
|
void AddFixed32(uint32_t fieldId, T v)
|
||||||
|
{
|
||||||
|
static_assert(sizeof(T) == SIZE_FIXED32, "AddFixed32: T is not 32 bits");
|
||||||
|
if (subMessage_ != nullptr) {
|
||||||
|
FinishSubMessage();
|
||||||
|
}
|
||||||
|
if (!isWriting_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* fieldMemory = nullptr;
|
||||||
|
uint32_t fieldOffset = 0;
|
||||||
|
// max field size = varint(fieldId + type) + Fixed32(v)
|
||||||
|
if (!writeCtx_->getMemory(writeCtx_, VARINT_ENCODE_MAX_SIZE + SIZE_FIXED32,
|
||||||
|
&fieldMemory, &fieldOffset)) {
|
||||||
|
Drop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t tagSize = EncodeVarint(fieldMemory, (fieldId << FIELDID_SHIFT) | ProtoMessageType::I32);
|
||||||
|
// T must be little-endian
|
||||||
|
if (memcpy_s(fieldMemory + tagSize, SIZE_FIXED32, &v, SIZE_FIXED32) != EOK) {
|
||||||
|
Drop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeCtx_->seek(writeCtx_, fieldOffset + tagSize + SIZE_FIXED32);
|
||||||
|
size_ += tagSize + SIZE_FIXED32;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ID Name Used For
|
||||||
|
// 1 I64 fixed64, sfixed64, double
|
||||||
|
template<typename T>
|
||||||
|
void AddFixed64(uint32_t fieldId, T v)
|
||||||
|
{
|
||||||
|
static_assert(sizeof(T) == SIZE_FIXED64, "AddFixed64: T is not 64 bits");
|
||||||
|
if (subMessage_ != nullptr) {
|
||||||
|
FinishSubMessage();
|
||||||
|
}
|
||||||
|
if (!isWriting_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* fieldMemory = nullptr;
|
||||||
|
uint32_t fieldOffset = 0;
|
||||||
|
// max field size = varint(fieldId + type) + Fixed64(v)
|
||||||
|
if (!writeCtx_->getMemory(writeCtx_, VARINT_ENCODE_MAX_SIZE + SIZE_FIXED64,
|
||||||
|
&fieldMemory, &fieldOffset)) {
|
||||||
|
Drop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t tagSize = EncodeVarint(fieldMemory, (fieldId << FIELDID_SHIFT) | ProtoMessageType::I64);
|
||||||
|
// T must be little-endian
|
||||||
|
if (memcpy_s(fieldMemory + tagSize, SIZE_FIXED64, &v, SIZE_FIXED64) != EOK) {
|
||||||
|
Drop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeCtx_->seek(writeCtx_, fieldOffset + tagSize + SIZE_FIXED64);
|
||||||
|
size_ += tagSize + SIZE_FIXED64;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ID Name Used For(unsigned and 'intN' varint)
|
||||||
|
// 0 VARINT int32, int64, uint32, uint64, bool, enum
|
||||||
|
template<typename T>
|
||||||
|
void AddVarint(uint32_t fieldId, T v)
|
||||||
|
{
|
||||||
|
if (subMessage_ != nullptr) {
|
||||||
|
FinishSubMessage();
|
||||||
|
}
|
||||||
|
if (!isWriting_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* fieldMemory = nullptr;
|
||||||
|
uint32_t fieldOffset = 0;
|
||||||
|
// max field size = varint(fieldId + type) + varint(v)
|
||||||
|
if (!writeCtx_->getMemory(writeCtx_, VARINT_ENCODE_MAX_SIZE + VARINT_ENCODE_MAX_SIZE,
|
||||||
|
&fieldMemory, &fieldOffset)) {
|
||||||
|
Drop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t fieldSize = EncodeVarint(fieldMemory, (fieldId << FIELDID_SHIFT) | ProtoMessageType::VARINT);
|
||||||
|
fieldSize += EncodeVarint(fieldMemory + fieldSize, v);
|
||||||
|
writeCtx_->seek(writeCtx_, fieldOffset + fieldSize);
|
||||||
|
size_ += fieldSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ID Name Used For('sintN' varint, ZigZag encode)
|
||||||
|
// 0 VARINT sint32, sint64
|
||||||
|
template<typename T>
|
||||||
|
void AddZigZagVarint(uint32_t fieldId, T v)
|
||||||
|
{
|
||||||
|
if (subMessage_ != nullptr) {
|
||||||
|
FinishSubMessage();
|
||||||
|
}
|
||||||
|
if (!isWriting_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* fieldMemory = nullptr;
|
||||||
|
uint32_t fieldOffset = 0;
|
||||||
|
// max field size = varint(fieldId + type) + varint(v)
|
||||||
|
if (!writeCtx_->getMemory(writeCtx_, VARINT_ENCODE_MAX_SIZE + VARINT_ENCODE_MAX_SIZE,
|
||||||
|
&fieldMemory, &fieldOffset)) {
|
||||||
|
Drop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t fieldSize = EncodeVarint(fieldMemory, (fieldId << FIELDID_SHIFT) | ProtoMessageType::VARINT);
|
||||||
|
fieldSize += EncodeZigZagVarint(fieldMemory + fieldSize, v);
|
||||||
|
writeCtx_->seek(writeCtx_, fieldOffset + fieldSize);
|
||||||
|
size_ += fieldSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ID Name Used For
|
||||||
|
// 2 LEN bytes, string
|
||||||
|
void AddBytes(uint32_t fieldId, const void* data, uint32_t dataSize);
|
||||||
|
|
||||||
|
// add customize data, return RandomWriteCtx pointer, caller implement:
|
||||||
|
// RandomWriteCtx* writeCtx = StartAddBytes();
|
||||||
|
// 1, write data by writeCtx->write() directly;
|
||||||
|
// 2, constructor Message object by writeCtx, and fill data by method of Message
|
||||||
|
// FinishAddBytes(size);
|
||||||
|
RandomWriteCtx* StartAddBytes(uint32_t fieldId);
|
||||||
|
void FinishAddBytes(int32_t size);
|
||||||
|
|
||||||
|
// get data by getData(), implement in getData() function:
|
||||||
|
// 1, write data by randomWriteCtx->write() directly;
|
||||||
|
// 2, constructor Message object by randomWriteCtx, and fill data by method of Message
|
||||||
|
using GetDataCallback = std::function<int32_t(RandomWriteCtx* randomWriteCtx)>;
|
||||||
|
void AddBytesByCallBack(uint32_t fieldId, GetDataCallback getData);
|
||||||
|
|
||||||
|
// ID Name Used For
|
||||||
|
// 2 LEN embedded messages
|
||||||
|
template<typename T>
|
||||||
|
T* AddSubMessage(uint32_t fieldId)
|
||||||
|
{
|
||||||
|
static_assert(std::is_base_of<BaseMessage, T>::value,
|
||||||
|
"SubMessage must be a derived class of BaseMessage");
|
||||||
|
static_assert(sizeof(T) == sizeof(BaseMessage),
|
||||||
|
"Size of SubMessage class must be equal to BaseMessage");
|
||||||
|
if (subMessage_ != nullptr) {
|
||||||
|
FinishSubMessage();
|
||||||
|
}
|
||||||
|
if (!isWriting_) {
|
||||||
|
// return message self pointer for business,
|
||||||
|
// business can call message->set_XXX() without checking message is nullptr
|
||||||
|
return static_cast<T*>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* fieldMemory = nullptr;
|
||||||
|
// varint(fieldId) + varint(len)
|
||||||
|
if (!writeCtx_->getMemory(writeCtx_, VARINT_ENCODE_MAX_SIZE + SIZE_RESERVED_LEN,
|
||||||
|
&fieldMemory, &backfillOffset_)) {
|
||||||
|
Drop();
|
||||||
|
return static_cast<T*>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t tagSize = EncodeVarint(fieldMemory, (fieldId << FIELDID_SHIFT) | ProtoMessageType::LEN);
|
||||||
|
backfillOffset_ += tagSize;
|
||||||
|
size_ += tagSize;
|
||||||
|
// reserve length space
|
||||||
|
writeCtx_->seek(writeCtx_, backfillOffset_ + SIZE_RESERVED_LEN);
|
||||||
|
if (!AllocateSubMessage()) {
|
||||||
|
Drop();
|
||||||
|
return static_cast<T*>(this);
|
||||||
|
}
|
||||||
|
return static_cast<T*>(subMessage_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ID Name Used For
|
||||||
|
// 2 LEN packed repeated fields(unsigned and 'intN' varint)
|
||||||
|
template<typename T>
|
||||||
|
inline void AddPackedVarint(uint32_t fieldId, const T* array, uint32_t arrayCount)
|
||||||
|
{
|
||||||
|
if (arrayCount == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (subMessage_ != nullptr) {
|
||||||
|
FinishSubMessage();
|
||||||
|
}
|
||||||
|
if (!isWriting_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t maxLen = 0;
|
||||||
|
uint32_t lenSize = GetPackedVarintLenSize(arrayCount, sizeof(T), maxLen);
|
||||||
|
if (lenSize == 0) {
|
||||||
|
Drop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* fieldMemory = nullptr;
|
||||||
|
uint32_t fieldOffset = 0;
|
||||||
|
// varint(fieldId) + lenSize + maxLen
|
||||||
|
if (!writeCtx_->getMemory(writeCtx_, VARINT_ENCODE_MAX_SIZE + lenSize + maxLen,
|
||||||
|
&fieldMemory, &fieldOffset)) {
|
||||||
|
Drop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t tagSize = EncodeVarint(fieldMemory, (fieldId << FIELDID_SHIFT) | ProtoMessageType::LEN);
|
||||||
|
// encode array of varint first
|
||||||
|
uint32_t dataSize = 0;
|
||||||
|
uint8_t* pData = fieldMemory + tagSize + lenSize;
|
||||||
|
for (uint32_t i = 0; i < arrayCount; i++) {
|
||||||
|
dataSize += EncodeVarint(pData + dataSize, *array);
|
||||||
|
array++;
|
||||||
|
}
|
||||||
|
// varint(Length)
|
||||||
|
EncodeVarintPadding(fieldMemory + tagSize, dataSize, lenSize);
|
||||||
|
size_ += tagSize + lenSize + dataSize;
|
||||||
|
// seek to tail
|
||||||
|
writeCtx_->seek(writeCtx_, fieldOffset + tagSize + lenSize + dataSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ID Name Used For
|
||||||
|
// 2 LEN packed repeated fields(I32 and I64)
|
||||||
|
template<typename T>
|
||||||
|
inline void AddPackedFixed(uint32_t fieldId, const T* array, uint32_t arrayCount)
|
||||||
|
{
|
||||||
|
static_assert(sizeof(T) == SIZE_FIXED32 || sizeof(T) == SIZE_FIXED64,
|
||||||
|
"AddPackedFixed: T is not 32 or 64 bits");
|
||||||
|
if (arrayCount == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (subMessage_ != nullptr) {
|
||||||
|
FinishSubMessage();
|
||||||
|
}
|
||||||
|
if (!isWriting_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t dataSize = arrayCount * sizeof(T);
|
||||||
|
uint8_t* fieldMemory = nullptr;
|
||||||
|
uint32_t fieldOffset = 0;
|
||||||
|
// varint(fieldId) + varint(dataSize) + dataSize
|
||||||
|
if (!writeCtx_->getMemory(writeCtx_, VARINT_ENCODE_MAX_SIZE + SIZE_RESERVED_LEN + dataSize,
|
||||||
|
&fieldMemory, &fieldOffset)) {
|
||||||
|
Drop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t tagSize = EncodeVarint(fieldMemory, (fieldId << FIELDID_SHIFT) | ProtoMessageType::LEN);
|
||||||
|
tagSize += EncodeVarint(fieldMemory + tagSize, dataSize);
|
||||||
|
if (memcpy_s(fieldMemory + tagSize, dataSize, array, dataSize) != EOK) {
|
||||||
|
Drop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_ += tagSize + dataSize;
|
||||||
|
// seek to tail
|
||||||
|
writeCtx_->seek(writeCtx_, fieldOffset + tagSize + dataSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
RandomWriteCtx* writeCtx_ = nullptr;
|
||||||
|
MessagePool* subMessageStack_ = nullptr;
|
||||||
|
BaseMessage* subMessage_ = nullptr;
|
||||||
|
int32_t size_ = 0;
|
||||||
|
uint32_t backfillOffset_ = 0;
|
||||||
|
bool isWriting_ = true; // false when Finish() or Drop()
|
||||||
|
|
||||||
|
bool AllocateSubMessage();
|
||||||
|
void FinishSubMessage();
|
||||||
|
|
||||||
|
inline void Drop()
|
||||||
|
{
|
||||||
|
isWriting_ = false;
|
||||||
|
size_ = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr uint32_t DEFAULT_SUBMESSAGE_DEPTH = 10;
|
||||||
|
// MessagePool is cache of the BaseMessage's submessage, avoid new and delete multiple times
|
||||||
|
// ONE BaseMessage corresponds to ONE MessagePool
|
||||||
|
class MessagePool {
|
||||||
|
public:
|
||||||
|
explicit MessagePool(uint32_t depth = DEFAULT_SUBMESSAGE_DEPTH)
|
||||||
|
{
|
||||||
|
Reset(depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Reset(uint32_t depth = DEFAULT_SUBMESSAGE_DEPTH)
|
||||||
|
{
|
||||||
|
messageCache_.resize(depth);
|
||||||
|
cursor_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseMessage* Get()
|
||||||
|
{
|
||||||
|
if (cursor_ < messageCache_.size()) {
|
||||||
|
return &messageCache_[cursor_++];
|
||||||
|
} else {
|
||||||
|
auto& msg = messageCache_.emplace_back();
|
||||||
|
cursor_++;
|
||||||
|
return &msg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Release()
|
||||||
|
{
|
||||||
|
if (cursor_ > 0) {
|
||||||
|
cursor_--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::vector<BaseMessage> messageCache_;
|
||||||
|
uint32_t cursor_ = 0;
|
||||||
|
};
|
||||||
|
} // namespace ProtoEncoder
|
||||||
|
} // namespace Profiler
|
||||||
|
} // namespace Developtools
|
||||||
|
} // namespace OHOS
|
||||||
|
#endif // BASE_MESSAGE_H
|
117
proto_encoder/include/varint_encode.h
Executable file
117
proto_encoder/include/varint_encode.h
Executable file
@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023 Huawei Device Co., Ltd.
|
||||||
|
* 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 VARINT_ENCODE_H
|
||||||
|
#define VARINT_ENCODE_H
|
||||||
|
#include <cinttypes>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace OHOS {
|
||||||
|
namespace Developtools {
|
||||||
|
namespace Profiler {
|
||||||
|
namespace ProtoEncoder {
|
||||||
|
constexpr uint32_t VARINT32_SIZE = 4;
|
||||||
|
constexpr uint32_t VARINT32_ENCODE_SIZE = 5;
|
||||||
|
constexpr uint32_t VARINT64_SIZE = 8;
|
||||||
|
constexpr uint32_t VARINT64_ENCODE_SIZE = 10;
|
||||||
|
constexpr uint32_t VARINT_ENCODE_MAX_SIZE = VARINT64_ENCODE_SIZE;
|
||||||
|
|
||||||
|
constexpr uint32_t VARINT_MAX_1BYTE = (1u << (7 * 1)) - 1;
|
||||||
|
constexpr uint32_t VARINT_MAX_2BYTE = (1u << (7 * 2)) - 1;
|
||||||
|
constexpr uint32_t VARINT_MAX_3BYTE = (1u << (7 * 3)) - 1;
|
||||||
|
constexpr uint32_t VARINT_MAX_4BYTE = (1u << (7 * 4)) - 1;
|
||||||
|
|
||||||
|
constexpr uint8_t VARINT_PAYLOAD_BITS = 7;
|
||||||
|
constexpr uint8_t VARINT_MASK_PAYLOAD = 0x7F;
|
||||||
|
constexpr uint8_t VARINT_MASK_MSB = 0x80;
|
||||||
|
|
||||||
|
inline uint32_t GetPackedVarintLenSize(uint32_t itemCount, uint32_t itemSize, uint32_t& len)
|
||||||
|
{
|
||||||
|
len = itemCount;
|
||||||
|
if (itemSize == VARINT32_SIZE) {
|
||||||
|
len = itemCount * VARINT32_ENCODE_SIZE;
|
||||||
|
} else if (itemSize == VARINT64_SIZE) {
|
||||||
|
len = itemCount * VARINT64_ENCODE_SIZE;
|
||||||
|
} // else bool is 1 byte
|
||||||
|
|
||||||
|
const uint32_t one = 1;
|
||||||
|
const uint32_t two = 2;
|
||||||
|
const uint32_t three = 3;
|
||||||
|
const uint32_t four = 4;
|
||||||
|
if (len <= VARINT_MAX_1BYTE) {
|
||||||
|
return one;
|
||||||
|
} else if (len <= VARINT_MAX_2BYTE) {
|
||||||
|
return two;
|
||||||
|
} else if (len <= VARINT_MAX_3BYTE) {
|
||||||
|
return three;
|
||||||
|
} else if (len <= VARINT_MAX_4BYTE) {
|
||||||
|
return four;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; // illegal, too large
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline typename std::make_unsigned<T>::type EncodeZigZag(T v)
|
||||||
|
{
|
||||||
|
if (v >= 0) {
|
||||||
|
return ((typename std::make_unsigned<T>::type)(v) << 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((typename std::make_unsigned<T>::type)(~v) << 1) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline uint32_t EncodeVarint(uint8_t* buf, T v)
|
||||||
|
{
|
||||||
|
// https://developers.google.com/protocol-buffers/docs/encoding
|
||||||
|
// Unsigned Integers and Signed Integers(intN)
|
||||||
|
uint64_t value = (uint64_t)v;
|
||||||
|
uint32_t size = 0;
|
||||||
|
while (value > (uint64_t)VARINT_MAX_1BYTE) {
|
||||||
|
buf[size] = (VARINT_MASK_PAYLOAD & value) | VARINT_MASK_MSB;
|
||||||
|
size++;
|
||||||
|
value >>= VARINT_PAYLOAD_BITS;
|
||||||
|
}
|
||||||
|
buf[size] = (VARINT_MASK_PAYLOAD & value);
|
||||||
|
size++;
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline uint32_t EncodeZigZagVarint(uint8_t* buf, T v)
|
||||||
|
{
|
||||||
|
return EncodeVarint(buf, EncodeZigZag(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline void EncodeVarintPadding(uint8_t* buf, T v, uint32_t paddingSize)
|
||||||
|
{
|
||||||
|
uint32_t size = 0;
|
||||||
|
paddingSize--;
|
||||||
|
while (size < paddingSize) {
|
||||||
|
buf[size] = (VARINT_MASK_PAYLOAD & v) | VARINT_MASK_MSB;
|
||||||
|
size++;
|
||||||
|
v >>= VARINT_PAYLOAD_BITS;
|
||||||
|
}
|
||||||
|
buf[size] = (VARINT_MASK_PAYLOAD & v);
|
||||||
|
}
|
||||||
|
} // namespace ProtoEncoder
|
||||||
|
} // namespace Profiler
|
||||||
|
} // namespace Developtools
|
||||||
|
} // namespace OHOS
|
||||||
|
#endif // VARINT_ENCODE_H
|
222
proto_encoder/src/base_message.cpp
Executable file
222
proto_encoder/src/base_message.cpp
Executable file
@ -0,0 +1,222 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023 Huawei Device Co., Ltd.
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
#include "base_message.h"
|
||||||
|
|
||||||
|
#include "securec.h"
|
||||||
|
#include "varint_encode.h"
|
||||||
|
|
||||||
|
namespace OHOS {
|
||||||
|
namespace Developtools {
|
||||||
|
namespace Profiler {
|
||||||
|
namespace ProtoEncoder {
|
||||||
|
bool BaseMessage::AllocateSubMessage()
|
||||||
|
{
|
||||||
|
if (subMessageStack_ == nullptr) {
|
||||||
|
subMessage_ = new (std::nothrow) BaseMessage(writeCtx_);
|
||||||
|
} else {
|
||||||
|
subMessage_ = subMessageStack_->Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subMessage_ == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
subMessage_->Reset(writeCtx_, subMessageStack_);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BaseMessage::FinishSubMessage()
|
||||||
|
{
|
||||||
|
int32_t subSize = subMessage_->Finish();
|
||||||
|
if (subMessageStack_ == nullptr) {
|
||||||
|
delete subMessage_;
|
||||||
|
} else {
|
||||||
|
subMessageStack_->Release();
|
||||||
|
}
|
||||||
|
subMessage_ = nullptr;
|
||||||
|
if (subSize < 0) {
|
||||||
|
Drop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* fieldMemory = nullptr;
|
||||||
|
// backfill length
|
||||||
|
writeCtx_->seek(writeCtx_, backfillOffset_);
|
||||||
|
if (!writeCtx_->getMemory(writeCtx_, SIZE_RESERVED_LEN,
|
||||||
|
&fieldMemory, &backfillOffset_)) {
|
||||||
|
Drop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subSize == 0) {
|
||||||
|
// reduce the size
|
||||||
|
*fieldMemory = 0;
|
||||||
|
writeCtx_->seek(writeCtx_, backfillOffset_ + 1);
|
||||||
|
size_++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// varint(Length)
|
||||||
|
EncodeVarintPadding(fieldMemory, subSize, SIZE_RESERVED_LEN);
|
||||||
|
size_ += SIZE_RESERVED_LEN + subSize;
|
||||||
|
// seek to tail
|
||||||
|
writeCtx_->seek(writeCtx_, backfillOffset_ + SIZE_RESERVED_LEN + subSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BaseMessage::AddBytes(uint32_t fieldId, const void* data, uint32_t dataSize)
|
||||||
|
{
|
||||||
|
if (subMessage_ != nullptr) {
|
||||||
|
FinishSubMessage();
|
||||||
|
}
|
||||||
|
if (!isWriting_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* fieldMemory = nullptr;
|
||||||
|
uint32_t fieldOffset = 0;
|
||||||
|
// max field size = varint(fieldId + type) + varint(dataSize) + dataSize
|
||||||
|
if (!writeCtx_->getMemory(writeCtx_, VARINT_ENCODE_MAX_SIZE + SIZE_RESERVED_LEN + dataSize,
|
||||||
|
&fieldMemory, &fieldOffset)) {
|
||||||
|
Drop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t fieldSize = EncodeVarint(fieldMemory, (fieldId << FIELDID_SHIFT) | ProtoMessageType::LEN);
|
||||||
|
fieldSize += EncodeVarint(fieldMemory + fieldSize, dataSize);
|
||||||
|
if (dataSize != 0) {
|
||||||
|
if (memcpy_s(fieldMemory + fieldSize, dataSize, data, dataSize) != EOK) {
|
||||||
|
Drop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fieldSize += dataSize;
|
||||||
|
size_ += fieldSize;
|
||||||
|
// seek to tail
|
||||||
|
writeCtx_->seek(writeCtx_, fieldOffset + fieldSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
RandomWriteCtx* BaseMessage::StartAddBytes(uint32_t fieldId)
|
||||||
|
{
|
||||||
|
if (subMessage_ != nullptr) {
|
||||||
|
FinishSubMessage();
|
||||||
|
}
|
||||||
|
if (!isWriting_) {
|
||||||
|
// finished or dropped
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* fieldMemory = nullptr;
|
||||||
|
// max field size = varint(fieldId + type) + varint(len)
|
||||||
|
if (!writeCtx_->getMemory(writeCtx_, VARINT_ENCODE_MAX_SIZE + SIZE_RESERVED_LEN,
|
||||||
|
&fieldMemory, &backfillOffset_)) {
|
||||||
|
Drop();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t tagSize = EncodeVarint(fieldMemory, (fieldId << FIELDID_SHIFT) | ProtoMessageType::LEN);
|
||||||
|
backfillOffset_ += tagSize;
|
||||||
|
size_ += tagSize;
|
||||||
|
// reserve length space
|
||||||
|
writeCtx_->seek(writeCtx_, backfillOffset_ + SIZE_RESERVED_LEN);
|
||||||
|
return writeCtx_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BaseMessage::FinishAddBytes(int32_t size)
|
||||||
|
{
|
||||||
|
if (size < 0) {
|
||||||
|
Drop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* fieldMemory = nullptr;
|
||||||
|
// backfill length
|
||||||
|
writeCtx_->seek(writeCtx_, backfillOffset_);
|
||||||
|
if (!writeCtx_->getMemory(writeCtx_, SIZE_RESERVED_LEN, &fieldMemory, &backfillOffset_)) {
|
||||||
|
Drop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size == 0) {
|
||||||
|
// reduce the size
|
||||||
|
*fieldMemory = 0;
|
||||||
|
writeCtx_->seek(writeCtx_, backfillOffset_ + 1);
|
||||||
|
size_++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// varint(Length)
|
||||||
|
EncodeVarintPadding(fieldMemory, size, SIZE_RESERVED_LEN);
|
||||||
|
size_ += SIZE_RESERVED_LEN + size;
|
||||||
|
// seek to tail
|
||||||
|
writeCtx_->seek(writeCtx_, backfillOffset_ + SIZE_RESERVED_LEN + size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BaseMessage::AddBytesByCallBack(uint32_t fieldId, GetDataCallback getData)
|
||||||
|
{
|
||||||
|
if (!getData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subMessage_ != nullptr) {
|
||||||
|
FinishSubMessage();
|
||||||
|
}
|
||||||
|
if (!isWriting_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* fieldMemory = nullptr;
|
||||||
|
uint32_t fieldOffset = 0;
|
||||||
|
// max field size = varint(fieldId + type) + varint(len)
|
||||||
|
if (!writeCtx_->getMemory(writeCtx_, VARINT_ENCODE_MAX_SIZE + SIZE_RESERVED_LEN,
|
||||||
|
&fieldMemory, &fieldOffset)) {
|
||||||
|
Drop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t tagSize = EncodeVarint(fieldMemory, (fieldId << FIELDID_SHIFT) | ProtoMessageType::LEN);
|
||||||
|
fieldOffset += tagSize;
|
||||||
|
size_ += tagSize;
|
||||||
|
// reserve length space
|
||||||
|
writeCtx_->seek(writeCtx_, fieldOffset + SIZE_RESERVED_LEN);
|
||||||
|
|
||||||
|
int32_t dataSize = getData(writeCtx_);
|
||||||
|
if (dataSize < 0) {
|
||||||
|
Drop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// backfill length
|
||||||
|
writeCtx_->seek(writeCtx_, fieldOffset);
|
||||||
|
if (!writeCtx_->getMemory(writeCtx_, SIZE_RESERVED_LEN, &fieldMemory, &fieldOffset)) {
|
||||||
|
Drop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataSize == 0) {
|
||||||
|
// reduce the size
|
||||||
|
*fieldMemory = 0;
|
||||||
|
writeCtx_->seek(writeCtx_, fieldOffset + 1);
|
||||||
|
size_++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EncodeVarintPadding(fieldMemory, dataSize, SIZE_RESERVED_LEN);
|
||||||
|
size_ += SIZE_RESERVED_LEN + dataSize;
|
||||||
|
// seek to tail
|
||||||
|
writeCtx_->seek(writeCtx_, fieldOffset + SIZE_RESERVED_LEN + dataSize);
|
||||||
|
}
|
||||||
|
} // namespace ProtoEncoder
|
||||||
|
} // namespace Profiler
|
||||||
|
} // namespace Developtools
|
||||||
|
} // namespace OHOS
|
24
proto_encoder/src/varint_encode.cpp
Executable file
24
proto_encoder/src/varint_encode.cpp
Executable file
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023 Huawei Device Co., Ltd.
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
#include "varint_encode.h"
|
||||||
|
|
||||||
|
namespace OHOS {
|
||||||
|
namespace Developtools {
|
||||||
|
namespace Profiler {
|
||||||
|
namespace ProtoEncoder {
|
||||||
|
} // namespace ProtoEncoder
|
||||||
|
} // namespace Profiler
|
||||||
|
} // namespace Developtools
|
||||||
|
} // namespace OHOS
|
101
proto_encoder/test/BUILD.gn
Executable file
101
proto_encoder/test/BUILD.gn
Executable file
@ -0,0 +1,101 @@
|
|||||||
|
# Copyright (c) 2023 Huawei Device Co., Ltd.
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
import("//build/test.gni")
|
||||||
|
import("//developtools/profiler/device/base/config.gni")
|
||||||
|
import("//developtools/profiler/protos/protos.gni")
|
||||||
|
|
||||||
|
module_output_path = "${OHOS_PROFILER_TEST_MODULE_OUTPUT_PATH}/proto_encoder"
|
||||||
|
config("module_private_config") {
|
||||||
|
visibility = [ ":*" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
protos_dir = "../example/"
|
||||||
|
protos_root_dir = rebase_path(protos_dir, root_build_dir)
|
||||||
|
proto_out_dir = "$root_gen_dir/cpp/" + rebase_path(protos_dir, "//")
|
||||||
|
proto_rel_out_dir = rebase_path(proto_out_dir, root_build_dir)
|
||||||
|
|
||||||
|
protos_defines = [ "$protos_dir" + "example.proto" ]
|
||||||
|
example_codegen_all = []
|
||||||
|
foreach(proto, protos_defines) {
|
||||||
|
name = get_path_info(proto, "name")
|
||||||
|
example_codegen_all += [
|
||||||
|
"$proto_out_dir/$name.pb.h",
|
||||||
|
"$proto_out_dir/$name.pb.cc",
|
||||||
|
"$proto_out_dir/$name.pbencoder.h",
|
||||||
|
"$proto_out_dir/$name.pbencoder.cc",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
action("proto_gen_source") {
|
||||||
|
script = "${OHOS_PROFILER_DIR}/build/protoc.sh"
|
||||||
|
sources = protos_defines
|
||||||
|
outputs = example_codegen_all
|
||||||
|
args = [
|
||||||
|
"$libc_dir_proto",
|
||||||
|
"$root_output_dir_proto",
|
||||||
|
"$proto_rel_out_dir",
|
||||||
|
"--cpp_out",
|
||||||
|
"$proto_rel_out_dir",
|
||||||
|
"--proto_path",
|
||||||
|
"$protos_root_dir",
|
||||||
|
]
|
||||||
|
args += rebase_path(sources, root_build_dir)
|
||||||
|
deps = [
|
||||||
|
"${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})",
|
||||||
|
"${OHOS_PROFILER_DIR}/device/services/ipc:protoencoder_plugin(${host_toolchain})",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ohos_source_set("proto_example_source") {
|
||||||
|
deps = [
|
||||||
|
":proto_gen_source",
|
||||||
|
]
|
||||||
|
include_dirs = [ "$proto_out_dir" ]
|
||||||
|
sources = example_codegen_all
|
||||||
|
public_deps = [
|
||||||
|
"${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf",
|
||||||
|
"${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite",
|
||||||
|
]
|
||||||
|
subsystem_name = "${OHOS_PROFILER_SUBSYS_NAME}"
|
||||||
|
part_name = "${OHOS_PROFILER_PART_NAME}"
|
||||||
|
}
|
||||||
|
|
||||||
|
ohos_unittest("proto_encoder_ut") {
|
||||||
|
module_out_path = module_output_path
|
||||||
|
sources = [
|
||||||
|
"unittest/base_message_unittest.cpp",
|
||||||
|
"unittest/varint_encode_unittest.cpp",
|
||||||
|
]
|
||||||
|
deps = [
|
||||||
|
":proto_example_source",
|
||||||
|
"../:proto_encoder_source",
|
||||||
|
"//third_party/googletest:gtest_main",
|
||||||
|
]
|
||||||
|
include_dirs = [
|
||||||
|
"../include",
|
||||||
|
"../example",
|
||||||
|
"//third_party/googletest/googletest/include/gtest",
|
||||||
|
"$proto_out_dir",
|
||||||
|
]
|
||||||
|
|
||||||
|
configs = [ ":module_private_config" ]
|
||||||
|
subsystem_name = "${OHOS_PROFILER_SUBSYS_NAME}"
|
||||||
|
part_name = "${OHOS_PROFILER_PART_NAME}"
|
||||||
|
}
|
||||||
|
|
||||||
|
group("unittest") {
|
||||||
|
testonly = true
|
||||||
|
deps = [ ":proto_encoder_ut" ]
|
||||||
|
}
|
1639
proto_encoder/test/unittest/base_message_unittest.cpp
Executable file
1639
proto_encoder/test/unittest/base_message_unittest.cpp
Executable file
File diff suppressed because it is too large
Load Diff
319
proto_encoder/test/unittest/varint_encode_unittest.cpp
Executable file
319
proto_encoder/test/unittest/varint_encode_unittest.cpp
Executable file
@ -0,0 +1,319 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021 Huawei Device Co., Ltd.
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <limits>
|
||||||
|
#include <vector>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "varint_encode.h"
|
||||||
|
|
||||||
|
namespace OHOS {
|
||||||
|
namespace Developtools {
|
||||||
|
namespace Profiler {
|
||||||
|
using namespace testing::ext;
|
||||||
|
using namespace ProtoEncoder;
|
||||||
|
|
||||||
|
class VarintEncodeUnittest : public ::testing::Test {
|
||||||
|
public:
|
||||||
|
static void SetUpTestCase() {};
|
||||||
|
static void TearDownTestCase() {};
|
||||||
|
|
||||||
|
void SetUp() {};
|
||||||
|
void TearDown() {};
|
||||||
|
|
||||||
|
const uint32_t two = 2;
|
||||||
|
const uint32_t three = 3;
|
||||||
|
const uint32_t four = 4;
|
||||||
|
};
|
||||||
|
|
||||||
|
HWTEST_F(VarintEncodeUnittest, GetPackedVarintLenSize, TestSize.Level1)
|
||||||
|
{
|
||||||
|
uint32_t len = 0;
|
||||||
|
uint32_t itemCount = 0;
|
||||||
|
uint32_t itemSize = sizeof(char);
|
||||||
|
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), (uint32_t)1);
|
||||||
|
EXPECT_EQ(len, (uint32_t)0);
|
||||||
|
|
||||||
|
itemSize = sizeof(int32_t);
|
||||||
|
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), (uint32_t)1);
|
||||||
|
EXPECT_EQ(len, itemCount * itemSize);
|
||||||
|
|
||||||
|
itemSize = sizeof(int64_t);
|
||||||
|
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), (uint32_t)1);
|
||||||
|
EXPECT_EQ(len, itemCount * itemSize);
|
||||||
|
|
||||||
|
itemSize = sizeof(char);
|
||||||
|
itemCount = VARINT_MAX_1BYTE;
|
||||||
|
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), (uint32_t)1);
|
||||||
|
EXPECT_EQ(len, itemCount * itemSize);
|
||||||
|
|
||||||
|
itemCount++;
|
||||||
|
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), two);
|
||||||
|
EXPECT_EQ(len, itemCount * itemSize);
|
||||||
|
|
||||||
|
itemCount = VARINT_MAX_2BYTE;
|
||||||
|
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), two);
|
||||||
|
EXPECT_EQ(len, itemCount * itemSize);
|
||||||
|
|
||||||
|
itemCount++;
|
||||||
|
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), three);
|
||||||
|
EXPECT_EQ(len, itemCount * itemSize);
|
||||||
|
|
||||||
|
itemCount = VARINT_MAX_3BYTE;
|
||||||
|
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), three);
|
||||||
|
EXPECT_EQ(len, itemCount * itemSize);
|
||||||
|
|
||||||
|
itemCount++;
|
||||||
|
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), four);
|
||||||
|
EXPECT_EQ(len, itemCount * itemSize);
|
||||||
|
|
||||||
|
itemCount = VARINT_MAX_4BYTE;
|
||||||
|
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), four);
|
||||||
|
EXPECT_EQ(len, itemCount * itemSize);
|
||||||
|
|
||||||
|
itemCount++;
|
||||||
|
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), (uint32_t)0);
|
||||||
|
EXPECT_EQ(len, itemCount * itemSize);
|
||||||
|
|
||||||
|
itemSize = sizeof(int32_t);
|
||||||
|
itemCount = VARINT_MAX_1BYTE / (itemSize + 1);
|
||||||
|
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), (uint32_t)1);
|
||||||
|
EXPECT_EQ(len, itemCount * (itemSize + 1));
|
||||||
|
|
||||||
|
itemCount++;
|
||||||
|
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), two);
|
||||||
|
EXPECT_EQ(len, itemCount * (itemSize + 1));
|
||||||
|
|
||||||
|
itemCount = VARINT_MAX_2BYTE / (itemSize + 1);
|
||||||
|
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), two);
|
||||||
|
EXPECT_EQ(len, itemCount * (itemSize + 1));
|
||||||
|
|
||||||
|
itemCount++;
|
||||||
|
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), three);
|
||||||
|
EXPECT_EQ(len, itemCount * (itemSize + 1));
|
||||||
|
|
||||||
|
itemCount = VARINT_MAX_3BYTE / (itemSize + 1);
|
||||||
|
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), three);
|
||||||
|
EXPECT_EQ(len, itemCount * (itemSize + 1));
|
||||||
|
|
||||||
|
itemCount++;
|
||||||
|
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), four);
|
||||||
|
EXPECT_EQ(len, itemCount * (itemSize + 1));
|
||||||
|
|
||||||
|
itemCount = VARINT_MAX_4BYTE / (itemSize + 1);
|
||||||
|
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), four);
|
||||||
|
EXPECT_EQ(len, itemCount * (itemSize + 1));
|
||||||
|
|
||||||
|
itemCount++;
|
||||||
|
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), (uint32_t)0);
|
||||||
|
EXPECT_EQ(len, itemCount * (itemSize + 1));
|
||||||
|
|
||||||
|
itemSize = sizeof(int64_t);
|
||||||
|
itemCount = VARINT_MAX_1BYTE / (itemSize + two);
|
||||||
|
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), (uint32_t)1);
|
||||||
|
EXPECT_EQ(len, itemCount * (itemSize + two));
|
||||||
|
|
||||||
|
itemCount++;
|
||||||
|
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), two);
|
||||||
|
EXPECT_EQ(len, itemCount * (itemSize + two));
|
||||||
|
|
||||||
|
itemCount = VARINT_MAX_2BYTE / (itemSize + two);
|
||||||
|
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), two);
|
||||||
|
EXPECT_EQ(len, itemCount * (itemSize + two));
|
||||||
|
|
||||||
|
itemCount++;
|
||||||
|
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), three);
|
||||||
|
EXPECT_EQ(len, itemCount * (itemSize + two));
|
||||||
|
|
||||||
|
itemCount = VARINT_MAX_3BYTE / (itemSize + two);
|
||||||
|
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), three);
|
||||||
|
EXPECT_EQ(len, itemCount * (itemSize + two));
|
||||||
|
|
||||||
|
itemCount++;
|
||||||
|
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), four);
|
||||||
|
EXPECT_EQ(len, itemCount * (itemSize + two));
|
||||||
|
|
||||||
|
itemCount = VARINT_MAX_4BYTE / (itemSize + two);
|
||||||
|
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), four);
|
||||||
|
EXPECT_EQ(len, itemCount * (itemSize + two));
|
||||||
|
|
||||||
|
itemCount++;
|
||||||
|
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), (uint32_t)0);
|
||||||
|
EXPECT_EQ(len, itemCount * (itemSize + two));
|
||||||
|
}
|
||||||
|
|
||||||
|
HWTEST_F(VarintEncodeUnittest, EncodeZigZag, TestSize.Level1)
|
||||||
|
{
|
||||||
|
int8_t signed8 = 0;
|
||||||
|
EXPECT_EQ(EncodeZigZag(signed8), (uint8_t)0);
|
||||||
|
signed8 = -1;
|
||||||
|
EXPECT_EQ(EncodeZigZag(signed8), (uint8_t)1);
|
||||||
|
signed8 = 1;
|
||||||
|
EXPECT_EQ(EncodeZigZag(signed8), (uint8_t)(signed8 * two));
|
||||||
|
std::srand(std::time(nullptr));
|
||||||
|
int rand = std::rand();
|
||||||
|
signed8 = static_cast<int8_t>rand;
|
||||||
|
if (signed8 >= 0) {
|
||||||
|
// n are encoded as 2 * n
|
||||||
|
EXPECT_EQ(EncodeZigZag(signed8), (uint8_t)(signed8 * two));
|
||||||
|
} else {
|
||||||
|
// -n are encoded as 2 * n + 1
|
||||||
|
EXPECT_EQ(EncodeZigZag(signed8), (uint8_t)(-signed8 - 1 + -signed8));
|
||||||
|
}
|
||||||
|
signed8 = std::numeric_limits<int8_t>::min();
|
||||||
|
EXPECT_EQ(EncodeZigZag(signed8), std::numeric_limits<uint8_t>::max());
|
||||||
|
signed8 = std::numeric_limits<int8_t>::max();
|
||||||
|
EXPECT_EQ(EncodeZigZag(signed8), std::numeric_limits<uint8_t>::max() - 1);
|
||||||
|
|
||||||
|
int32_t signed32 = 0;
|
||||||
|
EXPECT_EQ(EncodeZigZag(signed32), (uint32_t)0);
|
||||||
|
signed32 = -1;
|
||||||
|
EXPECT_EQ(EncodeZigZag(signed32), (uint32_t)1);
|
||||||
|
signed32 = 1;
|
||||||
|
EXPECT_EQ(EncodeZigZag(signed32), (uint32_t)(signed32 * two));
|
||||||
|
std::srand(rand);
|
||||||
|
rand = std::rand();
|
||||||
|
signed32 = static_cast<int32_t>rand;
|
||||||
|
if (signed32 >= 0) {
|
||||||
|
// n are encoded as 2 * n
|
||||||
|
EXPECT_EQ(EncodeZigZag(signed32), (uint32_t)(signed32 * two));
|
||||||
|
} else {
|
||||||
|
// -n are encoded as 2 * n + 1
|
||||||
|
EXPECT_EQ(EncodeZigZag(signed32), (uint32_t)(-signed32 - 1 + -signed32));
|
||||||
|
}
|
||||||
|
signed32 = std::numeric_limits<int32_t>::min();
|
||||||
|
EXPECT_EQ(EncodeZigZag(signed32), std::numeric_limits<uint32_t>::max());
|
||||||
|
signed32 = std::numeric_limits<int32_t>::max();
|
||||||
|
EXPECT_EQ(EncodeZigZag(signed32), std::numeric_limits<uint32_t>::max() - 1);
|
||||||
|
|
||||||
|
int64_t signed64 = 0;
|
||||||
|
EXPECT_EQ(EncodeZigZag(signed64), (uint64_t)0);
|
||||||
|
signed64 = -1;
|
||||||
|
EXPECT_EQ(EncodeZigZag(signed64), (uint64_t)1);
|
||||||
|
signed64 = 1;
|
||||||
|
EXPECT_EQ(EncodeZigZag(signed64), (uint64_t)(signed64 * two));
|
||||||
|
std::srand(rand);
|
||||||
|
rand = std::rand();
|
||||||
|
signed64 = static_cast<int64_t>rand;
|
||||||
|
if (signed64 >= 0) {
|
||||||
|
// n are encoded as 2 * n
|
||||||
|
EXPECT_EQ(EncodeZigZag(signed64), (uint64_t)(signed64 * two));
|
||||||
|
} else {
|
||||||
|
// -n are encoded as 2 * n + 1
|
||||||
|
EXPECT_EQ(EncodeZigZag(signed64), (uint64_t)(-signed64 - 1 + -signed64));
|
||||||
|
}
|
||||||
|
signed64 = std::numeric_limits<int64_t>::min();
|
||||||
|
EXPECT_EQ(EncodeZigZag(signed64), std::numeric_limits<uint64_t>::max());
|
||||||
|
signed64 = std::numeric_limits<int64_t>::max();
|
||||||
|
EXPECT_EQ(EncodeZigZag(signed64), std::numeric_limits<uint64_t>::max() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CompareBytes(const uint8_t* a, const uint8_t* b, size_t size)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < size; i++) {
|
||||||
|
if (a[i] != b[i]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t ENCODE_BYTES_MIN_BOOL[] = {0x00};
|
||||||
|
const uint8_t ENCODE_BYTES_MAX_BOOL[] = {0x01};
|
||||||
|
const uint8_t ENCODE_BYTES_MIN_S8[] = {0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01};
|
||||||
|
const uint8_t ENCODE_BYTES_MAX_S8[] = {0x7F};
|
||||||
|
const uint8_t ENCODE_BYTES_MIN_U8[] = {0x00};
|
||||||
|
const uint8_t ENCODE_BYTES_MAX_U8[] = {0xFF, 0x01};
|
||||||
|
const uint8_t ENCODE_BYTES_MIN_S32[] = {0x80, 0x80, 0x80, 0x80, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0x01};
|
||||||
|
const uint8_t ENCODE_BYTES_MAX_S32[] = {0xFF, 0xFF, 0xFF, 0xFF, 0x07};
|
||||||
|
const uint8_t ENCODE_BYTES_MIN_U32[] = {0x00};
|
||||||
|
const uint8_t ENCODE_BYTES_MAX_U32[] = {0xFF, 0xFF, 0xFF, 0xFF, 0x0F};
|
||||||
|
const uint8_t ENCODE_BYTES_MIN_S64[] = {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01};
|
||||||
|
const uint8_t ENCODE_BYTES_MAX_S64[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F};
|
||||||
|
const uint8_t ENCODE_BYTES_MIN_U64[] = {0x00};
|
||||||
|
const uint8_t ENCODE_BYTES_MAX_U64[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01};
|
||||||
|
|
||||||
|
HWTEST_F(VarintEncodeUnittest, EncodeVarint, TestSize.Level1)
|
||||||
|
{
|
||||||
|
uint8_t buf[VARINT_ENCODE_MAX_SIZE] = {0};
|
||||||
|
bool b = std::numeric_limits<bool>::min();
|
||||||
|
EXPECT_EQ(EncodeVarint(buf, b), (uint32_t)sizeof(ENCODE_BYTES_MIN_BOOL));
|
||||||
|
EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MIN_BOOL, sizeof(ENCODE_BYTES_MIN_BOOL)));
|
||||||
|
b = std::numeric_limits<bool>::max();
|
||||||
|
EXPECT_EQ(EncodeVarint(buf, b), (uint32_t)sizeof(ENCODE_BYTES_MAX_BOOL));
|
||||||
|
EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MAX_BOOL, sizeof(ENCODE_BYTES_MAX_BOOL)));
|
||||||
|
|
||||||
|
int8_t s8 = std::numeric_limits<int8_t>::min();
|
||||||
|
EXPECT_EQ(EncodeVarint(buf, s8), (uint32_t)sizeof(ENCODE_BYTES_MIN_S8));
|
||||||
|
EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MIN_S8, sizeof(ENCODE_BYTES_MIN_S8)));
|
||||||
|
s8 = std::numeric_limits<int8_t>::max();
|
||||||
|
EXPECT_EQ(EncodeVarint(buf, s8), (uint32_t)sizeof(ENCODE_BYTES_MAX_S8));
|
||||||
|
EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MAX_S8, sizeof(ENCODE_BYTES_MAX_S8)));
|
||||||
|
|
||||||
|
uint8_t u8 = std::numeric_limits<uint8_t>::min();
|
||||||
|
EXPECT_EQ(EncodeVarint(buf, u8), (uint32_t)sizeof(ENCODE_BYTES_MIN_U8));
|
||||||
|
EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MIN_U8, sizeof(ENCODE_BYTES_MIN_U8)));
|
||||||
|
u8 = std::numeric_limits<uint8_t>::max();
|
||||||
|
EXPECT_EQ(EncodeVarint(buf, u8), (uint32_t)sizeof(ENCODE_BYTES_MAX_U8));
|
||||||
|
EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MAX_U8, sizeof(ENCODE_BYTES_MAX_U8)));
|
||||||
|
|
||||||
|
int32_t s32 = std::numeric_limits<int32_t>::min();
|
||||||
|
EXPECT_EQ(EncodeVarint(buf, s32), (uint32_t)sizeof(ENCODE_BYTES_MIN_S32));
|
||||||
|
EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MIN_S32, sizeof(ENCODE_BYTES_MIN_S32)));
|
||||||
|
s32 = std::numeric_limits<int32_t>::max();
|
||||||
|
EXPECT_EQ(EncodeVarint(buf, s32), (uint32_t)sizeof(ENCODE_BYTES_MAX_S32));
|
||||||
|
EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MAX_S32, sizeof(ENCODE_BYTES_MAX_S32)));
|
||||||
|
|
||||||
|
uint32_t u32 = std::numeric_limits<uint32_t>::min();
|
||||||
|
EXPECT_EQ(EncodeVarint(buf, u32), (uint32_t)sizeof(ENCODE_BYTES_MIN_U32));
|
||||||
|
EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MIN_U32, sizeof(ENCODE_BYTES_MIN_U32)));
|
||||||
|
u32 = std::numeric_limits<uint32_t>::max();
|
||||||
|
EXPECT_EQ(EncodeVarint(buf, u32), (uint32_t)sizeof(ENCODE_BYTES_MAX_U32));
|
||||||
|
EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MAX_U32, sizeof(ENCODE_BYTES_MAX_U32)));
|
||||||
|
|
||||||
|
int64_t s64 = std::numeric_limits<int64_t>::min();
|
||||||
|
EXPECT_EQ(EncodeVarint(buf, s64), (uint32_t)sizeof(ENCODE_BYTES_MIN_S64));
|
||||||
|
EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MIN_S64, sizeof(ENCODE_BYTES_MIN_S64)));
|
||||||
|
s64 = std::numeric_limits<int64_t>::max();
|
||||||
|
EXPECT_EQ(EncodeVarint(buf, s64), (uint32_t)sizeof(ENCODE_BYTES_MAX_S64));
|
||||||
|
EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MAX_S64, sizeof(ENCODE_BYTES_MAX_S64)));
|
||||||
|
|
||||||
|
uint64_t u64 = std::numeric_limits<uint64_t>::min();
|
||||||
|
EXPECT_EQ(EncodeVarint(buf, u64), (uint32_t)sizeof(ENCODE_BYTES_MIN_U64));
|
||||||
|
EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MIN_U64, sizeof(ENCODE_BYTES_MIN_U64)));
|
||||||
|
u64 = std::numeric_limits<uint64_t>::max();
|
||||||
|
EXPECT_EQ(EncodeVarint(buf, u64), (uint32_t)sizeof(ENCODE_BYTES_MAX_U64));
|
||||||
|
EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MAX_U64, sizeof(ENCODE_BYTES_MAX_U64)));
|
||||||
|
}
|
||||||
|
|
||||||
|
HWTEST_F(VarintEncodeUnittest, EncodeVarintPadding, TestSize.Level1)
|
||||||
|
{
|
||||||
|
const uint8_t paddingByte = 0x80;
|
||||||
|
uint8_t buf[VARINT_ENCODE_MAX_SIZE] = {0};
|
||||||
|
uint64_t u64 = 1;
|
||||||
|
EncodeVarintPadding(buf, u64, VARINT_ENCODE_MAX_SIZE);
|
||||||
|
uint32_t i = 1;
|
||||||
|
while (i < VARINT_ENCODE_MAX_SIZE - 1) {
|
||||||
|
EXPECT_EQ(buf[i++], paddingByte);
|
||||||
|
}
|
||||||
|
EXPECT_EQ(buf[i], (uint8_t)0);
|
||||||
|
|
||||||
|
u64 = std::numeric_limits<uint64_t>::max();
|
||||||
|
EncodeVarintPadding(buf, u64, VARINT_ENCODE_MAX_SIZE);
|
||||||
|
EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MAX_U64, sizeof(ENCODE_BYTES_MAX_U64)));
|
||||||
|
}
|
||||||
|
} // namespace Profiler
|
||||||
|
} // namespace Developtools
|
||||||
|
} // namespace OHOS
|
Loading…
Reference in New Issue
Block a user