300 lines
8.3 KiB
C++
300 lines
8.3 KiB
C++
//======== Copyright © 2011, Valve Corporation, All rights reserved. ========//
|
|
//
|
|
// Purpose: Helper functions for protobufs
|
|
//
|
|
//===========================================================================//
|
|
|
|
#include "tier0/dbg.h"
|
|
|
|
#include "google/protobuf/descriptor.h"
|
|
#include "google/protobuf/reflection_ops.h"
|
|
#include "google/protobuf/descriptor.pb.h"
|
|
|
|
using namespace google::protobuf;
|
|
//using namespace stl;
|
|
|
|
class CProtobufLogHandler
|
|
{
|
|
public:
|
|
|
|
CProtobufLogHandler()
|
|
{
|
|
google::protobuf::SetLogHandler( LogHandler );
|
|
}
|
|
|
|
~CProtobufLogHandler()
|
|
{
|
|
google::protobuf::SetLogHandler( NULL );
|
|
}
|
|
|
|
static void LogHandler( google::protobuf::LogLevel level, const char* filename, int line, const std::string& message )
|
|
{
|
|
switch ( level )
|
|
{
|
|
case google::protobuf::LOGLEVEL_INFO:
|
|
case google::protobuf::LOGLEVEL_WARNING:
|
|
DevMsg( "Protobuf: %s(%d): %s\n", filename, line, message.c_str() );
|
|
break;
|
|
|
|
case google::protobuf::LOGLEVEL_ERROR:
|
|
Warning( "Protobuf: %s(%d): %s\n", filename, line, message.c_str() );
|
|
break;
|
|
|
|
case google::protobuf::LOGLEVEL_FATAL:
|
|
Warning( "Protobuf: %s(%d): %s\n", filename, line, message.c_str() );
|
|
Plat_ExitProcess( 100 );
|
|
break;
|
|
}
|
|
|
|
}
|
|
};
|
|
|
|
static CProtobufLogHandler g_ProtobufLogHandler;
|
|
|
|
/*
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Purpose: Copies a field into a third message if its different in the other messages
|
|
//----------------------------------------------------------------------------
|
|
bool ProtoBufDeltaMerge( const ::google::protobuf::Message &src, const ::google::protobuf::Message &delta, ::google::protobuf::Message* to )
|
|
{
|
|
const Descriptor* descriptor = src.GetDescriptor();
|
|
|
|
if ( descriptor != delta.GetDescriptor() )
|
|
{
|
|
Warning( "Tried to merge delta to a src message of a different type.");
|
|
return false;
|
|
}
|
|
|
|
if ( descriptor != to->GetDescriptor() )
|
|
{
|
|
Warning( "Tried to merge dleta to a message of a different type.");
|
|
return false;
|
|
}
|
|
|
|
to->Clear();
|
|
|
|
const Reflection* src_reflection = src.GetReflection();
|
|
const Reflection* delta_reflection = delta.GetReflection();
|
|
const Reflection* to_reflection = to->GetReflection();
|
|
|
|
Assert( src_reflection == delta_reflection );
|
|
Assert( src_reflection == to_reflection );
|
|
|
|
vector<const FieldDescriptor*> fields;
|
|
src_reflection->ListFields(src, &fields);
|
|
|
|
for ( size_t i = 0; i < fields.size(); i++ )
|
|
{
|
|
const FieldDescriptor* field = fields[i];
|
|
|
|
// We can't really delta repeated fields, it sucks
|
|
if ( field->is_repeated() )
|
|
{
|
|
int count = delta_reflection->FieldSize(delta, field);
|
|
to_reflection->ClearField( to, field );
|
|
|
|
for ( int j = 0; j < count; j++ )
|
|
{
|
|
switch ( field->cpp_type() )
|
|
{
|
|
#define HANDLE_TYPE(CPPTYPE, METHOD) \
|
|
case FieldDescriptor::CPPTYPE_##CPPTYPE: \
|
|
to_reflection->Add##METHOD(to, field, delta_reflection->GetRepeated##METHOD(delta, field, j)); \
|
|
break;
|
|
|
|
HANDLE_TYPE(INT32 , Int32 );
|
|
HANDLE_TYPE(INT64 , Int64 );
|
|
HANDLE_TYPE(UINT32, UInt32);
|
|
HANDLE_TYPE(UINT64, UInt64);
|
|
HANDLE_TYPE(FLOAT , Float );
|
|
HANDLE_TYPE(DOUBLE, Double);
|
|
HANDLE_TYPE(BOOL , Bool );
|
|
HANDLE_TYPE(STRING, String);
|
|
HANDLE_TYPE(ENUM , Enum );
|
|
#undef HANDLE_TYPE
|
|
|
|
case FieldDescriptor::CPPTYPE_MESSAGE:
|
|
// We can recurse this!
|
|
Message *to_element = to_reflection->AddMessage( to, field );
|
|
if ( !ProtoBufDeltaMerge( src_reflection->GetRepeatedMessage( src, field, j ), delta_reflection->GetRepeatedMessage( delta, field, j ), to_element ) )
|
|
return false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch ( field->cpp_type() )
|
|
{
|
|
#define HANDLE_TYPE(CPPTYPE, METHOD) \
|
|
case FieldDescriptor::CPPTYPE_##CPPTYPE: \
|
|
if ( delta_reflection->HasField( delta, field ) ) \
|
|
{ \
|
|
to_reflection->Set##METHOD( to, field, delta_reflection->Get##METHOD( delta, field ) ); \
|
|
} \
|
|
else \
|
|
{ \
|
|
if ( src_reflection->HasField( src, field ) ) \
|
|
{ \
|
|
to_reflection->Set##METHOD( to, field, src_reflection->Get##METHOD( delta, field ) ); \
|
|
} \
|
|
else \
|
|
{ \
|
|
to_reflection->ClearField( to, field ); \
|
|
} \
|
|
} \
|
|
break;
|
|
|
|
HANDLE_TYPE(INT32 , Int32 );
|
|
HANDLE_TYPE(INT64 , Int64 );
|
|
HANDLE_TYPE(UINT32, UInt32);
|
|
HANDLE_TYPE(UINT64, UInt64);
|
|
HANDLE_TYPE(FLOAT , Float );
|
|
HANDLE_TYPE(DOUBLE, Double);
|
|
HANDLE_TYPE(BOOL , Bool );
|
|
HANDLE_TYPE(STRING, String);
|
|
HANDLE_TYPE(ENUM , Enum );
|
|
#undef HANDLE_TYPE
|
|
|
|
case FieldDescriptor::CPPTYPE_MESSAGE:
|
|
Message *to_element = to_reflection->MutableMessage( to, field );
|
|
if ( delta_reflection->HasField( delta, field ) )
|
|
{
|
|
if ( !ProtoBufDeltaMerge( src_reflection->GetMessage( src, field ), delta_reflection->GetMessage( delta, field ), to_element ) )
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
if ( src_reflection->HasField( src, field ) ) \
|
|
{
|
|
to_element->Clear();
|
|
to_element->MergeFrom( src_reflection->GetMessage( src, field ) );
|
|
}
|
|
else
|
|
{
|
|
to_reflection->ClearField( to, field );
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ProtoBufCalcDelta( const ::google::protobuf::Message &src, const ::google::protobuf::Message &dest, ::google::protobuf::Message *delta )
|
|
{
|
|
const Descriptor* descriptor = src.GetDescriptor();
|
|
|
|
if ( descriptor != dest.GetDescriptor() )
|
|
{
|
|
Warning( "Tried to calc delta to a src message of a different type.");
|
|
return false;
|
|
}
|
|
|
|
if ( descriptor != delta->GetDescriptor() )
|
|
{
|
|
Warning( "Tried to calc delta to a message of a different type.");
|
|
return false;
|
|
}
|
|
|
|
delta->Clear();
|
|
|
|
const Reflection* src_reflection = src.GetReflection();
|
|
const Reflection* dest_reflection = dest.GetReflection();
|
|
const Reflection* delta_reflection = delta->GetReflection();
|
|
|
|
Assert( src_reflection == dest_reflection );
|
|
Assert( src_reflection == delta_reflection );
|
|
|
|
vector<const FieldDescriptor*> fields;
|
|
src_reflection->ListFields(src, &fields);
|
|
|
|
for ( size_t i = 0; i < fields.size(); i++ )
|
|
{
|
|
const FieldDescriptor* field = fields[i];
|
|
|
|
// We can't really delta repeated fields, it sucks
|
|
if ( field->is_repeated() )
|
|
{
|
|
int count = dest_reflection->FieldSize(dest, field);
|
|
delta_reflection->ClearField( delta, field );
|
|
|
|
for ( int j = 0; j < count; j++ )
|
|
{
|
|
switch ( field->cpp_type() )
|
|
{
|
|
#define HANDLE_TYPE(CPPTYPE, METHOD) \
|
|
case FieldDescriptor::CPPTYPE_##CPPTYPE: \
|
|
delta_reflection->Add##METHOD(delta, field, dest_reflection->GetRepeated##METHOD(dest, field, j)); \
|
|
break;
|
|
|
|
HANDLE_TYPE(INT32 , Int32 );
|
|
HANDLE_TYPE(INT64 , Int64 );
|
|
HANDLE_TYPE(UINT32, UInt32);
|
|
HANDLE_TYPE(UINT64, UInt64);
|
|
HANDLE_TYPE(FLOAT , Float );
|
|
HANDLE_TYPE(DOUBLE, Double);
|
|
HANDLE_TYPE(BOOL , Bool );
|
|
HANDLE_TYPE(STRING, String);
|
|
HANDLE_TYPE(ENUM , Enum );
|
|
#undef HANDLE_TYPE
|
|
|
|
case FieldDescriptor::CPPTYPE_MESSAGE:
|
|
// We can recurse this!
|
|
Message *delta_element = delta_reflection->AddMessage( delta, field );
|
|
if ( !ProtoBufCalcDelta( src_reflection->GetRepeatedMessage( src, field, j ), dest_reflection->GetRepeatedMessage( dest, field, j ), delta_element ) )
|
|
return false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch ( field->cpp_type() )
|
|
{
|
|
#define HANDLE_TYPE(CPPTYPE, METHOD) \
|
|
case FieldDescriptor::CPPTYPE_##CPPTYPE: \
|
|
if ( dest_reflection->HasField( dest, field ) ) \
|
|
{ \
|
|
if ( !src_reflection->HasField( src, field ) || \
|
|
src_reflection->Get##METHOD( src, field ) != dest_reflection->Get##METHOD( dest, field ) ) \
|
|
{ \
|
|
delta_reflection->Set##METHOD( delta, field, dest_reflection->Get##METHOD( dest, field ) ); \
|
|
} \
|
|
} \
|
|
else \
|
|
{ \
|
|
if ( src_reflection->HasField( src, field ) ) \
|
|
{ \
|
|
delta_reflection->Set##METHOD( delta, field, dest_reflection->Get##METHOD( dest, field ) ); \
|
|
} \
|
|
} \
|
|
break;
|
|
HANDLE_TYPE(INT32 , Int32 );
|
|
HANDLE_TYPE(INT64 , Int64 );
|
|
HANDLE_TYPE(UINT32, UInt32);
|
|
HANDLE_TYPE(UINT64, UInt64);
|
|
HANDLE_TYPE(FLOAT , Float );
|
|
HANDLE_TYPE(DOUBLE, Double);
|
|
HANDLE_TYPE(BOOL , Bool );
|
|
HANDLE_TYPE(STRING, String);
|
|
HANDLE_TYPE(ENUM , Enum );
|
|
#undef HANDLE_TYPE
|
|
|
|
case FieldDescriptor::CPPTYPE_MESSAGE:
|
|
Message *delta_element = delta_reflection->MutableMessage( delta, field );
|
|
if ( !ProtoBufCalcDelta( src_reflection->GetMessage( src, field ), dest_reflection->GetMessage( dest, field ), delta_element ) )
|
|
return false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
*/
|
|
|