1
0
mirror of https://gitlab.com/kelteseth/ScreenPlay.git synced 2024-09-15 06:52:34 +02:00

Add protocolbuffer lib

This commit is contained in:
Daniel Schukies 2018-11-17 11:31:38 +01:00
parent 2acb4c4229
commit 8e10948094
572 changed files with 273415 additions and 0 deletions

11
Common/ProtocolBuffer/.gitattributes vendored Normal file
View File

@ -0,0 +1,11 @@
*.uasset filter=lfs diff=lfs merge=lfs -text
*.umap filter=lfs diff=lfs merge=lfs -text
*.kra filter=lfs diff=lfs merge=lfs -text
*.blend filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text
*.jpg filter=lfs diff=lfs merge=lfs -text
*.fbx filter=lfs diff=lfs merge=lfs -text
*.bmp filter=lfs diff=lfs merge=lfs -text
*.lib filter=lfs diff=lfs merge=lfs -text
*.exe filter=lfs diff=lfs merge=lfs -text
*.dll filter=lfs diff=lfs merge=lfs -text

View File

@ -0,0 +1,554 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: account.proto
#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
#include "account.pb.h"
#include <algorithm>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/port.h>
#include <google/protobuf/stubs/once.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/wire_format_lite_inl.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/generated_message_reflection.h>
#include <google/protobuf/reflection_ops.h>
#include <google/protobuf/wire_format.h>
// @@protoc_insertion_point(includes)
namespace community {
class LoginDefaultTypeInternal {
public:
::google::protobuf::internal::ExplicitlyConstructed<Login>
_instance;
} _Login_default_instance_;
namespace protobuf_account_2eproto {
namespace {
::google::protobuf::Metadata file_level_metadata[1];
} // namespace
PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::ParseTableField
const TableStruct::entries[] GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
{0, 0, 0, ::google::protobuf::internal::kInvalidMask, 0, 0},
};
PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::AuxillaryParseTableField
const TableStruct::aux[] GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
::google::protobuf::internal::AuxillaryParseTableField(),
};
PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::ParseTable const
TableStruct::schema[] GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
{ NULL, NULL, 0, -1, -1, -1, -1, NULL, false },
};
const ::google::protobuf::uint32 TableStruct::offsets[] GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
~0u, // no _has_bits_
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Login, _internal_metadata_),
~0u, // no _extensions_
~0u, // no _oneof_case_
~0u, // no _weak_field_map_
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Login, username_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Login, password_),
};
static const ::google::protobuf::internal::MigrationSchema schemas[] GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
{ 0, -1, sizeof(Login)},
};
static ::google::protobuf::Message const * const file_default_instances[] = {
reinterpret_cast<const ::google::protobuf::Message*>(&_Login_default_instance_),
};
namespace {
void protobuf_AssignDescriptors() {
AddDescriptors();
::google::protobuf::MessageFactory* factory = NULL;
AssignDescriptors(
"account.proto", schemas, file_default_instances, TableStruct::offsets, factory,
file_level_metadata, NULL, NULL);
}
void protobuf_AssignDescriptorsOnce() {
static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
::google::protobuf::GoogleOnceInit(&once, &protobuf_AssignDescriptors);
}
void protobuf_RegisterTypes(const ::std::string&) GOOGLE_ATTRIBUTE_COLD;
void protobuf_RegisterTypes(const ::std::string&) {
protobuf_AssignDescriptorsOnce();
::google::protobuf::internal::RegisterAllTypes(file_level_metadata, 1);
}
} // namespace
void TableStruct::InitDefaultsImpl() {
GOOGLE_PROTOBUF_VERIFY_VERSION;
::google::protobuf::internal::InitProtobufDefaults();
_Login_default_instance_._instance.DefaultConstruct();
::google::protobuf::internal::OnShutdownDestroyMessage(
&_Login_default_instance_);}
void InitDefaults() {
static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
::google::protobuf::GoogleOnceInit(&once, &TableStruct::InitDefaultsImpl);
}
namespace {
void AddDescriptorsImpl() {
InitDefaults();
static const char descriptor[] GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
"\n\raccount.proto\022\tcommunity\"+\n\005Login\022\020\n\010u"
"sername\030\001 \001(\t\022\020\n\010password\030\002 \001(\tb\006proto3"
};
::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
descriptor, 79);
::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
"account.proto", &protobuf_RegisterTypes);
}
} // anonymous namespace
void AddDescriptors() {
static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
::google::protobuf::GoogleOnceInit(&once, &AddDescriptorsImpl);
}
// Force AddDescriptors() to be called at dynamic initialization time.
struct StaticDescriptorInitializer {
StaticDescriptorInitializer() {
AddDescriptors();
}
} static_descriptor_initializer;
} // namespace protobuf_account_2eproto
// ===================================================================
#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int Login::kUsernameFieldNumber;
const int Login::kPasswordFieldNumber;
#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
Login::Login()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
if (GOOGLE_PREDICT_TRUE(this != internal_default_instance())) {
protobuf_account_2eproto::InitDefaults();
}
SharedCtor();
// @@protoc_insertion_point(constructor:community.Login)
}
Login::Login(const Login& from)
: ::google::protobuf::Message(),
_internal_metadata_(NULL),
_cached_size_(0) {
_internal_metadata_.MergeFrom(from._internal_metadata_);
username_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
if (from.username().size() > 0) {
username_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.username_);
}
password_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
if (from.password().size() > 0) {
password_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.password_);
}
// @@protoc_insertion_point(copy_constructor:community.Login)
}
void Login::SharedCtor() {
username_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
password_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
_cached_size_ = 0;
}
Login::~Login() {
// @@protoc_insertion_point(destructor:community.Login)
SharedDtor();
}
void Login::SharedDtor() {
username_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
password_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
void Login::SetCachedSize(int size) const {
GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
_cached_size_ = size;
GOOGLE_SAFE_CONCURRENT_WRITES_END();
}
const ::google::protobuf::Descriptor* Login::descriptor() {
protobuf_account_2eproto::protobuf_AssignDescriptorsOnce();
return protobuf_account_2eproto::file_level_metadata[kIndexInFileMessages].descriptor;
}
const Login& Login::default_instance() {
protobuf_account_2eproto::InitDefaults();
return *internal_default_instance();
}
Login* Login::New(::google::protobuf::Arena* arena) const {
Login* n = new Login;
if (arena != NULL) {
arena->Own(n);
}
return n;
}
void Login::Clear() {
// @@protoc_insertion_point(message_clear_start:community.Login)
::google::protobuf::uint32 cached_has_bits = 0;
// Prevent compiler warnings about cached_has_bits being unused
(void) cached_has_bits;
username_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
password_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
_internal_metadata_.Clear();
}
bool Login::MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input) {
#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
::google::protobuf::uint32 tag;
// @@protoc_insertion_point(parse_start:community.Login)
for (;;) {
::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoffNoLastTag(127u);
tag = p.first;
if (!p.second) goto handle_unusual;
switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
// string username = 1;
case 1: {
if (static_cast< ::google::protobuf::uint8>(tag) ==
static_cast< ::google::protobuf::uint8>(10u /* 10 & 0xFF */)) {
DO_(::google::protobuf::internal::WireFormatLite::ReadString(
input, this->mutable_username()));
DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
this->username().data(), static_cast<int>(this->username().length()),
::google::protobuf::internal::WireFormatLite::PARSE,
"community.Login.username"));
} else {
goto handle_unusual;
}
break;
}
// string password = 2;
case 2: {
if (static_cast< ::google::protobuf::uint8>(tag) ==
static_cast< ::google::protobuf::uint8>(18u /* 18 & 0xFF */)) {
DO_(::google::protobuf::internal::WireFormatLite::ReadString(
input, this->mutable_password()));
DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
this->password().data(), static_cast<int>(this->password().length()),
::google::protobuf::internal::WireFormatLite::PARSE,
"community.Login.password"));
} else {
goto handle_unusual;
}
break;
}
default: {
handle_unusual:
if (tag == 0) {
goto success;
}
DO_(::google::protobuf::internal::WireFormat::SkipField(
input, tag, _internal_metadata_.mutable_unknown_fields()));
break;
}
}
}
success:
// @@protoc_insertion_point(parse_success:community.Login)
return true;
failure:
// @@protoc_insertion_point(parse_failure:community.Login)
return false;
#undef DO_
}
void Login::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
// @@protoc_insertion_point(serialize_start:community.Login)
::google::protobuf::uint32 cached_has_bits = 0;
(void) cached_has_bits;
// string username = 1;
if (this->username().size() > 0) {
::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
this->username().data(), static_cast<int>(this->username().length()),
::google::protobuf::internal::WireFormatLite::SERIALIZE,
"community.Login.username");
::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
1, this->username(), output);
}
// string password = 2;
if (this->password().size() > 0) {
::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
this->password().data(), static_cast<int>(this->password().length()),
::google::protobuf::internal::WireFormatLite::SERIALIZE,
"community.Login.password");
::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
2, this->password(), output);
}
if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
(::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance()), output);
}
// @@protoc_insertion_point(serialize_end:community.Login)
}
::google::protobuf::uint8* Login::InternalSerializeWithCachedSizesToArray(
bool deterministic, ::google::protobuf::uint8* target) const {
(void)deterministic; // Unused
// @@protoc_insertion_point(serialize_to_array_start:community.Login)
::google::protobuf::uint32 cached_has_bits = 0;
(void) cached_has_bits;
// string username = 1;
if (this->username().size() > 0) {
::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
this->username().data(), static_cast<int>(this->username().length()),
::google::protobuf::internal::WireFormatLite::SERIALIZE,
"community.Login.username");
target =
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
1, this->username(), target);
}
// string password = 2;
if (this->password().size() > 0) {
::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
this->password().data(), static_cast<int>(this->password().length()),
::google::protobuf::internal::WireFormatLite::SERIALIZE,
"community.Login.password");
target =
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
2, this->password(), target);
}
if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
(::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance()), target);
}
// @@protoc_insertion_point(serialize_to_array_end:community.Login)
return target;
}
size_t Login::ByteSizeLong() const {
// @@protoc_insertion_point(message_byte_size_start:community.Login)
size_t total_size = 0;
if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
(::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance()));
}
// string username = 1;
if (this->username().size() > 0) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->username());
}
// string password = 2;
if (this->password().size() > 0) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->password());
}
int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
_cached_size_ = cached_size;
GOOGLE_SAFE_CONCURRENT_WRITES_END();
return total_size;
}
void Login::MergeFrom(const ::google::protobuf::Message& from) {
// @@protoc_insertion_point(generalized_merge_from_start:community.Login)
GOOGLE_DCHECK_NE(&from, this);
const Login* source =
::google::protobuf::internal::DynamicCastToGenerated<const Login>(
&from);
if (source == NULL) {
// @@protoc_insertion_point(generalized_merge_from_cast_fail:community.Login)
::google::protobuf::internal::ReflectionOps::Merge(from, this);
} else {
// @@protoc_insertion_point(generalized_merge_from_cast_success:community.Login)
MergeFrom(*source);
}
}
void Login::MergeFrom(const Login& from) {
// @@protoc_insertion_point(class_specific_merge_from_start:community.Login)
GOOGLE_DCHECK_NE(&from, this);
_internal_metadata_.MergeFrom(from._internal_metadata_);
::google::protobuf::uint32 cached_has_bits = 0;
(void) cached_has_bits;
if (from.username().size() > 0) {
username_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.username_);
}
if (from.password().size() > 0) {
password_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.password_);
}
}
void Login::CopyFrom(const ::google::protobuf::Message& from) {
// @@protoc_insertion_point(generalized_copy_from_start:community.Login)
if (&from == this) return;
Clear();
MergeFrom(from);
}
void Login::CopyFrom(const Login& from) {
// @@protoc_insertion_point(class_specific_copy_from_start:community.Login)
if (&from == this) return;
Clear();
MergeFrom(from);
}
bool Login::IsInitialized() const {
return true;
}
void Login::Swap(Login* other) {
if (other == this) return;
InternalSwap(other);
}
void Login::InternalSwap(Login* other) {
using std::swap;
username_.Swap(&other->username_);
password_.Swap(&other->password_);
_internal_metadata_.Swap(&other->_internal_metadata_);
swap(_cached_size_, other->_cached_size_);
}
::google::protobuf::Metadata Login::GetMetadata() const {
protobuf_account_2eproto::protobuf_AssignDescriptorsOnce();
return protobuf_account_2eproto::file_level_metadata[kIndexInFileMessages];
}
#if PROTOBUF_INLINE_NOT_IN_HEADERS
// Login
// string username = 1;
void Login::clear_username() {
username_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
const ::std::string& Login::username() const {
// @@protoc_insertion_point(field_get:community.Login.username)
return username_.GetNoArena();
}
void Login::set_username(const ::std::string& value) {
username_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
// @@protoc_insertion_point(field_set:community.Login.username)
}
#if LANG_CXX11
void Login::set_username(::std::string&& value) {
username_.SetNoArena(
&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::move(value));
// @@protoc_insertion_point(field_set_rvalue:community.Login.username)
}
#endif
void Login::set_username(const char* value) {
GOOGLE_DCHECK(value != NULL);
username_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
// @@protoc_insertion_point(field_set_char:community.Login.username)
}
void Login::set_username(const char* value, size_t size) {
username_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
::std::string(reinterpret_cast<const char*>(value), size));
// @@protoc_insertion_point(field_set_pointer:community.Login.username)
}
::std::string* Login::mutable_username() {
// @@protoc_insertion_point(field_mutable:community.Login.username)
return username_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
::std::string* Login::release_username() {
// @@protoc_insertion_point(field_release:community.Login.username)
return username_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
void Login::set_allocated_username(::std::string* username) {
if (username != NULL) {
} else {
}
username_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), username);
// @@protoc_insertion_point(field_set_allocated:community.Login.username)
}
// string password = 2;
void Login::clear_password() {
password_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
const ::std::string& Login::password() const {
// @@protoc_insertion_point(field_get:community.Login.password)
return password_.GetNoArena();
}
void Login::set_password(const ::std::string& value) {
password_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
// @@protoc_insertion_point(field_set:community.Login.password)
}
#if LANG_CXX11
void Login::set_password(::std::string&& value) {
password_.SetNoArena(
&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::move(value));
// @@protoc_insertion_point(field_set_rvalue:community.Login.password)
}
#endif
void Login::set_password(const char* value) {
GOOGLE_DCHECK(value != NULL);
password_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
// @@protoc_insertion_point(field_set_char:community.Login.password)
}
void Login::set_password(const char* value, size_t size) {
password_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
::std::string(reinterpret_cast<const char*>(value), size));
// @@protoc_insertion_point(field_set_pointer:community.Login.password)
}
::std::string* Login::mutable_password() {
// @@protoc_insertion_point(field_mutable:community.Login.password)
return password_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
::std::string* Login::release_password() {
// @@protoc_insertion_point(field_release:community.Login.password)
return password_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
void Login::set_allocated_password(::std::string* password) {
if (password != NULL) {
} else {
}
password_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), password);
// @@protoc_insertion_point(field_set_allocated:community.Login.password)
}
#endif // PROTOBUF_INLINE_NOT_IN_HEADERS
// @@protoc_insertion_point(namespace_scope)
} // namespace community
// @@protoc_insertion_point(global_scope)

View File

@ -0,0 +1,306 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: account.proto
#ifndef PROTOBUF_account_2eproto__INCLUDED
#define PROTOBUF_account_2eproto__INCLUDED
#include <string>
#include <google/protobuf/stubs/common.h>
#if GOOGLE_PROTOBUF_VERSION < 3004000
#error This file was generated by a newer version of protoc which is
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
#if 3004000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.
#endif
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/arena.h>
#include <google/protobuf/arenastring.h>
#include <google/protobuf/generated_message_table_driven.h>
#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/metadata.h>
#include <google/protobuf/message.h>
#include <google/protobuf/repeated_field.h> // IWYU pragma: export
#include <google/protobuf/extension_set.h> // IWYU pragma: export
#include <google/protobuf/unknown_field_set.h>
// @@protoc_insertion_point(includes)
namespace community {
class Login;
class LoginDefaultTypeInternal;
extern LoginDefaultTypeInternal _Login_default_instance_;
} // namespace community
namespace community {
namespace protobuf_account_2eproto {
// Internal implementation detail -- do not call these.
struct TableStruct {
static const ::google::protobuf::internal::ParseTableField entries[];
static const ::google::protobuf::internal::AuxillaryParseTableField aux[];
static const ::google::protobuf::internal::ParseTable schema[];
static const ::google::protobuf::uint32 offsets[];
static const ::google::protobuf::internal::FieldMetadata field_metadata[];
static const ::google::protobuf::internal::SerializationTable serialization_table[];
static void InitDefaultsImpl();
};
void AddDescriptors();
void InitDefaults();
} // namespace protobuf_account_2eproto
// ===================================================================
class Login : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:community.Login) */ {
public:
Login();
virtual ~Login();
Login(const Login& from);
inline Login& operator=(const Login& from) {
CopyFrom(from);
return *this;
}
#if LANG_CXX11
Login(Login&& from) noexcept
: Login() {
*this = ::std::move(from);
}
inline Login& operator=(Login&& from) noexcept {
if (GetArenaNoVirtual() == from.GetArenaNoVirtual()) {
if (this != &from) InternalSwap(&from);
} else {
CopyFrom(from);
}
return *this;
}
#endif
static const ::google::protobuf::Descriptor* descriptor();
static const Login& default_instance();
static inline const Login* internal_default_instance() {
return reinterpret_cast<const Login*>(
&_Login_default_instance_);
}
static PROTOBUF_CONSTEXPR int const kIndexInFileMessages =
0;
void Swap(Login* other);
friend void swap(Login& a, Login& b) {
a.Swap(&b);
}
// implements Message ----------------------------------------------
inline Login* New() const PROTOBUF_FINAL { return New(NULL); }
Login* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL;
void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
void CopyFrom(const Login& from);
void MergeFrom(const Login& from);
void Clear() PROTOBUF_FINAL;
bool IsInitialized() const PROTOBUF_FINAL;
size_t ByteSizeLong() const PROTOBUF_FINAL;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input) PROTOBUF_FINAL;
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const PROTOBUF_FINAL;
::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
bool deterministic, ::google::protobuf::uint8* target) const PROTOBUF_FINAL;
int GetCachedSize() const PROTOBUF_FINAL { return _cached_size_; }
private:
void SharedCtor();
void SharedDtor();
void SetCachedSize(int size) const PROTOBUF_FINAL;
void InternalSwap(Login* other);
private:
inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
return NULL;
}
inline void* MaybeArenaPtr() const {
return NULL;
}
public:
::google::protobuf::Metadata GetMetadata() const PROTOBUF_FINAL;
// nested types ----------------------------------------------------
// accessors -------------------------------------------------------
// string username = 1;
void clear_username();
static const int kUsernameFieldNumber = 1;
const ::std::string& username() const;
void set_username(const ::std::string& value);
#if LANG_CXX11
void set_username(::std::string&& value);
#endif
void set_username(const char* value);
void set_username(const char* value, size_t size);
::std::string* mutable_username();
::std::string* release_username();
void set_allocated_username(::std::string* username);
// string password = 2;
void clear_password();
static const int kPasswordFieldNumber = 2;
const ::std::string& password() const;
void set_password(const ::std::string& value);
#if LANG_CXX11
void set_password(::std::string&& value);
#endif
void set_password(const char* value);
void set_password(const char* value, size_t size);
::std::string* mutable_password();
::std::string* release_password();
void set_allocated_password(::std::string* password);
// @@protoc_insertion_point(class_scope:community.Login)
private:
::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
::google::protobuf::internal::ArenaStringPtr username_;
::google::protobuf::internal::ArenaStringPtr password_;
mutable int _cached_size_;
friend struct protobuf_account_2eproto::TableStruct;
};
// ===================================================================
// ===================================================================
#if !PROTOBUF_INLINE_NOT_IN_HEADERS
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif // __GNUC__
// Login
// string username = 1;
inline void Login::clear_username() {
username_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline const ::std::string& Login::username() const {
// @@protoc_insertion_point(field_get:community.Login.username)
return username_.GetNoArena();
}
inline void Login::set_username(const ::std::string& value) {
username_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
// @@protoc_insertion_point(field_set:community.Login.username)
}
#if LANG_CXX11
inline void Login::set_username(::std::string&& value) {
username_.SetNoArena(
&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::move(value));
// @@protoc_insertion_point(field_set_rvalue:community.Login.username)
}
#endif
inline void Login::set_username(const char* value) {
GOOGLE_DCHECK(value != NULL);
username_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
// @@protoc_insertion_point(field_set_char:community.Login.username)
}
inline void Login::set_username(const char* value, size_t size) {
username_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
::std::string(reinterpret_cast<const char*>(value), size));
// @@protoc_insertion_point(field_set_pointer:community.Login.username)
}
inline ::std::string* Login::mutable_username() {
// @@protoc_insertion_point(field_mutable:community.Login.username)
return username_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline ::std::string* Login::release_username() {
// @@protoc_insertion_point(field_release:community.Login.username)
return username_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline void Login::set_allocated_username(::std::string* username) {
if (username != NULL) {
} else {
}
username_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), username);
// @@protoc_insertion_point(field_set_allocated:community.Login.username)
}
// string password = 2;
inline void Login::clear_password() {
password_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline const ::std::string& Login::password() const {
// @@protoc_insertion_point(field_get:community.Login.password)
return password_.GetNoArena();
}
inline void Login::set_password(const ::std::string& value) {
password_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
// @@protoc_insertion_point(field_set:community.Login.password)
}
#if LANG_CXX11
inline void Login::set_password(::std::string&& value) {
password_.SetNoArena(
&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::move(value));
// @@protoc_insertion_point(field_set_rvalue:community.Login.password)
}
#endif
inline void Login::set_password(const char* value) {
GOOGLE_DCHECK(value != NULL);
password_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
// @@protoc_insertion_point(field_set_char:community.Login.password)
}
inline void Login::set_password(const char* value, size_t size) {
password_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
::std::string(reinterpret_cast<const char*>(value), size));
// @@protoc_insertion_point(field_set_pointer:community.Login.password)
}
inline ::std::string* Login::mutable_password() {
// @@protoc_insertion_point(field_mutable:community.Login.password)
return password_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline ::std::string* Login::release_password() {
// @@protoc_insertion_point(field_release:community.Login.password)
return password_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline void Login::set_allocated_password(::std::string* password) {
if (password != NULL) {
} else {
}
password_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), password);
// @@protoc_insertion_point(field_set_allocated:community.Login.password)
}
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif // __GNUC__
#endif // !PROTOBUF_INLINE_NOT_IN_HEADERS
// @@protoc_insertion_point(namespace_scope)
} // namespace community
// @@protoc_insertion_point(global_scope)
#endif // PROTOBUF_account_2eproto__INCLUDED

View File

@ -0,0 +1,109 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: character.proto
#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
#include "character.pb.h"
#include <algorithm>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/port.h>
#include <google/protobuf/stubs/once.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/wire_format_lite_inl.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/generated_message_reflection.h>
#include <google/protobuf/reflection_ops.h>
#include <google/protobuf/wire_format.h>
// @@protoc_insertion_point(includes)
namespace community {
namespace protobuf_character_2eproto {
namespace {
} // namespace
PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::ParseTableField
const TableStruct::entries[] GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
{0, 0, 0, ::google::protobuf::internal::kInvalidMask, 0, 0},
};
PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::AuxillaryParseTableField
const TableStruct::aux[] GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
::google::protobuf::internal::AuxillaryParseTableField(),
};
PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::ParseTable const
TableStruct::schema[] GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
{ NULL, NULL, 0, -1, -1, -1, -1, NULL, false },
};
const ::google::protobuf::uint32 TableStruct::offsets[1] = {};
static const ::google::protobuf::internal::MigrationSchema* schemas = NULL;
static const ::google::protobuf::Message* const* file_default_instances = NULL;
namespace {
void protobuf_AssignDescriptors() {
AddDescriptors();
::google::protobuf::MessageFactory* factory = NULL;
AssignDescriptors(
"character.proto", schemas, file_default_instances, TableStruct::offsets, factory,
NULL, NULL, NULL);
}
void protobuf_AssignDescriptorsOnce() {
static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
::google::protobuf::GoogleOnceInit(&once, &protobuf_AssignDescriptors);
}
void protobuf_RegisterTypes(const ::std::string&) GOOGLE_ATTRIBUTE_COLD;
void protobuf_RegisterTypes(const ::std::string&) {
protobuf_AssignDescriptorsOnce();
}
} // namespace
void TableStruct::InitDefaultsImpl() {
GOOGLE_PROTOBUF_VERIFY_VERSION;
::google::protobuf::internal::InitProtobufDefaults();
}
void InitDefaults() {
static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
::google::protobuf::GoogleOnceInit(&once, &TableStruct::InitDefaultsImpl);
}
namespace {
void AddDescriptorsImpl() {
InitDefaults();
static const char descriptor[] GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
"\n\017character.proto\022\tcommunityb\006proto3"
};
::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
descriptor, 36);
::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
"character.proto", &protobuf_RegisterTypes);
}
} // anonymous namespace
void AddDescriptors() {
static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
::google::protobuf::GoogleOnceInit(&once, &AddDescriptorsImpl);
}
// Force AddDescriptors() to be called at dynamic initialization time.
struct StaticDescriptorInitializer {
StaticDescriptorInitializer() {
AddDescriptors();
}
} static_descriptor_initializer;
} // namespace protobuf_character_2eproto
// @@protoc_insertion_point(namespace_scope)
} // namespace community
// @@protoc_insertion_point(global_scope)

View File

@ -0,0 +1,76 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: character.proto
#ifndef PROTOBUF_character_2eproto__INCLUDED
#define PROTOBUF_character_2eproto__INCLUDED
#include <string>
#include <google/protobuf/stubs/common.h>
#if GOOGLE_PROTOBUF_VERSION < 3004000
#error This file was generated by a newer version of protoc which is
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
#if 3004000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.
#endif
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/arena.h>
#include <google/protobuf/arenastring.h>
#include <google/protobuf/generated_message_table_driven.h>
#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/metadata.h>
#include <google/protobuf/repeated_field.h> // IWYU pragma: export
#include <google/protobuf/extension_set.h> // IWYU pragma: export
// @@protoc_insertion_point(includes)
namespace community {
} // namespace community
namespace community {
namespace protobuf_character_2eproto {
// Internal implementation detail -- do not call these.
struct TableStruct {
static const ::google::protobuf::internal::ParseTableField entries[];
static const ::google::protobuf::internal::AuxillaryParseTableField aux[];
static const ::google::protobuf::internal::ParseTable schema[];
static const ::google::protobuf::uint32 offsets[];
static const ::google::protobuf::internal::FieldMetadata field_metadata[];
static const ::google::protobuf::internal::SerializationTable serialization_table[];
static void InitDefaultsImpl();
};
void AddDescriptors();
void InitDefaults();
} // namespace protobuf_character_2eproto
// ===================================================================
// ===================================================================
// ===================================================================
#if !PROTOBUF_INLINE_NOT_IN_HEADERS
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif // __GNUC__
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif // __GNUC__
#endif // !PROTOBUF_INLINE_NOT_IN_HEADERS
// @@protoc_insertion_point(namespace_scope)
} // namespace community
// @@protoc_insertion_point(global_scope)
#endif // PROTOBUF_character_2eproto__INCLUDED

View File

@ -0,0 +1,410 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: container.proto
#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
#include "container.pb.h"
#include <algorithm>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/port.h>
#include <google/protobuf/stubs/once.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/wire_format_lite_inl.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/generated_message_reflection.h>
#include <google/protobuf/reflection_ops.h>
#include <google/protobuf/wire_format.h>
// @@protoc_insertion_point(includes)
namespace community {
class MessageContainerDefaultTypeInternal {
public:
::google::protobuf::internal::ExplicitlyConstructed<MessageContainer>
_instance;
} _MessageContainer_default_instance_;
namespace protobuf_container_2eproto {
namespace {
::google::protobuf::Metadata file_level_metadata[1];
} // namespace
PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::ParseTableField
const TableStruct::entries[] GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
{0, 0, 0, ::google::protobuf::internal::kInvalidMask, 0, 0},
};
PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::AuxillaryParseTableField
const TableStruct::aux[] GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
::google::protobuf::internal::AuxillaryParseTableField(),
};
PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::ParseTable const
TableStruct::schema[] GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
{ NULL, NULL, 0, -1, -1, -1, -1, NULL, false },
};
const ::google::protobuf::uint32 TableStruct::offsets[] GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
~0u, // no _has_bits_
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageContainer, _internal_metadata_),
~0u, // no _extensions_
~0u, // no _oneof_case_
~0u, // no _weak_field_map_
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageContainer, message_),
};
static const ::google::protobuf::internal::MigrationSchema schemas[] GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
{ 0, -1, sizeof(MessageContainer)},
};
static ::google::protobuf::Message const * const file_default_instances[] = {
reinterpret_cast<const ::google::protobuf::Message*>(&_MessageContainer_default_instance_),
};
namespace {
void protobuf_AssignDescriptors() {
AddDescriptors();
::google::protobuf::MessageFactory* factory = NULL;
AssignDescriptors(
"container.proto", schemas, file_default_instances, TableStruct::offsets, factory,
file_level_metadata, NULL, NULL);
}
void protobuf_AssignDescriptorsOnce() {
static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
::google::protobuf::GoogleOnceInit(&once, &protobuf_AssignDescriptors);
}
void protobuf_RegisterTypes(const ::std::string&) GOOGLE_ATTRIBUTE_COLD;
void protobuf_RegisterTypes(const ::std::string&) {
protobuf_AssignDescriptorsOnce();
::google::protobuf::internal::RegisterAllTypes(file_level_metadata, 1);
}
} // namespace
void TableStruct::InitDefaultsImpl() {
GOOGLE_PROTOBUF_VERIFY_VERSION;
::google::protobuf::internal::InitProtobufDefaults();
::google::protobuf::protobuf_google_2fprotobuf_2fany_2eproto::InitDefaults();
_MessageContainer_default_instance_._instance.DefaultConstruct();
::google::protobuf::internal::OnShutdownDestroyMessage(
&_MessageContainer_default_instance_);}
void InitDefaults() {
static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
::google::protobuf::GoogleOnceInit(&once, &TableStruct::InitDefaultsImpl);
}
namespace {
void AddDescriptorsImpl() {
InitDefaults();
static const char descriptor[] GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
"\n\017container.proto\022\tcommunity\032\031google/pro"
"tobuf/any.proto\"9\n\020MessageContainer\022%\n\007m"
"essage\030\001 \003(\0132\024.google.protobuf.Anyb\006prot"
"o3"
};
::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
descriptor, 122);
::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
"container.proto", &protobuf_RegisterTypes);
::google::protobuf::protobuf_google_2fprotobuf_2fany_2eproto::AddDescriptors();
}
} // anonymous namespace
void AddDescriptors() {
static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
::google::protobuf::GoogleOnceInit(&once, &AddDescriptorsImpl);
}
// Force AddDescriptors() to be called at dynamic initialization time.
struct StaticDescriptorInitializer {
StaticDescriptorInitializer() {
AddDescriptors();
}
} static_descriptor_initializer;
} // namespace protobuf_container_2eproto
// ===================================================================
#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int MessageContainer::kMessageFieldNumber;
#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
MessageContainer::MessageContainer()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
if (GOOGLE_PREDICT_TRUE(this != internal_default_instance())) {
protobuf_container_2eproto::InitDefaults();
}
SharedCtor();
// @@protoc_insertion_point(constructor:community.MessageContainer)
}
MessageContainer::MessageContainer(const MessageContainer& from)
: ::google::protobuf::Message(),
_internal_metadata_(NULL),
message_(from.message_),
_cached_size_(0) {
_internal_metadata_.MergeFrom(from._internal_metadata_);
// @@protoc_insertion_point(copy_constructor:community.MessageContainer)
}
void MessageContainer::SharedCtor() {
_cached_size_ = 0;
}
MessageContainer::~MessageContainer() {
// @@protoc_insertion_point(destructor:community.MessageContainer)
SharedDtor();
}
void MessageContainer::SharedDtor() {
}
void MessageContainer::SetCachedSize(int size) const {
GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
_cached_size_ = size;
GOOGLE_SAFE_CONCURRENT_WRITES_END();
}
const ::google::protobuf::Descriptor* MessageContainer::descriptor() {
protobuf_container_2eproto::protobuf_AssignDescriptorsOnce();
return protobuf_container_2eproto::file_level_metadata[kIndexInFileMessages].descriptor;
}
const MessageContainer& MessageContainer::default_instance() {
protobuf_container_2eproto::InitDefaults();
return *internal_default_instance();
}
MessageContainer* MessageContainer::New(::google::protobuf::Arena* arena) const {
MessageContainer* n = new MessageContainer;
if (arena != NULL) {
arena->Own(n);
}
return n;
}
void MessageContainer::Clear() {
// @@protoc_insertion_point(message_clear_start:community.MessageContainer)
::google::protobuf::uint32 cached_has_bits = 0;
// Prevent compiler warnings about cached_has_bits being unused
(void) cached_has_bits;
message_.Clear();
_internal_metadata_.Clear();
}
bool MessageContainer::MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input) {
#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
::google::protobuf::uint32 tag;
// @@protoc_insertion_point(parse_start:community.MessageContainer)
for (;;) {
::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoffNoLastTag(127u);
tag = p.first;
if (!p.second) goto handle_unusual;
switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
// repeated .google.protobuf.Any message = 1;
case 1: {
if (static_cast< ::google::protobuf::uint8>(tag) ==
static_cast< ::google::protobuf::uint8>(10u /* 10 & 0xFF */)) {
DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
input, add_message()));
} else {
goto handle_unusual;
}
break;
}
default: {
handle_unusual:
if (tag == 0) {
goto success;
}
DO_(::google::protobuf::internal::WireFormat::SkipField(
input, tag, _internal_metadata_.mutable_unknown_fields()));
break;
}
}
}
success:
// @@protoc_insertion_point(parse_success:community.MessageContainer)
return true;
failure:
// @@protoc_insertion_point(parse_failure:community.MessageContainer)
return false;
#undef DO_
}
void MessageContainer::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
// @@protoc_insertion_point(serialize_start:community.MessageContainer)
::google::protobuf::uint32 cached_has_bits = 0;
(void) cached_has_bits;
// repeated .google.protobuf.Any message = 1;
for (unsigned int i = 0,
n = static_cast<unsigned int>(this->message_size()); i < n; i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
1, this->message(static_cast<int>(i)), output);
}
if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
(::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance()), output);
}
// @@protoc_insertion_point(serialize_end:community.MessageContainer)
}
::google::protobuf::uint8* MessageContainer::InternalSerializeWithCachedSizesToArray(
bool deterministic, ::google::protobuf::uint8* target) const {
(void)deterministic; // Unused
// @@protoc_insertion_point(serialize_to_array_start:community.MessageContainer)
::google::protobuf::uint32 cached_has_bits = 0;
(void) cached_has_bits;
// repeated .google.protobuf.Any message = 1;
for (unsigned int i = 0,
n = static_cast<unsigned int>(this->message_size()); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
InternalWriteMessageNoVirtualToArray(
1, this->message(static_cast<int>(i)), deterministic, target);
}
if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
(::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance()), target);
}
// @@protoc_insertion_point(serialize_to_array_end:community.MessageContainer)
return target;
}
size_t MessageContainer::ByteSizeLong() const {
// @@protoc_insertion_point(message_byte_size_start:community.MessageContainer)
size_t total_size = 0;
if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
(::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance()));
}
// repeated .google.protobuf.Any message = 1;
{
unsigned int count = static_cast<unsigned int>(this->message_size());
total_size += 1UL * count;
for (unsigned int i = 0; i < count; i++) {
total_size +=
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->message(static_cast<int>(i)));
}
}
int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
_cached_size_ = cached_size;
GOOGLE_SAFE_CONCURRENT_WRITES_END();
return total_size;
}
void MessageContainer::MergeFrom(const ::google::protobuf::Message& from) {
// @@protoc_insertion_point(generalized_merge_from_start:community.MessageContainer)
GOOGLE_DCHECK_NE(&from, this);
const MessageContainer* source =
::google::protobuf::internal::DynamicCastToGenerated<const MessageContainer>(
&from);
if (source == NULL) {
// @@protoc_insertion_point(generalized_merge_from_cast_fail:community.MessageContainer)
::google::protobuf::internal::ReflectionOps::Merge(from, this);
} else {
// @@protoc_insertion_point(generalized_merge_from_cast_success:community.MessageContainer)
MergeFrom(*source);
}
}
void MessageContainer::MergeFrom(const MessageContainer& from) {
// @@protoc_insertion_point(class_specific_merge_from_start:community.MessageContainer)
GOOGLE_DCHECK_NE(&from, this);
_internal_metadata_.MergeFrom(from._internal_metadata_);
::google::protobuf::uint32 cached_has_bits = 0;
(void) cached_has_bits;
message_.MergeFrom(from.message_);
}
void MessageContainer::CopyFrom(const ::google::protobuf::Message& from) {
// @@protoc_insertion_point(generalized_copy_from_start:community.MessageContainer)
if (&from == this) return;
Clear();
MergeFrom(from);
}
void MessageContainer::CopyFrom(const MessageContainer& from) {
// @@protoc_insertion_point(class_specific_copy_from_start:community.MessageContainer)
if (&from == this) return;
Clear();
MergeFrom(from);
}
bool MessageContainer::IsInitialized() const {
return true;
}
void MessageContainer::Swap(MessageContainer* other) {
if (other == this) return;
InternalSwap(other);
}
void MessageContainer::InternalSwap(MessageContainer* other) {
using std::swap;
message_.InternalSwap(&other->message_);
_internal_metadata_.Swap(&other->_internal_metadata_);
swap(_cached_size_, other->_cached_size_);
}
::google::protobuf::Metadata MessageContainer::GetMetadata() const {
protobuf_container_2eproto::protobuf_AssignDescriptorsOnce();
return protobuf_container_2eproto::file_level_metadata[kIndexInFileMessages];
}
#if PROTOBUF_INLINE_NOT_IN_HEADERS
// MessageContainer
// repeated .google.protobuf.Any message = 1;
int MessageContainer::message_size() const {
return message_.size();
}
void MessageContainer::clear_message() {
message_.Clear();
}
const ::google::protobuf::Any& MessageContainer::message(int index) const {
// @@protoc_insertion_point(field_get:community.MessageContainer.message)
return message_.Get(index);
}
::google::protobuf::Any* MessageContainer::mutable_message(int index) {
// @@protoc_insertion_point(field_mutable:community.MessageContainer.message)
return message_.Mutable(index);
}
::google::protobuf::Any* MessageContainer::add_message() {
// @@protoc_insertion_point(field_add:community.MessageContainer.message)
return message_.Add();
}
::google::protobuf::RepeatedPtrField< ::google::protobuf::Any >*
MessageContainer::mutable_message() {
// @@protoc_insertion_point(field_mutable_list:community.MessageContainer.message)
return &message_;
}
const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Any >&
MessageContainer::message() const {
// @@protoc_insertion_point(field_list:community.MessageContainer.message)
return message_;
}
#endif // PROTOBUF_INLINE_NOT_IN_HEADERS
// @@protoc_insertion_point(namespace_scope)
} // namespace community
// @@protoc_insertion_point(global_scope)

View File

@ -0,0 +1,214 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: container.proto
#ifndef PROTOBUF_container_2eproto__INCLUDED
#define PROTOBUF_container_2eproto__INCLUDED
#include <string>
#include <google/protobuf/stubs/common.h>
#if GOOGLE_PROTOBUF_VERSION < 3004000
#error This file was generated by a newer version of protoc which is
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
#if 3004000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.
#endif
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/arena.h>
#include <google/protobuf/arenastring.h>
#include <google/protobuf/generated_message_table_driven.h>
#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/metadata.h>
#include <google/protobuf/message.h>
#include <google/protobuf/repeated_field.h> // IWYU pragma: export
#include <google/protobuf/extension_set.h> // IWYU pragma: export
#include <google/protobuf/unknown_field_set.h>
#include <google/protobuf/any.pb.h>
// @@protoc_insertion_point(includes)
namespace community {
class MessageContainer;
class MessageContainerDefaultTypeInternal;
extern MessageContainerDefaultTypeInternal _MessageContainer_default_instance_;
} // namespace community
namespace community {
namespace protobuf_container_2eproto {
// Internal implementation detail -- do not call these.
struct TableStruct {
static const ::google::protobuf::internal::ParseTableField entries[];
static const ::google::protobuf::internal::AuxillaryParseTableField aux[];
static const ::google::protobuf::internal::ParseTable schema[];
static const ::google::protobuf::uint32 offsets[];
static const ::google::protobuf::internal::FieldMetadata field_metadata[];
static const ::google::protobuf::internal::SerializationTable serialization_table[];
static void InitDefaultsImpl();
};
void AddDescriptors();
void InitDefaults();
} // namespace protobuf_container_2eproto
// ===================================================================
class MessageContainer : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:community.MessageContainer) */ {
public:
MessageContainer();
virtual ~MessageContainer();
MessageContainer(const MessageContainer& from);
inline MessageContainer& operator=(const MessageContainer& from) {
CopyFrom(from);
return *this;
}
#if LANG_CXX11
MessageContainer(MessageContainer&& from) noexcept
: MessageContainer() {
*this = ::std::move(from);
}
inline MessageContainer& operator=(MessageContainer&& from) noexcept {
if (GetArenaNoVirtual() == from.GetArenaNoVirtual()) {
if (this != &from) InternalSwap(&from);
} else {
CopyFrom(from);
}
return *this;
}
#endif
static const ::google::protobuf::Descriptor* descriptor();
static const MessageContainer& default_instance();
static inline const MessageContainer* internal_default_instance() {
return reinterpret_cast<const MessageContainer*>(
&_MessageContainer_default_instance_);
}
static PROTOBUF_CONSTEXPR int const kIndexInFileMessages =
0;
void Swap(MessageContainer* other);
friend void swap(MessageContainer& a, MessageContainer& b) {
a.Swap(&b);
}
// implements Message ----------------------------------------------
inline MessageContainer* New() const PROTOBUF_FINAL { return New(NULL); }
MessageContainer* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL;
void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
void CopyFrom(const MessageContainer& from);
void MergeFrom(const MessageContainer& from);
void Clear() PROTOBUF_FINAL;
bool IsInitialized() const PROTOBUF_FINAL;
size_t ByteSizeLong() const PROTOBUF_FINAL;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input) PROTOBUF_FINAL;
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const PROTOBUF_FINAL;
::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
bool deterministic, ::google::protobuf::uint8* target) const PROTOBUF_FINAL;
int GetCachedSize() const PROTOBUF_FINAL { return _cached_size_; }
private:
void SharedCtor();
void SharedDtor();
void SetCachedSize(int size) const PROTOBUF_FINAL;
void InternalSwap(MessageContainer* other);
private:
inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
return NULL;
}
inline void* MaybeArenaPtr() const {
return NULL;
}
public:
::google::protobuf::Metadata GetMetadata() const PROTOBUF_FINAL;
// nested types ----------------------------------------------------
// accessors -------------------------------------------------------
// repeated .google.protobuf.Any message = 1;
int message_size() const;
void clear_message();
static const int kMessageFieldNumber = 1;
const ::google::protobuf::Any& message(int index) const;
::google::protobuf::Any* mutable_message(int index);
::google::protobuf::Any* add_message();
::google::protobuf::RepeatedPtrField< ::google::protobuf::Any >*
mutable_message();
const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Any >&
message() const;
// @@protoc_insertion_point(class_scope:community.MessageContainer)
private:
::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
::google::protobuf::RepeatedPtrField< ::google::protobuf::Any > message_;
mutable int _cached_size_;
friend struct protobuf_container_2eproto::TableStruct;
};
// ===================================================================
// ===================================================================
#if !PROTOBUF_INLINE_NOT_IN_HEADERS
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif // __GNUC__
// MessageContainer
// repeated .google.protobuf.Any message = 1;
inline int MessageContainer::message_size() const {
return message_.size();
}
inline void MessageContainer::clear_message() {
message_.Clear();
}
inline const ::google::protobuf::Any& MessageContainer::message(int index) const {
// @@protoc_insertion_point(field_get:community.MessageContainer.message)
return message_.Get(index);
}
inline ::google::protobuf::Any* MessageContainer::mutable_message(int index) {
// @@protoc_insertion_point(field_mutable:community.MessageContainer.message)
return message_.Mutable(index);
}
inline ::google::protobuf::Any* MessageContainer::add_message() {
// @@protoc_insertion_point(field_add:community.MessageContainer.message)
return message_.Add();
}
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::Any >*
MessageContainer::mutable_message() {
// @@protoc_insertion_point(field_mutable_list:community.MessageContainer.message)
return &message_;
}
inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Any >&
MessageContainer::message() const {
// @@protoc_insertion_point(field_list:community.MessageContainer.message)
return message_;
}
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif // __GNUC__
#endif // !PROTOBUF_INLINE_NOT_IN_HEADERS
// @@protoc_insertion_point(namespace_scope)
} // namespace community
// @@protoc_insertion_point(global_scope)
#endif // PROTOBUF_container_2eproto__INCLUDED

View File

@ -0,0 +1,109 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: world.proto
#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
#include "world.pb.h"
#include <algorithm>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/port.h>
#include <google/protobuf/stubs/once.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/wire_format_lite_inl.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/generated_message_reflection.h>
#include <google/protobuf/reflection_ops.h>
#include <google/protobuf/wire_format.h>
// @@protoc_insertion_point(includes)
namespace community {
namespace protobuf_world_2eproto {
namespace {
} // namespace
PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::ParseTableField
const TableStruct::entries[] GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
{0, 0, 0, ::google::protobuf::internal::kInvalidMask, 0, 0},
};
PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::AuxillaryParseTableField
const TableStruct::aux[] GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
::google::protobuf::internal::AuxillaryParseTableField(),
};
PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::ParseTable const
TableStruct::schema[] GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
{ NULL, NULL, 0, -1, -1, -1, -1, NULL, false },
};
const ::google::protobuf::uint32 TableStruct::offsets[1] = {};
static const ::google::protobuf::internal::MigrationSchema* schemas = NULL;
static const ::google::protobuf::Message* const* file_default_instances = NULL;
namespace {
void protobuf_AssignDescriptors() {
AddDescriptors();
::google::protobuf::MessageFactory* factory = NULL;
AssignDescriptors(
"world.proto", schemas, file_default_instances, TableStruct::offsets, factory,
NULL, NULL, NULL);
}
void protobuf_AssignDescriptorsOnce() {
static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
::google::protobuf::GoogleOnceInit(&once, &protobuf_AssignDescriptors);
}
void protobuf_RegisterTypes(const ::std::string&) GOOGLE_ATTRIBUTE_COLD;
void protobuf_RegisterTypes(const ::std::string&) {
protobuf_AssignDescriptorsOnce();
}
} // namespace
void TableStruct::InitDefaultsImpl() {
GOOGLE_PROTOBUF_VERIFY_VERSION;
::google::protobuf::internal::InitProtobufDefaults();
}
void InitDefaults() {
static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
::google::protobuf::GoogleOnceInit(&once, &TableStruct::InitDefaultsImpl);
}
namespace {
void AddDescriptorsImpl() {
InitDefaults();
static const char descriptor[] GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
"\n\013world.proto\022\tcommunityb\006proto3"
};
::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
descriptor, 32);
::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
"world.proto", &protobuf_RegisterTypes);
}
} // anonymous namespace
void AddDescriptors() {
static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
::google::protobuf::GoogleOnceInit(&once, &AddDescriptorsImpl);
}
// Force AddDescriptors() to be called at dynamic initialization time.
struct StaticDescriptorInitializer {
StaticDescriptorInitializer() {
AddDescriptors();
}
} static_descriptor_initializer;
} // namespace protobuf_world_2eproto
// @@protoc_insertion_point(namespace_scope)
} // namespace community
// @@protoc_insertion_point(global_scope)

View File

@ -0,0 +1,76 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: world.proto
#ifndef PROTOBUF_world_2eproto__INCLUDED
#define PROTOBUF_world_2eproto__INCLUDED
#include <string>
#include <google/protobuf/stubs/common.h>
#if GOOGLE_PROTOBUF_VERSION < 3004000
#error This file was generated by a newer version of protoc which is
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
#if 3004000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.
#endif
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/arena.h>
#include <google/protobuf/arenastring.h>
#include <google/protobuf/generated_message_table_driven.h>
#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/metadata.h>
#include <google/protobuf/repeated_field.h> // IWYU pragma: export
#include <google/protobuf/extension_set.h> // IWYU pragma: export
// @@protoc_insertion_point(includes)
namespace community {
} // namespace community
namespace community {
namespace protobuf_world_2eproto {
// Internal implementation detail -- do not call these.
struct TableStruct {
static const ::google::protobuf::internal::ParseTableField entries[];
static const ::google::protobuf::internal::AuxillaryParseTableField aux[];
static const ::google::protobuf::internal::ParseTable schema[];
static const ::google::protobuf::uint32 offsets[];
static const ::google::protobuf::internal::FieldMetadata field_metadata[];
static const ::google::protobuf::internal::SerializationTable serialization_table[];
static void InitDefaultsImpl();
};
void AddDescriptors();
void InitDefaults();
} // namespace protobuf_world_2eproto
// ===================================================================
// ===================================================================
// ===================================================================
#if !PROTOBUF_INLINE_NOT_IN_HEADERS
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif // __GNUC__
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif // __GNUC__
#endif // !PROTOBUF_INLINE_NOT_IN_HEADERS
// @@protoc_insertion_point(namespace_scope)
} // namespace community
// @@protoc_insertion_point(global_scope)
#endif // PROTOBUF_world_2eproto__INCLUDED

View File

@ -0,0 +1,6 @@
#!/bin/bash
Msys2Path='C:\\msys64\\mingw64\\bin'
args=' --proto_path=../ --cpp_out=../GenCode ../*.proto'
exec ../GenTools/protoc.exe $args #// for local compile on windows
pause

View File

@ -0,0 +1,6 @@
#!/bin/bash
Msys2Path='C:\\msys64\\mingw64\\bin'
args=' --proto_path=../ --cpp_out=../GenCode ../*.proto'
exec $Msys2Path'\\'protoc.exe $args
pause

View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1827ffcf3ef3827ae7f9f4e6189cd88c0ecd9fb01e87c507273844321f42e60c
size 394806

View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:88d99ad5e98290bd27d6c7bec4f1303a2cc6924f565e3644a01aac60bf9b04bd
size 2461906

View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a2ab3641bfc9badfa3365f80305eb051648ce6bc3044a2c2df1bcd32bb508bea
size 2564731

View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4505e4a3643d761e760d7ead2c2492cc9461ce532bd51b8f2c486902bdf0e8d3
size 30157

View File

@ -0,0 +1,8 @@
syntax = "proto3";
package community;
message Login {
string username = 1;
string password = 2;
}

View File

@ -0,0 +1,3 @@
syntax = "proto3";
package community;

View File

@ -0,0 +1,10 @@
syntax = "proto3";
import "google/protobuf/any.proto";
package community;
message MessageContainer
{
repeated google.protobuf.Any message = 1;
}

View File

@ -0,0 +1,123 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <google/protobuf/any.h>
#include <google/protobuf/generated_message_util.h>
namespace google {
namespace protobuf {
namespace internal {
namespace {
string GetTypeUrl(const Descriptor* message,
const string& type_url_prefix) {
if (!type_url_prefix.empty() &&
type_url_prefix[type_url_prefix.size() - 1] == '/') {
return type_url_prefix + message->full_name();
} else {
return type_url_prefix + "/" + message->full_name();
}
}
} // namespace
const char kAnyFullTypeName[] = "google.protobuf.Any";
const char kTypeGoogleApisComPrefix[] = "type.googleapis.com/";
const char kTypeGoogleProdComPrefix[] = "type.googleprod.com/";
AnyMetadata::AnyMetadata(UrlType* type_url, ValueType* value)
: type_url_(type_url), value_(value) {
}
void AnyMetadata::PackFrom(const Message& message) {
PackFrom(message, kTypeGoogleApisComPrefix);
}
void AnyMetadata::PackFrom(const Message& message,
const string& type_url_prefix) {
type_url_->SetNoArena(&::google::protobuf::internal::GetEmptyString(),
GetTypeUrl(message.GetDescriptor(), type_url_prefix));
message.SerializeToString(value_->MutableNoArena(
&::google::protobuf::internal::GetEmptyStringAlreadyInited()));
}
bool AnyMetadata::UnpackTo(Message* message) const {
if (!InternalIs(message->GetDescriptor())) {
return false;
}
return message->ParseFromString(value_->GetNoArena());
}
bool AnyMetadata::InternalIs(const Descriptor* descriptor) const {
const string type_url = type_url_->GetNoArena();
string full_name;
if (!ParseAnyTypeUrl(type_url, &full_name)) {
return false;
}
return full_name == descriptor->full_name();
}
bool ParseAnyTypeUrl(const string& type_url, string* url_prefix,
string* full_type_name) {
size_t pos = type_url.find_last_of("/");
if (pos == string::npos || pos + 1 == type_url.size()) {
return false;
}
if (url_prefix) {
*url_prefix = type_url.substr(0, pos + 1);
}
*full_type_name = type_url.substr(pos + 1);
return true;
}
bool ParseAnyTypeUrl(const string& type_url, string* full_type_name) {
return ParseAnyTypeUrl(type_url, NULL, full_type_name);
}
bool GetAnyFieldDescriptors(const Message& message,
const FieldDescriptor** type_url_field,
const FieldDescriptor** value_field) {
const Descriptor* descriptor = message.GetDescriptor();
if (descriptor->full_name() != kAnyFullTypeName) {
return false;
}
*type_url_field = descriptor->FindFieldByNumber(1);
*value_field = descriptor->FindFieldByNumber(2);
return (*type_url_field != NULL &&
(*type_url_field)->type() == FieldDescriptor::TYPE_STRING &&
*value_field != NULL &&
(*value_field)->type() == FieldDescriptor::TYPE_BYTES);
}
} // namespace internal
} // namespace protobuf
} // namespace google

View File

@ -0,0 +1,118 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef GOOGLE_PROTOBUF_ANY_H__
#define GOOGLE_PROTOBUF_ANY_H__
#include <string>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/message.h>
#include <google/protobuf/arenastring.h>
namespace google {
namespace protobuf {
namespace internal {
// Helper class used to implement google::protobuf::Any.
class LIBPROTOBUF_EXPORT AnyMetadata {
typedef ArenaStringPtr UrlType;
typedef ArenaStringPtr ValueType;
public:
// AnyMetadata does not take ownership of "type_url" and "value".
AnyMetadata(UrlType* type_url, ValueType* value);
// Packs a message using the default type URL prefix: "type.googleapis.com".
// The resulted type URL will be "type.googleapis.com/<message_full_name>".
void PackFrom(const Message& message);
// Packs a message using the given type URL prefix. The type URL will be
// constructed by concatenating the message type's full name to the prefix
// with an optional "/" separator if the prefix doesn't already end up "/".
// For example, both PackFrom(message, "type.googleapis.com") and
// PackFrom(message, "type.googleapis.com/") yield the same result type
// URL: "type.googleapis.com/<message_full_name>".
void PackFrom(const Message& message, const string& type_url_prefix);
// Unpacks the payload into the given message. Returns false if the message's
// type doesn't match the type specified in the type URL (i.e., the full
// name after the last "/" of the type URL doesn't match the message's actual
// full name) or parsing the payload has failed.
bool UnpackTo(Message* message) const;
// Checks whether the type specified in the type URL matches the given type.
// A type is consdiered matching if its full name matches the full name after
// the last "/" in the type URL.
template<typename T>
bool Is() const {
return InternalIs(T::default_instance().GetDescriptor());
}
private:
bool InternalIs(const Descriptor* message) const;
UrlType* type_url_;
ValueType* value_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(AnyMetadata);
};
extern const char kAnyFullTypeName[]; // "google.protobuf.Any".
extern const char kTypeGoogleApisComPrefix[]; // "type.googleapis.com/".
extern const char kTypeGoogleProdComPrefix[]; // "type.googleprod.com/".
// Get the proto type name from Any::type_url value. For example, passing
// "type.googleapis.com/rpc.QueryOrigin" will return "rpc.QueryOrigin" in
// *full_type_name. Returns false if the type_url does not have a "/"
// in the type url separating the full type name.
//
// NOTE: this function is available publicly as:
// google::protobuf::Any() // static method on the generated message type.
bool ParseAnyTypeUrl(const string& type_url, string* full_type_name);
// Get the proto type name and prefix from Any::type_url value. For example,
// passing "type.googleapis.com/rpc.QueryOrigin" will return
// "type.googleapis.com/" in *url_prefix and "rpc.QueryOrigin" in
// *full_type_name. Returns false if the type_url does not have a "/" in the
// type url separating the full type name.
bool ParseAnyTypeUrl(const string& type_url, string* url_prefix,
string* full_type_name);
// See if message is of type google.protobuf.Any, if so, return the descriptors
// for "type_url" and "value" fields.
bool GetAnyFieldDescriptors(const Message& message,
const FieldDescriptor** type_url_field,
const FieldDescriptor** value_field);
} // namespace internal
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_ANY_H__

View File

@ -0,0 +1,435 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: google/protobuf/any.proto
#include <google/protobuf/any.pb.h>
#include <algorithm>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/port.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/wire_format_lite_inl.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/generated_message_reflection.h>
#include <google/protobuf/reflection_ops.h>
#include <google/protobuf/wire_format.h>
// This is a temporary google only hack
#ifdef GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS
#include "third_party/protobuf/version.h"
#endif
// @@protoc_insertion_point(includes)
namespace google {
namespace protobuf {
class AnyDefaultTypeInternal {
public:
::google::protobuf::internal::ExplicitlyConstructed<Any>
_instance;
} _Any_default_instance_;
} // namespace protobuf
} // namespace google
namespace protobuf_google_2fprotobuf_2fany_2eproto {
static void InitDefaultsAny() {
GOOGLE_PROTOBUF_VERIFY_VERSION;
{
void* ptr = &::google::protobuf::_Any_default_instance_;
new (ptr) ::google::protobuf::Any();
::google::protobuf::internal::OnShutdownDestroyMessage(ptr);
}
::google::protobuf::Any::InitAsDefaultInstance();
}
LIBPROTOBUF_EXPORT ::google::protobuf::internal::SCCInfo<0> scc_info_Any =
{{ATOMIC_VAR_INIT(::google::protobuf::internal::SCCInfoBase::kUninitialized), 0, InitDefaultsAny}, {}};
void InitDefaults() {
::google::protobuf::internal::InitSCC(&scc_info_Any.base);
}
::google::protobuf::Metadata file_level_metadata[1];
const ::google::protobuf::uint32 TableStruct::offsets[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
~0u, // no _has_bits_
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::google::protobuf::Any, _internal_metadata_),
~0u, // no _extensions_
~0u, // no _oneof_case_
~0u, // no _weak_field_map_
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::google::protobuf::Any, type_url_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::google::protobuf::Any, value_),
};
static const ::google::protobuf::internal::MigrationSchema schemas[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
{ 0, -1, sizeof(::google::protobuf::Any)},
};
static ::google::protobuf::Message const * const file_default_instances[] = {
reinterpret_cast<const ::google::protobuf::Message*>(&::google::protobuf::_Any_default_instance_),
};
void protobuf_AssignDescriptors() {
AddDescriptors();
AssignDescriptors(
"google/protobuf/any.proto", schemas, file_default_instances, TableStruct::offsets,
file_level_metadata, NULL, NULL);
}
void protobuf_AssignDescriptorsOnce() {
static ::google::protobuf::internal::once_flag once;
::google::protobuf::internal::call_once(once, protobuf_AssignDescriptors);
}
void protobuf_RegisterTypes(const ::std::string&) GOOGLE_PROTOBUF_ATTRIBUTE_COLD;
void protobuf_RegisterTypes(const ::std::string&) {
protobuf_AssignDescriptorsOnce();
::google::protobuf::internal::RegisterAllTypes(file_level_metadata, 1);
}
void AddDescriptorsImpl() {
InitDefaults();
static const char descriptor[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
"\n\031google/protobuf/any.proto\022\017google.prot"
"obuf\"&\n\003Any\022\020\n\010type_url\030\001 \001(\t\022\r\n\005value\030\002"
" \001(\014Bo\n\023com.google.protobufB\010AnyProtoP\001Z"
"%github.com/golang/protobuf/ptypes/any\242\002"
"\003GPB\252\002\036Google.Protobuf.WellKnownTypesb\006p"
"roto3"
};
::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
descriptor, 205);
::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
"google/protobuf/any.proto", &protobuf_RegisterTypes);
}
void AddDescriptors() {
static ::google::protobuf::internal::once_flag once;
::google::protobuf::internal::call_once(once, AddDescriptorsImpl);
}
// Force AddDescriptors() to be called at dynamic initialization time.
struct StaticDescriptorInitializer {
StaticDescriptorInitializer() {
AddDescriptors();
}
} static_descriptor_initializer;
} // namespace protobuf_google_2fprotobuf_2fany_2eproto
namespace google {
namespace protobuf {
// ===================================================================
void Any::InitAsDefaultInstance() {
}
void Any::PackFrom(const ::google::protobuf::Message& message) {
_any_metadata_.PackFrom(message);
}
void Any::PackFrom(const ::google::protobuf::Message& message,
const ::std::string& type_url_prefix) {
_any_metadata_.PackFrom(message, type_url_prefix);
}
bool Any::UnpackTo(::google::protobuf::Message* message) const {
return _any_metadata_.UnpackTo(message);
}
bool Any::ParseAnyTypeUrl(const string& type_url,
string* full_type_name) {
return ::google::protobuf::internal::ParseAnyTypeUrl(type_url,
full_type_name);
}
#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int Any::kTypeUrlFieldNumber;
const int Any::kValueFieldNumber;
#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
Any::Any()
: ::google::protobuf::Message(), _internal_metadata_(NULL), _any_metadata_(&type_url_, &value_) {
::google::protobuf::internal::InitSCC(
&protobuf_google_2fprotobuf_2fany_2eproto::scc_info_Any.base);
SharedCtor();
// @@protoc_insertion_point(constructor:google.protobuf.Any)
}
Any::Any(const Any& from)
: ::google::protobuf::Message(),
_internal_metadata_(NULL),
_any_metadata_(&type_url_, &value_) {
_internal_metadata_.MergeFrom(from._internal_metadata_);
type_url_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
if (from.type_url().size() > 0) {
type_url_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.type_url_);
}
value_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
if (from.value().size() > 0) {
value_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.value_);
}
// @@protoc_insertion_point(copy_constructor:google.protobuf.Any)
}
void Any::SharedCtor() {
type_url_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
value_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
Any::~Any() {
// @@protoc_insertion_point(destructor:google.protobuf.Any)
SharedDtor();
}
void Any::SharedDtor() {
type_url_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
value_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
void Any::SetCachedSize(int size) const {
_cached_size_.Set(size);
}
const ::google::protobuf::Descriptor* Any::descriptor() {
::protobuf_google_2fprotobuf_2fany_2eproto::protobuf_AssignDescriptorsOnce();
return ::protobuf_google_2fprotobuf_2fany_2eproto::file_level_metadata[kIndexInFileMessages].descriptor;
}
const Any& Any::default_instance() {
::google::protobuf::internal::InitSCC(&protobuf_google_2fprotobuf_2fany_2eproto::scc_info_Any.base);
return *internal_default_instance();
}
void Any::Clear() {
// @@protoc_insertion_point(message_clear_start:google.protobuf.Any)
::google::protobuf::uint32 cached_has_bits = 0;
// Prevent compiler warnings about cached_has_bits being unused
(void) cached_has_bits;
type_url_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
_internal_metadata_.Clear();
}
bool Any::MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input) {
#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
::google::protobuf::uint32 tag;
// @@protoc_insertion_point(parse_start:google.protobuf.Any)
for (;;) {
::std::pair<::google::protobuf::uint32, bool> p = input->ReadTagWithCutoffNoLastTag(127u);
tag = p.first;
if (!p.second) goto handle_unusual;
switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
// string type_url = 1;
case 1: {
if (static_cast< ::google::protobuf::uint8>(tag) ==
static_cast< ::google::protobuf::uint8>(10u /* 10 & 0xFF */)) {
DO_(::google::protobuf::internal::WireFormatLite::ReadString(
input, this->mutable_type_url()));
DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
this->type_url().data(), static_cast<int>(this->type_url().length()),
::google::protobuf::internal::WireFormatLite::PARSE,
"google.protobuf.Any.type_url"));
} else {
goto handle_unusual;
}
break;
}
// bytes value = 2;
case 2: {
if (static_cast< ::google::protobuf::uint8>(tag) ==
static_cast< ::google::protobuf::uint8>(18u /* 18 & 0xFF */)) {
DO_(::google::protobuf::internal::WireFormatLite::ReadBytes(
input, this->mutable_value()));
} else {
goto handle_unusual;
}
break;
}
default: {
handle_unusual:
if (tag == 0) {
goto success;
}
DO_(::google::protobuf::internal::WireFormat::SkipField(
input, tag, _internal_metadata_.mutable_unknown_fields()));
break;
}
}
}
success:
// @@protoc_insertion_point(parse_success:google.protobuf.Any)
return true;
failure:
// @@protoc_insertion_point(parse_failure:google.protobuf.Any)
return false;
#undef DO_
}
void Any::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
// @@protoc_insertion_point(serialize_start:google.protobuf.Any)
::google::protobuf::uint32 cached_has_bits = 0;
(void) cached_has_bits;
// string type_url = 1;
if (this->type_url().size() > 0) {
::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
this->type_url().data(), static_cast<int>(this->type_url().length()),
::google::protobuf::internal::WireFormatLite::SERIALIZE,
"google.protobuf.Any.type_url");
::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
1, this->type_url(), output);
}
// bytes value = 2;
if (this->value().size() > 0) {
::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased(
2, this->value(), output);
}
if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
(::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance()), output);
}
// @@protoc_insertion_point(serialize_end:google.protobuf.Any)
}
::google::protobuf::uint8* Any::InternalSerializeWithCachedSizesToArray(
bool deterministic, ::google::protobuf::uint8* target) const {
(void)deterministic; // Unused
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Any)
::google::protobuf::uint32 cached_has_bits = 0;
(void) cached_has_bits;
// string type_url = 1;
if (this->type_url().size() > 0) {
::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
this->type_url().data(), static_cast<int>(this->type_url().length()),
::google::protobuf::internal::WireFormatLite::SERIALIZE,
"google.protobuf.Any.type_url");
target =
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
1, this->type_url(), target);
}
// bytes value = 2;
if (this->value().size() > 0) {
target =
::google::protobuf::internal::WireFormatLite::WriteBytesToArray(
2, this->value(), target);
}
if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
(::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance()), target);
}
// @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Any)
return target;
}
size_t Any::ByteSizeLong() const {
// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Any)
size_t total_size = 0;
if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
(::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance()));
}
// string type_url = 1;
if (this->type_url().size() > 0) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->type_url());
}
// bytes value = 2;
if (this->value().size() > 0) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::BytesSize(
this->value());
}
int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
SetCachedSize(cached_size);
return total_size;
}
void Any::MergeFrom(const ::google::protobuf::Message& from) {
// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Any)
GOOGLE_DCHECK_NE(&from, this);
const Any* source =
::google::protobuf::internal::DynamicCastToGenerated<const Any>(
&from);
if (source == NULL) {
// @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Any)
::google::protobuf::internal::ReflectionOps::Merge(from, this);
} else {
// @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Any)
MergeFrom(*source);
}
}
void Any::MergeFrom(const Any& from) {
// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Any)
GOOGLE_DCHECK_NE(&from, this);
_internal_metadata_.MergeFrom(from._internal_metadata_);
::google::protobuf::uint32 cached_has_bits = 0;
(void) cached_has_bits;
if (from.type_url().size() > 0) {
type_url_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.type_url_);
}
if (from.value().size() > 0) {
value_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.value_);
}
}
void Any::CopyFrom(const ::google::protobuf::Message& from) {
// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Any)
if (&from == this) return;
Clear();
MergeFrom(from);
}
void Any::CopyFrom(const Any& from) {
// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Any)
if (&from == this) return;
Clear();
MergeFrom(from);
}
bool Any::IsInitialized() const {
return true;
}
void Any::Swap(Any* other) {
if (other == this) return;
InternalSwap(other);
}
void Any::InternalSwap(Any* other) {
using std::swap;
type_url_.Swap(&other->type_url_, &::google::protobuf::internal::GetEmptyStringAlreadyInited(),
GetArenaNoVirtual());
value_.Swap(&other->value_, &::google::protobuf::internal::GetEmptyStringAlreadyInited(),
GetArenaNoVirtual());
_internal_metadata_.Swap(&other->_internal_metadata_);
}
::google::protobuf::Metadata Any::GetMetadata() const {
protobuf_google_2fprotobuf_2fany_2eproto::protobuf_AssignDescriptorsOnce();
return ::protobuf_google_2fprotobuf_2fany_2eproto::file_level_metadata[kIndexInFileMessages];
}
// @@protoc_insertion_point(namespace_scope)
} // namespace protobuf
} // namespace google
namespace google {
namespace protobuf {
template<> GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE ::google::protobuf::Any* Arena::CreateMaybeMessage< ::google::protobuf::Any >(Arena* arena) {
return Arena::CreateInternal< ::google::protobuf::Any >(arena);
}
} // namespace protobuf
} // namespace google
// @@protoc_insertion_point(global_scope)

View File

@ -0,0 +1,331 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: google/protobuf/any.proto
#ifndef PROTOBUF_INCLUDED_google_2fprotobuf_2fany_2eproto
#define PROTOBUF_INCLUDED_google_2fprotobuf_2fany_2eproto
#include <string>
#include <google/protobuf/stubs/common.h>
#if GOOGLE_PROTOBUF_VERSION < 3006001
#error This file was generated by a newer version of protoc which is
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
#if 3006001 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.
#endif
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/arena.h>
#include <google/protobuf/arenastring.h>
#include <google/protobuf/generated_message_table_driven.h>
#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/inlined_string_field.h>
#include <google/protobuf/metadata.h>
#include <google/protobuf/message.h>
#include <google/protobuf/repeated_field.h> // IWYU pragma: export
#include <google/protobuf/extension_set.h> // IWYU pragma: export
#include <google/protobuf/unknown_field_set.h>
#include <google/protobuf/any.h>
// @@protoc_insertion_point(includes)
#define PROTOBUF_INTERNAL_EXPORT_protobuf_google_2fprotobuf_2fany_2eproto LIBPROTOBUF_EXPORT
namespace protobuf_google_2fprotobuf_2fany_2eproto {
// Internal implementation detail -- do not use these members.
struct LIBPROTOBUF_EXPORT TableStruct {
static const ::google::protobuf::internal::ParseTableField entries[];
static const ::google::protobuf::internal::AuxillaryParseTableField aux[];
static const ::google::protobuf::internal::ParseTable schema[1];
static const ::google::protobuf::internal::FieldMetadata field_metadata[];
static const ::google::protobuf::internal::SerializationTable serialization_table[];
static const ::google::protobuf::uint32 offsets[];
};
void LIBPROTOBUF_EXPORT AddDescriptors();
} // namespace protobuf_google_2fprotobuf_2fany_2eproto
namespace google {
namespace protobuf {
class Any;
class AnyDefaultTypeInternal;
LIBPROTOBUF_EXPORT extern AnyDefaultTypeInternal _Any_default_instance_;
} // namespace protobuf
} // namespace google
namespace google {
namespace protobuf {
template<> LIBPROTOBUF_EXPORT ::google::protobuf::Any* Arena::CreateMaybeMessage<::google::protobuf::Any>(Arena*);
} // namespace protobuf
} // namespace google
namespace google {
namespace protobuf {
// ===================================================================
class LIBPROTOBUF_EXPORT Any : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Any) */ {
public:
Any();
virtual ~Any();
Any(const Any& from);
inline Any& operator=(const Any& from) {
CopyFrom(from);
return *this;
}
#if LANG_CXX11
Any(Any&& from) noexcept
: Any() {
*this = ::std::move(from);
}
inline Any& operator=(Any&& from) noexcept {
if (GetArenaNoVirtual() == from.GetArenaNoVirtual()) {
if (this != &from) InternalSwap(&from);
} else {
CopyFrom(from);
}
return *this;
}
#endif
static const ::google::protobuf::Descriptor* descriptor();
static const Any& default_instance();
static void InitAsDefaultInstance(); // FOR INTERNAL USE ONLY
static inline const Any* internal_default_instance() {
return reinterpret_cast<const Any*>(
&_Any_default_instance_);
}
static constexpr int kIndexInFileMessages =
0;
// implements Any -----------------------------------------------
void PackFrom(const ::google::protobuf::Message& message);
void PackFrom(const ::google::protobuf::Message& message,
const ::std::string& type_url_prefix);
bool UnpackTo(::google::protobuf::Message* message) const;
template<typename T> bool Is() const {
return _any_metadata_.Is<T>();
}
static bool ParseAnyTypeUrl(const string& type_url,
string* full_type_name);
void Swap(Any* other);
friend void swap(Any& a, Any& b) {
a.Swap(&b);
}
// implements Message ----------------------------------------------
inline Any* New() const final {
return CreateMaybeMessage<Any>(NULL);
}
Any* New(::google::protobuf::Arena* arena) const final {
return CreateMaybeMessage<Any>(arena);
}
void CopyFrom(const ::google::protobuf::Message& from) final;
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const Any& from);
void MergeFrom(const Any& from);
void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input) final;
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const final;
::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
bool deterministic, ::google::protobuf::uint8* target) const final;
int GetCachedSize() const final { return _cached_size_.Get(); }
private:
void SharedCtor();
void SharedDtor();
void SetCachedSize(int size) const final;
void InternalSwap(Any* other);
private:
inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
return NULL;
}
inline void* MaybeArenaPtr() const {
return NULL;
}
public:
::google::protobuf::Metadata GetMetadata() const final;
// nested types ----------------------------------------------------
// accessors -------------------------------------------------------
// string type_url = 1;
void clear_type_url();
static const int kTypeUrlFieldNumber = 1;
const ::std::string& type_url() const;
void set_type_url(const ::std::string& value);
#if LANG_CXX11
void set_type_url(::std::string&& value);
#endif
void set_type_url(const char* value);
void set_type_url(const char* value, size_t size);
::std::string* mutable_type_url();
::std::string* release_type_url();
void set_allocated_type_url(::std::string* type_url);
// bytes value = 2;
void clear_value();
static const int kValueFieldNumber = 2;
const ::std::string& value() const;
void set_value(const ::std::string& value);
#if LANG_CXX11
void set_value(::std::string&& value);
#endif
void set_value(const char* value);
void set_value(const void* value, size_t size);
::std::string* mutable_value();
::std::string* release_value();
void set_allocated_value(::std::string* value);
// @@protoc_insertion_point(class_scope:google.protobuf.Any)
private:
::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
::google::protobuf::internal::ArenaStringPtr type_url_;
::google::protobuf::internal::ArenaStringPtr value_;
mutable ::google::protobuf::internal::CachedSize _cached_size_;
::google::protobuf::internal::AnyMetadata _any_metadata_;
friend struct ::protobuf_google_2fprotobuf_2fany_2eproto::TableStruct;
};
// ===================================================================
// ===================================================================
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif // __GNUC__
// Any
// string type_url = 1;
inline void Any::clear_type_url() {
type_url_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline const ::std::string& Any::type_url() const {
// @@protoc_insertion_point(field_get:google.protobuf.Any.type_url)
return type_url_.GetNoArena();
}
inline void Any::set_type_url(const ::std::string& value) {
type_url_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
// @@protoc_insertion_point(field_set:google.protobuf.Any.type_url)
}
#if LANG_CXX11
inline void Any::set_type_url(::std::string&& value) {
type_url_.SetNoArena(
&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::move(value));
// @@protoc_insertion_point(field_set_rvalue:google.protobuf.Any.type_url)
}
#endif
inline void Any::set_type_url(const char* value) {
GOOGLE_DCHECK(value != NULL);
type_url_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
// @@protoc_insertion_point(field_set_char:google.protobuf.Any.type_url)
}
inline void Any::set_type_url(const char* value, size_t size) {
type_url_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
::std::string(reinterpret_cast<const char*>(value), size));
// @@protoc_insertion_point(field_set_pointer:google.protobuf.Any.type_url)
}
inline ::std::string* Any::mutable_type_url() {
// @@protoc_insertion_point(field_mutable:google.protobuf.Any.type_url)
return type_url_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline ::std::string* Any::release_type_url() {
// @@protoc_insertion_point(field_release:google.protobuf.Any.type_url)
return type_url_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline void Any::set_allocated_type_url(::std::string* type_url) {
if (type_url != NULL) {
} else {
}
type_url_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), type_url);
// @@protoc_insertion_point(field_set_allocated:google.protobuf.Any.type_url)
}
// bytes value = 2;
inline void Any::clear_value() {
value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline const ::std::string& Any::value() const {
// @@protoc_insertion_point(field_get:google.protobuf.Any.value)
return value_.GetNoArena();
}
inline void Any::set_value(const ::std::string& value) {
value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
// @@protoc_insertion_point(field_set:google.protobuf.Any.value)
}
#if LANG_CXX11
inline void Any::set_value(::std::string&& value) {
value_.SetNoArena(
&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::move(value));
// @@protoc_insertion_point(field_set_rvalue:google.protobuf.Any.value)
}
#endif
inline void Any::set_value(const char* value) {
GOOGLE_DCHECK(value != NULL);
value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
// @@protoc_insertion_point(field_set_char:google.protobuf.Any.value)
}
inline void Any::set_value(const void* value, size_t size) {
value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
::std::string(reinterpret_cast<const char*>(value), size));
// @@protoc_insertion_point(field_set_pointer:google.protobuf.Any.value)
}
inline ::std::string* Any::mutable_value() {
// @@protoc_insertion_point(field_mutable:google.protobuf.Any.value)
return value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline ::std::string* Any::release_value() {
// @@protoc_insertion_point(field_release:google.protobuf.Any.value)
return value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline void Any::set_allocated_value(::std::string* value) {
if (value != NULL) {
} else {
}
value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
// @@protoc_insertion_point(field_set_allocated:google.protobuf.Any.value)
}
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif // __GNUC__
// @@protoc_insertion_point(namespace_scope)
} // namespace protobuf
} // namespace google
// @@protoc_insertion_point(global_scope)
#endif // PROTOBUF_INCLUDED_google_2fprotobuf_2fany_2eproto

View File

@ -0,0 +1,154 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
package google.protobuf;
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
option go_package = "github.com/golang/protobuf/ptypes/any";
option java_package = "com.google.protobuf";
option java_outer_classname = "AnyProto";
option java_multiple_files = true;
option objc_class_prefix = "GPB";
// `Any` contains an arbitrary serialized protocol buffer message along with a
// URL that describes the type of the serialized message.
//
// Protobuf library provides support to pack/unpack Any values in the form
// of utility functions or additional generated methods of the Any type.
//
// Example 1: Pack and unpack a message in C++.
//
// Foo foo = ...;
// Any any;
// any.PackFrom(foo);
// ...
// if (any.UnpackTo(&foo)) {
// ...
// }
//
// Example 2: Pack and unpack a message in Java.
//
// Foo foo = ...;
// Any any = Any.pack(foo);
// ...
// if (any.is(Foo.class)) {
// foo = any.unpack(Foo.class);
// }
//
// Example 3: Pack and unpack a message in Python.
//
// foo = Foo(...)
// any = Any()
// any.Pack(foo)
// ...
// if any.Is(Foo.DESCRIPTOR):
// any.Unpack(foo)
// ...
//
// Example 4: Pack and unpack a message in Go
//
// foo := &pb.Foo{...}
// any, err := ptypes.MarshalAny(foo)
// ...
// foo := &pb.Foo{}
// if err := ptypes.UnmarshalAny(any, foo); err != nil {
// ...
// }
//
// The pack methods provided by protobuf library will by default use
// 'type.googleapis.com/full.type.name' as the type URL and the unpack
// methods only use the fully qualified type name after the last '/'
// in the type URL, for example "foo.bar.com/x/y.z" will yield type
// name "y.z".
//
//
// JSON
// ====
// The JSON representation of an `Any` value uses the regular
// representation of the deserialized, embedded message, with an
// additional field `@type` which contains the type URL. Example:
//
// package google.profile;
// message Person {
// string first_name = 1;
// string last_name = 2;
// }
//
// {
// "@type": "type.googleapis.com/google.profile.Person",
// "firstName": <string>,
// "lastName": <string>
// }
//
// If the embedded message type is well-known and has a custom JSON
// representation, that representation will be embedded adding a field
// `value` which holds the custom JSON in addition to the `@type`
// field. Example (for message [google.protobuf.Duration][]):
//
// {
// "@type": "type.googleapis.com/google.protobuf.Duration",
// "value": "1.212s"
// }
//
message Any {
// A URL/resource name that uniquely identifies the type of the serialized
// protocol buffer message. The last segment of the URL's path must represent
// the fully qualified name of the type (as in
// `path/google.protobuf.Duration`). The name should be in a canonical form
// (e.g., leading "." is not accepted).
//
// In practice, teams usually precompile into the binary all types that they
// expect it to use in the context of Any. However, for URLs which use the
// scheme `http`, `https`, or no scheme, one can optionally set up a type
// server that maps type URLs to message definitions as follows:
//
// * If no scheme is provided, `https` is assumed.
// * An HTTP GET on the URL must yield a [google.protobuf.Type][]
// value in binary format, or produce an error.
// * Applications are allowed to cache lookup results based on the
// URL, or have them precompiled into a binary to avoid any
// lookup. Therefore, binary compatibility needs to be preserved
// on changes to types. (Use versioned type names to manage
// breaking changes.)
//
// Note: this functionality is not currently available in the official
// protobuf release, and it is not used for type URLs beginning with
// type.googleapis.com.
//
// Schemes other than `http`, `https` (or the empty scheme) might be
// used with implementation specific semantics.
//
string type_url = 1;
// Must be a valid serialized protocol buffer of the above specified type.
bytes value = 2;
}

View File

@ -0,0 +1,89 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <google/protobuf/any_test.pb.h>
#include <gtest/gtest.h>
namespace google {
namespace protobuf {
namespace {
TEST(AnyTest, TestPackAndUnpack) {
protobuf_unittest::TestAny submessage;
submessage.set_int32_value(12345);
protobuf_unittest::TestAny message;
message.mutable_any_value()->PackFrom(submessage);
string data = message.SerializeAsString();
ASSERT_TRUE(message.ParseFromString(data));
EXPECT_TRUE(message.has_any_value());
ASSERT_TRUE(message.any_value().UnpackTo(&submessage));
EXPECT_EQ(12345, submessage.int32_value());
}
TEST(AnyTest, TestPackAndUnpackAny) {
// We can pack a Any message inside another Any message.
protobuf_unittest::TestAny submessage;
submessage.set_int32_value(12345);
google::protobuf::Any any;
any.PackFrom(submessage);
protobuf_unittest::TestAny message;
message.mutable_any_value()->PackFrom(any);
string data = message.SerializeAsString();
ASSERT_TRUE(message.ParseFromString(data));
EXPECT_TRUE(message.has_any_value());
ASSERT_TRUE(message.any_value().UnpackTo(&any));
ASSERT_TRUE(any.UnpackTo(&submessage));
EXPECT_EQ(12345, submessage.int32_value());
}
TEST(AnyTest, TestIs) {
protobuf_unittest::TestAny submessage;
submessage.set_int32_value(12345);
google::protobuf::Any any;
any.PackFrom(submessage);
ASSERT_TRUE(any.ParseFromString(any.SerializeAsString()));
EXPECT_TRUE(any.Is<protobuf_unittest::TestAny>());
EXPECT_FALSE(any.Is<google::protobuf::Any>());
protobuf_unittest::TestAny message;
message.mutable_any_value()->PackFrom(any);
ASSERT_TRUE(message.ParseFromString(message.SerializeAsString()));
EXPECT_FALSE(message.any_value().Is<protobuf_unittest::TestAny>());
EXPECT_TRUE(message.any_value().Is<google::protobuf::Any>());
}
} // namespace
} // namespace protobuf
} // namespace google

View File

@ -0,0 +1,41 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
package protobuf_unittest;
import "google/protobuf/any.proto";
message TestAny {
int32 int32_value = 1;
google.protobuf.Any any_value = 2;
repeated google.protobuf.Any repeated_any_value = 3;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,210 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
package google.protobuf;
import "google/protobuf/source_context.proto";
import "google/protobuf/type.proto";
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
option java_package = "com.google.protobuf";
option java_outer_classname = "ApiProto";
option java_multiple_files = true;
option objc_class_prefix = "GPB";
option go_package = "google.golang.org/genproto/protobuf/api;api";
// Api is a light-weight descriptor for an API Interface.
//
// Interfaces are also described as "protocol buffer services" in some contexts,
// such as by the "service" keyword in a .proto file, but they are different
// from API Services, which represent a concrete implementation of an interface
// as opposed to simply a description of methods and bindings. They are also
// sometimes simply referred to as "APIs" in other contexts, such as the name of
// this message itself. See https://cloud.google.com/apis/design/glossary for
// detailed terminology.
message Api {
// The fully qualified name of this interface, including package name
// followed by the interface's simple name.
string name = 1;
// The methods of this interface, in unspecified order.
repeated Method methods = 2;
// Any metadata attached to the interface.
repeated Option options = 3;
// A version string for this interface. If specified, must have the form
// `major-version.minor-version`, as in `1.10`. If the minor version is
// omitted, it defaults to zero. If the entire version field is empty, the
// major version is derived from the package name, as outlined below. If the
// field is not empty, the version in the package name will be verified to be
// consistent with what is provided here.
//
// The versioning schema uses [semantic
// versioning](http://semver.org) where the major version number
// indicates a breaking change and the minor version an additive,
// non-breaking change. Both version numbers are signals to users
// what to expect from different versions, and should be carefully
// chosen based on the product plan.
//
// The major version is also reflected in the package name of the
// interface, which must end in `v<major-version>`, as in
// `google.feature.v1`. For major versions 0 and 1, the suffix can
// be omitted. Zero major versions must only be used for
// experimental, non-GA interfaces.
//
//
string version = 4;
// Source context for the protocol buffer service represented by this
// message.
SourceContext source_context = 5;
// Included interfaces. See [Mixin][].
repeated Mixin mixins = 6;
// The source syntax of the service.
Syntax syntax = 7;
}
// Method represents a method of an API interface.
message Method {
// The simple name of this method.
string name = 1;
// A URL of the input message type.
string request_type_url = 2;
// If true, the request is streamed.
bool request_streaming = 3;
// The URL of the output message type.
string response_type_url = 4;
// If true, the response is streamed.
bool response_streaming = 5;
// Any metadata attached to the method.
repeated Option options = 6;
// The source syntax of this method.
Syntax syntax = 7;
}
// Declares an API Interface to be included in this interface. The including
// interface must redeclare all the methods from the included interface, but
// documentation and options are inherited as follows:
//
// - If after comment and whitespace stripping, the documentation
// string of the redeclared method is empty, it will be inherited
// from the original method.
//
// - Each annotation belonging to the service config (http,
// visibility) which is not set in the redeclared method will be
// inherited.
//
// - If an http annotation is inherited, the path pattern will be
// modified as follows. Any version prefix will be replaced by the
// version of the including interface plus the [root][] path if
// specified.
//
// Example of a simple mixin:
//
// package google.acl.v1;
// service AccessControl {
// // Get the underlying ACL object.
// rpc GetAcl(GetAclRequest) returns (Acl) {
// option (google.api.http).get = "/v1/{resource=**}:getAcl";
// }
// }
//
// package google.storage.v2;
// service Storage {
// rpc GetAcl(GetAclRequest) returns (Acl);
//
// // Get a data record.
// rpc GetData(GetDataRequest) returns (Data) {
// option (google.api.http).get = "/v2/{resource=**}";
// }
// }
//
// Example of a mixin configuration:
//
// apis:
// - name: google.storage.v2.Storage
// mixins:
// - name: google.acl.v1.AccessControl
//
// The mixin construct implies that all methods in `AccessControl` are
// also declared with same name and request/response types in
// `Storage`. A documentation generator or annotation processor will
// see the effective `Storage.GetAcl` method after inherting
// documentation and annotations as follows:
//
// service Storage {
// // Get the underlying ACL object.
// rpc GetAcl(GetAclRequest) returns (Acl) {
// option (google.api.http).get = "/v2/{resource=**}:getAcl";
// }
// ...
// }
//
// Note how the version in the path pattern changed from `v1` to `v2`.
//
// If the `root` field in the mixin is specified, it should be a
// relative path under which inherited HTTP paths are placed. Example:
//
// apis:
// - name: google.storage.v2.Storage
// mixins:
// - name: google.acl.v1.AccessControl
// root: acls
//
// This implies the following inherited HTTP annotation:
//
// service Storage {
// // Get the underlying ACL object.
// rpc GetAcl(GetAclRequest) returns (Acl) {
// option (google.api.http).get = "/v2/acls/{resource=**}:getAcl";
// }
// ...
// }
message Mixin {
// The fully qualified name of the interface which is included.
string name = 1;
// If non-empty specifies a path under which inherited HTTP paths
// are rooted.
string root = 2;
}

View File

@ -0,0 +1,415 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <google/protobuf/arena.h>
#include <algorithm>
#include <limits>
#ifdef ADDRESS_SANITIZER
#include <sanitizer/asan_interface.h>
#endif // ADDRESS_SANITIZER
#include <google/protobuf/stubs/port.h>
namespace google {
static const size_t kMinCleanupListElements = 8;
static const size_t kMaxCleanupListElements = 64; // 1kB on 64-bit.
namespace protobuf {
namespace internal {
std::atomic<int64> ArenaImpl::lifecycle_id_generator_;
#if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
ArenaImpl::ThreadCache& ArenaImpl::thread_cache() {
static internal::ThreadLocalStorage<ThreadCache>* thread_cache_ =
new internal::ThreadLocalStorage<ThreadCache>();
return *thread_cache_->Get();
}
#elif defined(PROTOBUF_USE_DLLS)
ArenaImpl::ThreadCache& ArenaImpl::thread_cache() {
static GOOGLE_THREAD_LOCAL ThreadCache thread_cache_ = { -1, NULL };
return thread_cache_;
}
#else
GOOGLE_THREAD_LOCAL ArenaImpl::ThreadCache ArenaImpl::thread_cache_ = {-1, NULL};
#endif
void ArenaImpl::Init() {
lifecycle_id_ =
lifecycle_id_generator_.fetch_add(1, std::memory_order_relaxed);
hint_.store(nullptr, std::memory_order_relaxed);
threads_.store(nullptr, std::memory_order_relaxed);
if (initial_block_) {
// Thread which calls Init() owns the first block. This allows the
// single-threaded case to allocate on the first block without having to
// perform atomic operations.
new (initial_block_) Block(options_.initial_block_size, NULL);
SerialArena* serial =
SerialArena::New(initial_block_, &thread_cache(), this);
serial->set_next(NULL);
threads_.store(serial, std::memory_order_relaxed);
space_allocated_.store(options_.initial_block_size,
std::memory_order_relaxed);
CacheSerialArena(serial);
} else {
space_allocated_.store(0, std::memory_order_relaxed);
}
}
ArenaImpl::~ArenaImpl() {
// Have to do this in a first pass, because some of the destructors might
// refer to memory in other blocks.
CleanupList();
FreeBlocks();
}
uint64 ArenaImpl::Reset() {
// Have to do this in a first pass, because some of the destructors might
// refer to memory in other blocks.
CleanupList();
uint64 space_allocated = FreeBlocks();
Init();
return space_allocated;
}
ArenaImpl::Block* ArenaImpl::NewBlock(Block* last_block, size_t min_bytes) {
size_t size;
if (last_block) {
// Double the current block size, up to a limit.
size = std::min(2 * last_block->size(), options_.max_block_size);
} else {
size = options_.start_block_size;
}
// Verify that min_bytes + kBlockHeaderSize won't overflow.
GOOGLE_CHECK_LE(min_bytes, std::numeric_limits<size_t>::max() - kBlockHeaderSize);
size = std::max(size, kBlockHeaderSize + min_bytes);
void* mem = options_.block_alloc(size);
Block* b = new (mem) Block(size, last_block);
space_allocated_.fetch_add(size, std::memory_order_relaxed);
return b;
}
ArenaImpl::Block::Block(size_t size, Block* next)
: next_(next), pos_(kBlockHeaderSize), size_(size) {}
GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE
void ArenaImpl::SerialArena::AddCleanupFallback(void* elem,
void (*cleanup)(void*)) {
size_t size = cleanup_ ? cleanup_->size * 2 : kMinCleanupListElements;
size = std::min(size, kMaxCleanupListElements);
size_t bytes = internal::AlignUpTo8(CleanupChunk::SizeOf(size));
CleanupChunk* list = reinterpret_cast<CleanupChunk*>(AllocateAligned(bytes));
list->next = cleanup_;
list->size = size;
cleanup_ = list;
cleanup_ptr_ = &list->nodes[0];
cleanup_limit_ = &list->nodes[size];
AddCleanup(elem, cleanup);
}
GOOGLE_PROTOBUF_ATTRIBUTE_FUNC_ALIGN(32)
void* ArenaImpl::AllocateAligned(size_t n) {
SerialArena* arena;
if (GOOGLE_PREDICT_TRUE(GetSerialArenaFast(&arena))) {
return arena->AllocateAligned(n);
} else {
return AllocateAlignedFallback(n);
}
}
void* ArenaImpl::AllocateAlignedAndAddCleanup(size_t n,
void (*cleanup)(void*)) {
SerialArena* arena;
if (GOOGLE_PREDICT_TRUE(GetSerialArenaFast(&arena))) {
return arena->AllocateAlignedAndAddCleanup(n, cleanup);
} else {
return AllocateAlignedAndAddCleanupFallback(n, cleanup);
}
}
void ArenaImpl::AddCleanup(void* elem, void (*cleanup)(void*)) {
SerialArena* arena;
if (GOOGLE_PREDICT_TRUE(GetSerialArenaFast(&arena))) {
arena->AddCleanup(elem, cleanup);
} else {
return AddCleanupFallback(elem, cleanup);
}
}
GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE
void* ArenaImpl::AllocateAlignedFallback(size_t n) {
return GetSerialArena()->AllocateAligned(n);
}
GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE
void* ArenaImpl::AllocateAlignedAndAddCleanupFallback(size_t n,
void (*cleanup)(void*)) {
return GetSerialArena()->AllocateAlignedAndAddCleanup(n, cleanup);
}
GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE
void ArenaImpl::AddCleanupFallback(void* elem, void (*cleanup)(void*)) {
GetSerialArena()->AddCleanup(elem, cleanup);
}
inline GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
bool ArenaImpl::GetSerialArenaFast(ArenaImpl::SerialArena** arena) {
// If this thread already owns a block in this arena then try to use that.
// This fast path optimizes the case where multiple threads allocate from the
// same arena.
ThreadCache* tc = &thread_cache();
if (GOOGLE_PREDICT_TRUE(tc->last_lifecycle_id_seen == lifecycle_id_)) {
*arena = tc->last_serial_arena;
return true;
}
// Check whether we own the last accessed SerialArena on this arena. This
// fast path optimizes the case where a single thread uses multiple arenas.
SerialArena* serial = hint_.load(std::memory_order_acquire);
if (GOOGLE_PREDICT_TRUE(serial != NULL && serial->owner() == tc)) {
*arena = serial;
return true;
}
return false;
}
ArenaImpl::SerialArena* ArenaImpl::GetSerialArena() {
SerialArena* arena;
if (GOOGLE_PREDICT_TRUE(GetSerialArenaFast(&arena))) {
return arena;
} else {
return GetSerialArenaFallback(&thread_cache());
}
}
GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE
void* ArenaImpl::SerialArena::AllocateAlignedFallback(size_t n) {
// Sync back to current's pos.
head_->set_pos(head_->size() - (limit_ - ptr_));
head_ = arena_->NewBlock(head_, n);
ptr_ = head_->Pointer(head_->pos());
limit_ = head_->Pointer(head_->size());
#ifdef ADDRESS_SANITIZER
ASAN_POISON_MEMORY_REGION(ptr_, limit_ - ptr_);
#endif // ADDRESS_SANITIZER
return AllocateAligned(n);
}
uint64 ArenaImpl::SpaceAllocated() const {
return space_allocated_.load(std::memory_order_relaxed);
}
uint64 ArenaImpl::SpaceUsed() const {
SerialArena* serial = threads_.load(std::memory_order_acquire);
uint64 space_used = 0;
for ( ; serial; serial = serial->next()) {
space_used += serial->SpaceUsed();
}
return space_used;
}
uint64 ArenaImpl::SerialArena::SpaceUsed() const {
// Get current block's size from ptr_ (since we can't trust head_->pos().
uint64 space_used = ptr_ - head_->Pointer(kBlockHeaderSize);
// Get subsequent block size from b->pos().
for (Block* b = head_->next(); b; b = b->next()) {
space_used += (b->pos() - kBlockHeaderSize);
}
// Remove the overhead of the SerialArena itself.
space_used -= kSerialArenaSize;
return space_used;
}
uint64 ArenaImpl::FreeBlocks() {
uint64 space_allocated = 0;
// By omitting an Acquire barrier we ensure that any user code that doesn't
// properly synchronize Reset() or the destructor will throw a TSAN warning.
SerialArena* serial = threads_.load(std::memory_order_relaxed);
while (serial) {
// This is inside a block we are freeing, so we need to read it now.
SerialArena* next = serial->next();
space_allocated += ArenaImpl::SerialArena::Free(serial, initial_block_,
options_.block_dealloc);
// serial is dead now.
serial = next;
}
return space_allocated;
}
uint64 ArenaImpl::SerialArena::Free(ArenaImpl::SerialArena* serial,
Block* initial_block,
void (*block_dealloc)(void*, size_t)) {
uint64 space_allocated = 0;
// We have to be careful in this function, since we will be freeing the Block
// that contains this SerialArena. Be careful about accessing |serial|.
for (Block* b = serial->head_; b; ) {
// This is inside the block we are freeing, so we need to read it now.
Block* next_block = b->next();
space_allocated += (b->size());
#ifdef ADDRESS_SANITIZER
// This memory was provided by the underlying allocator as unpoisoned, so
// return it in an unpoisoned state.
ASAN_UNPOISON_MEMORY_REGION(b->Pointer(0), b->size());
#endif // ADDRESS_SANITIZER
if (b != initial_block) {
block_dealloc(b, b->size());
}
b = next_block;
}
return space_allocated;
}
void ArenaImpl::CleanupList() {
// By omitting an Acquire barrier we ensure that any user code that doesn't
// properly synchronize Reset() or the destructor will throw a TSAN warning.
SerialArena* serial = threads_.load(std::memory_order_relaxed);
for ( ; serial; serial = serial->next()) {
serial->CleanupList();
}
}
void ArenaImpl::SerialArena::CleanupList() {
if (cleanup_ != NULL) {
CleanupListFallback();
}
}
void ArenaImpl::SerialArena::CleanupListFallback() {
// Cleanup newest chunk: ptrs give us length.
size_t n = cleanup_ptr_ - &cleanup_->nodes[0];
CleanupNode* node = cleanup_ptr_;
for (size_t i = 0; i < n; i++) {
--node;
node->cleanup(node->elem);
}
// Cleanup older chunks, which are known to be full.
CleanupChunk* list = cleanup_->next;
while (list) {
size_t n = list->size;
CleanupNode* node = &list->nodes[list->size];
for (size_t i = 0; i < n; i++) {
--node;
node->cleanup(node->elem);
}
list = list->next;
}
}
ArenaImpl::SerialArena* ArenaImpl::SerialArena::New(Block* b, void* owner,
ArenaImpl* arena) {
GOOGLE_DCHECK_EQ(b->pos(), kBlockHeaderSize); // Should be a fresh block
GOOGLE_DCHECK_LE(kBlockHeaderSize + kSerialArenaSize, b->size());
SerialArena* serial =
reinterpret_cast<SerialArena*>(b->Pointer(kBlockHeaderSize));
b->set_pos(kBlockHeaderSize + kSerialArenaSize);
serial->arena_ = arena;
serial->owner_ = owner;
serial->head_ = b;
serial->ptr_ = b->Pointer(b->pos());
serial->limit_ = b->Pointer(b->size());
serial->cleanup_ = NULL;
serial->cleanup_ptr_ = NULL;
serial->cleanup_limit_ = NULL;
return serial;
}
GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE
ArenaImpl::SerialArena* ArenaImpl::GetSerialArenaFallback(void* me) {
// Look for this SerialArena in our linked list.
SerialArena* serial = threads_.load(std::memory_order_acquire);
for ( ; serial; serial = serial->next()) {
if (serial->owner() == me) {
break;
}
}
if (!serial) {
// This thread doesn't have any SerialArena, which also means it doesn't
// have any blocks yet. So we'll allocate its first block now.
Block* b = NewBlock(NULL, kSerialArenaSize);
serial = SerialArena::New(b, me, this);
SerialArena* head = threads_.load(std::memory_order_relaxed);
do {
serial->set_next(head);
} while (!threads_.compare_exchange_weak(
head, serial, std::memory_order_release, std::memory_order_relaxed));
}
CacheSerialArena(serial);
return serial;
}
} // namespace internal
void Arena::CallDestructorHooks() {
uint64 space_allocated = impl_.SpaceAllocated();
// Call the reset hook
if (on_arena_reset_ != NULL) {
on_arena_reset_(this, hooks_cookie_, space_allocated);
}
// Call the destruction hook
if (on_arena_destruction_ != NULL) {
on_arena_destruction_(this, hooks_cookie_, space_allocated);
}
}
void Arena::OnArenaAllocation(const std::type_info* allocated_type,
size_t n) const {
if (on_arena_allocation_ != NULL) {
on_arena_allocation_(allocated_type, n, hooks_cookie_);
}
}
} // namespace protobuf
} // namespace google

View File

@ -0,0 +1,703 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// This file defines an Arena allocator for better allocation performance.
#ifndef GOOGLE_PROTOBUF_ARENA_H__
#define GOOGLE_PROTOBUF_ARENA_H__
#include <limits>
#ifdef max
#undef max // Visual Studio defines this macro
#endif
#if defined(_MSC_VER) && !defined(_LIBCPP_STD_VER) && !_HAS_EXCEPTIONS
// Work around bugs in MSVC <typeinfo> header when _HAS_EXCEPTIONS=0.
#include <exception>
#include <typeinfo>
namespace std {
using type_info = ::type_info;
}
#else
#include <typeinfo>
#endif
#include <google/protobuf/arena_impl.h>
#include <google/protobuf/stubs/port.h>
#include <type_traits>
namespace google {
namespace protobuf {
struct ArenaOptions; // defined below
} // namespace protobuf
namespace quality_webanswers {
void TempPrivateWorkAround(::google::protobuf::ArenaOptions* arena_options);
} // namespace quality_webanswers
namespace protobuf {
class Arena; // defined below
class Message; // defined in message.h
class MessageLite;
namespace arena_metrics {
void EnableArenaMetrics(::google::protobuf::ArenaOptions* options);
} // namespace arena_metrics
namespace internal {
struct ArenaStringPtr; // defined in arenastring.h
class LazyField; // defined in lazy_field.h
template <typename Type>
class GenericTypeHandler; // defined in repeated_field.h
// Templated cleanup methods.
template <typename T>
void arena_destruct_object(void* object) {
reinterpret_cast<T*>(object)->~T();
}
template <typename T>
void arena_delete_object(void* object) {
delete reinterpret_cast<T*>(object);
}
inline void arena_free(void* object, size_t size) {
#if defined(__GXX_DELETE_WITH_SIZE__) || defined(__cpp_sized_deallocation)
::operator delete(object, size);
#else
(void)size;
::operator delete(object);
#endif
}
} // namespace internal
// ArenaOptions provides optional additional parameters to arena construction
// that control its block-allocation behavior.
struct ArenaOptions {
// This defines the size of the first block requested from the system malloc.
// Subsequent block sizes will increase in a geometric series up to a maximum.
size_t start_block_size;
// This defines the maximum block size requested from system malloc (unless an
// individual arena allocation request occurs with a size larger than this
// maximum). Requested block sizes increase up to this value, then remain
// here.
size_t max_block_size;
// An initial block of memory for the arena to use, or NULL for none. If
// provided, the block must live at least as long as the arena itself. The
// creator of the Arena retains ownership of the block after the Arena is
// destroyed.
char* initial_block;
// The size of the initial block, if provided.
size_t initial_block_size;
// A function pointer to an alloc method that returns memory blocks of size
// requested. By default, it contains a ptr to the malloc function.
//
// NOTE: block_alloc and dealloc functions are expected to behave like
// malloc and free, including Asan poisoning.
void* (*block_alloc)(size_t);
// A function pointer to a dealloc method that takes ownership of the blocks
// from the arena. By default, it contains a ptr to a wrapper function that
// calls free.
void (*block_dealloc)(void*, size_t);
ArenaOptions()
: start_block_size(kDefaultStartBlockSize),
max_block_size(kDefaultMaxBlockSize),
initial_block(NULL),
initial_block_size(0),
block_alloc(&::operator new),
block_dealloc(&internal::arena_free),
on_arena_init(NULL),
on_arena_reset(NULL),
on_arena_destruction(NULL),
on_arena_allocation(NULL) {}
private:
// Hooks for adding external functionality such as user-specific metrics
// collection, specific debugging abilities, etc.
// Init hook may return a pointer to a cookie to be stored in the arena.
// reset and destruction hooks will then be called with the same cookie
// pointer. This allows us to save an external object per arena instance and
// use it on the other hooks (Note: It is just as legal for init to return
// NULL and not use the cookie feature).
// on_arena_reset and on_arena_destruction also receive the space used in
// the arena just before the reset.
void* (*on_arena_init)(Arena* arena);
void (*on_arena_reset)(Arena* arena, void* cookie, uint64 space_used);
void (*on_arena_destruction)(Arena* arena, void* cookie, uint64 space_used);
// type_info is promised to be static - its lifetime extends to
// match program's lifetime (It is given by typeid operator).
// Note: typeid(void) will be passed as allocated_type every time we
// intentionally want to avoid monitoring an allocation. (i.e. internal
// allocations for managing the arena)
void (*on_arena_allocation)(const std::type_info* allocated_type,
uint64 alloc_size, void* cookie);
// Constants define default starting block size and max block size for
// arena allocator behavior -- see descriptions above.
static const size_t kDefaultStartBlockSize = 256;
static const size_t kDefaultMaxBlockSize = 8192;
friend void ::google::protobuf::arena_metrics::EnableArenaMetrics(ArenaOptions*);
friend void quality_webanswers::TempPrivateWorkAround(ArenaOptions*);
friend class Arena;
friend class ArenaOptionsTestFriend;
};
// Support for non-RTTI environments. (The metrics hooks API uses type
// information.)
#ifndef GOOGLE_PROTOBUF_NO_RTTI
#define RTTI_TYPE_ID(type) (&typeid(type))
#else
#define RTTI_TYPE_ID(type) (NULL)
#endif
// Arena allocator. Arena allocation replaces ordinary (heap-based) allocation
// with new/delete, and improves performance by aggregating allocations into
// larger blocks and freeing allocations all at once. Protocol messages are
// allocated on an arena by using Arena::CreateMessage<T>(Arena*), below, and
// are automatically freed when the arena is destroyed.
//
// This is a thread-safe implementation: multiple threads may allocate from the
// arena concurrently. Destruction is not thread-safe and the destructing
// thread must synchronize with users of the arena first.
//
// An arena provides two allocation interfaces: CreateMessage<T>, which works
// for arena-enabled proto2 message types as well as other types that satisfy
// the appropriate protocol (described below), and Create<T>, which works for
// any arbitrary type T. CreateMessage<T> is better when the type T supports it,
// because this interface (i) passes the arena pointer to the created object so
// that its sub-objects and internal allocations can use the arena too, and (ii)
// elides the object's destructor call when possible. Create<T> does not place
// any special requirements on the type T, and will invoke the object's
// destructor when the arena is destroyed.
//
// The arena message allocation protocol, required by CreateMessage<T>, is as
// follows:
//
// - The type T must have (at least) two constructors: a constructor with no
// arguments, called when a T is allocated on the heap; and a constructor with
// a google::protobuf::Arena* argument, called when a T is allocated on an arena. If the
// second constructor is called with a NULL arena pointer, it must be
// equivalent to invoking the first (no-argument) constructor.
//
// - The type T must have a particular type trait: a nested type
// |InternalArenaConstructable_|. This is usually a typedef to |void|. If no
// such type trait exists, then the instantiation CreateMessage<T> will fail
// to compile.
//
// - The type T *may* have the type trait |DestructorSkippable_|. If this type
// trait is present in the type, then its destructor will not be called if and
// only if it was passed a non-NULL arena pointer. If this type trait is not
// present on the type, then its destructor is always called when the
// containing arena is destroyed.
//
// - One- and two-user-argument forms of CreateMessage<T>() also exist that
// forward these constructor arguments to T's constructor: for example,
// CreateMessage<T>(Arena*, arg1, arg2) forwards to a constructor T(Arena*,
// arg1, arg2).
//
// This protocol is implemented by all arena-enabled proto2 message classes as
// well as RepeatedPtrField.
//
// Do NOT subclass Arena. This class will be marked as final when C++11 is
// enabled.
class LIBPROTOBUF_EXPORT Arena {
public:
// Arena constructor taking custom options. See ArenaOptions below for
// descriptions of the options available.
explicit Arena(const ArenaOptions& options) : impl_(options) {
Init(options);
}
// Block overhead. Use this as a guide for how much to over-allocate the
// initial block if you want an allocation of size N to fit inside it.
//
// WARNING: if you allocate multiple objects, it is difficult to guarantee
// that a series of allocations will fit in the initial block, especially if
// Arena changes its alignment guarantees in the future!
static const size_t kBlockOverhead = internal::ArenaImpl::kBlockHeaderSize +
internal::ArenaImpl::kSerialArenaSize;
// Default constructor with sensible default options, tuned for average
// use-cases.
Arena() : impl_(ArenaOptions()) { Init(ArenaOptions()); }
~Arena() {
if (hooks_cookie_) {
CallDestructorHooks();
}
}
void Init(const ArenaOptions& options) {
on_arena_allocation_ = options.on_arena_allocation;
on_arena_reset_ = options.on_arena_reset;
on_arena_destruction_ = options.on_arena_destruction;
// Call the initialization hook
if (options.on_arena_init != NULL) {
hooks_cookie_ = options.on_arena_init(this);
} else {
hooks_cookie_ = NULL;
}
}
// API to create proto2 message objects on the arena. If the arena passed in
// is NULL, then a heap allocated object is returned. Type T must be a message
// defined in a .proto file with cc_enable_arenas set to true, otherwise a
// compilation error will occur.
//
// RepeatedField and RepeatedPtrField may also be instantiated directly on an
// arena with this method.
//
// This function also accepts any type T that satisfies the arena message
// allocation protocol, documented above.
template <typename T, typename... Args>
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE static T* CreateMessage(
Arena* arena, Args&&... args) {
static_assert(
InternalHelper<T>::is_arena_constructable::value,
"CreateMessage can only construct types that are ArenaConstructable");
// We must delegate to CreateMaybeMessage() and NOT CreateMessageInternal()
// because protobuf generated classes specialize CreateMaybeMessage() and we
// need to use that specialization for code size reasons.
return Arena::CreateMaybeMessage<T>(arena, std::forward<Args>(args)...);
}
// API to create any objects on the arena. Note that only the object will
// be created on the arena; the underlying ptrs (in case of a proto2 message)
// will be still heap allocated. Proto messages should usually be allocated
// with CreateMessage<T>() instead.
//
// Note that even if T satisfies the arena message construction protocol
// (InternalArenaConstructable_ trait and optional DestructorSkippable_
// trait), as described above, this function does not follow the protocol;
// instead, it treats T as a black-box type, just as if it did not have these
// traits. Specifically, T's constructor arguments will always be only those
// passed to Create<T>() -- no additional arena pointer is implicitly added.
// Furthermore, the destructor will always be called at arena destruction time
// (unless the destructor is trivial). Hence, from T's point of view, it is as
// if the object were allocated on the heap (except that the underlying memory
// is obtained from the arena).
template <typename T, typename... Args>
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE static T* Create(Arena* arena,
Args&&... args) {
return CreateNoMessage<T>(arena, is_arena_constructable<T>(),
std::forward<Args>(args)...);
}
// Create an array of object type T on the arena *without* invoking the
// constructor of T. If `arena` is null, then the return value should be freed
// with `delete[] x;` (or `::operator delete[](x);`).
// To ensure safe uses, this function checks at compile time
// (when compiled as C++11) that T is trivially default-constructible and
// trivially destructible.
template <typename T>
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE static T* CreateArray(
Arena* arena, size_t num_elements) {
static_assert(std::is_pod<T>::value,
"CreateArray requires a trivially constructible type");
static_assert(std::is_trivially_destructible<T>::value,
"CreateArray requires a trivially destructible type");
GOOGLE_CHECK_LE(num_elements, std::numeric_limits<size_t>::max() / sizeof(T))
<< "Requested size is too large to fit into size_t.";
if (arena == NULL) {
return static_cast<T*>(::operator new[](num_elements * sizeof(T)));
} else {
return arena->CreateInternalRawArray<T>(num_elements);
}
}
// Returns the total space allocated by the arena, which is the sum of the
// sizes of the underlying blocks. This method is relatively fast; a counter
// is kept as blocks are allocated.
uint64 SpaceAllocated() const { return impl_.SpaceAllocated(); }
// Returns the total space used by the arena. Similar to SpaceAllocated but
// does not include free space and block overhead. The total space returned
// may not include space used by other threads executing concurrently with
// the call to this method.
uint64 SpaceUsed() const { return impl_.SpaceUsed(); }
// DEPRECATED. Please use SpaceAllocated() and SpaceUsed().
//
// Combines SpaceAllocated and SpaceUsed. Returns a pair of
// <space_allocated, space_used>.
PROTOBUF_RUNTIME_DEPRECATED("Please use SpaceAllocated() and SpaceUsed()")
std::pair<uint64, uint64> SpaceAllocatedAndUsed() const {
return std::make_pair(SpaceAllocated(), SpaceUsed());
}
// Frees all storage allocated by this arena after calling destructors
// registered with OwnDestructor() and freeing objects registered with Own().
// Any objects allocated on this arena are unusable after this call. It also
// returns the total space used by the arena which is the sums of the sizes
// of the allocated blocks. This method is not thread-safe.
GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE uint64 Reset() {
// Call the reset hook
if (on_arena_reset_ != NULL) {
on_arena_reset_(this, hooks_cookie_, impl_.SpaceAllocated());
}
return impl_.Reset();
}
// Adds |object| to a list of heap-allocated objects to be freed with |delete|
// when the arena is destroyed or reset.
template <typename T>
GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE void Own(T* object) {
OwnInternal(object, std::is_convertible<T*, Message*>());
}
// Adds |object| to a list of objects whose destructors will be manually
// called when the arena is destroyed or reset. This differs from Own() in
// that it does not free the underlying memory with |delete|; hence, it is
// normally only used for objects that are placement-newed into
// arena-allocated memory.
template <typename T>
GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE void OwnDestructor(T* object) {
if (object != NULL) {
impl_.AddCleanup(object, &internal::arena_destruct_object<T>);
}
}
// Adds a custom member function on an object to the list of destructors that
// will be manually called when the arena is destroyed or reset. This differs
// from OwnDestructor() in that any member function may be specified, not only
// the class destructor.
GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE void OwnCustomDestructor(
void* object, void (*destruct)(void*)) {
impl_.AddCleanup(object, destruct);
}
// Retrieves the arena associated with |value| if |value| is an arena-capable
// message, or NULL otherwise. This differs from value->GetArena() in that the
// latter is a virtual call, while this method is a templated call that
// resolves at compile-time.
template <typename T>
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE static Arena* GetArena(
const T* value) {
return GetArenaInternal(value, is_arena_constructable<T>());
}
template <typename T>
class InternalHelper {
template <typename U>
static char DestructorSkippable(const typename U::DestructorSkippable_*);
template <typename U>
static double DestructorSkippable(...);
typedef std::integral_constant<
bool, sizeof(DestructorSkippable<T>(static_cast<const T*>(0))) ==
sizeof(char) ||
std::is_trivially_destructible<T>::value>
is_destructor_skippable;
template <typename U>
static char ArenaConstructable(
const typename U::InternalArenaConstructable_*);
template <typename U>
static double ArenaConstructable(...);
typedef std::integral_constant<bool, sizeof(ArenaConstructable<T>(
static_cast<const T*>(0))) ==
sizeof(char)>
is_arena_constructable;
template <typename... Args>
static T* Construct(void* ptr, Args&&... args) {
return new (ptr) T(std::forward<Args>(args)...);
}
static Arena* GetArena(const T* p) { return p->GetArenaNoVirtual(); }
friend class Arena;
};
// Helper typetraits that indicates support for arenas in a type T at compile
// time. This is public only to allow construction of higher-level templated
// utilities.
//
// is_arena_constructable<T>::value is true if the message type T has arena
// support enabled, and false otherwise.
//
// is_destructor_skippable<T>::value is true if the message type T has told
// the arena that it is safe to skip the destructor, and false otherwise.
//
// This is inside Arena because only Arena has the friend relationships
// necessary to see the underlying generated code traits.
template <typename T>
struct is_arena_constructable : InternalHelper<T>::is_arena_constructable {};
template <typename T>
struct is_destructor_skippable : InternalHelper<T>::is_destructor_skippable {
};
private:
template <typename T, typename... Args>
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE static T* CreateMessageInternal(
Arena* arena, Args&&... args) {
static_assert(
InternalHelper<T>::is_arena_constructable::value,
"CreateMessage can only construct types that are ArenaConstructable");
if (arena == NULL) {
return new T(nullptr, std::forward<Args>(args)...);
} else {
return arena->DoCreateMessage<T>(std::forward<Args>(args)...);
}
}
// This specialization for no arguments is necessary, because its behavior is
// slightly different. When the arena pointer is nullptr, it calls T()
// instead of T(nullptr).
template <typename T>
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE static T* CreateMessageInternal(
Arena* arena) {
static_assert(
InternalHelper<T>::is_arena_constructable::value,
"CreateMessage can only construct types that are ArenaConstructable");
if (arena == NULL) {
return new T();
} else {
return arena->DoCreateMessage<T>();
}
}
template <typename T, typename... Args>
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE static T* CreateInternal(
Arena* arena, Args&&... args) {
if (arena == NULL) {
return new T(std::forward<Args>(args)...);
} else {
return arena->DoCreate<T>(std::is_trivially_destructible<T>::value,
std::forward<Args>(args)...);
}
}
void CallDestructorHooks();
void OnArenaAllocation(const std::type_info* allocated_type, size_t n) const;
inline void AllocHook(const std::type_info* allocated_type, size_t n) const {
if (GOOGLE_PREDICT_FALSE(hooks_cookie_ != NULL)) {
OnArenaAllocation(allocated_type, n);
}
}
// Allocate and also optionally call on_arena_allocation callback with the
// allocated type info when the hooks are in place in ArenaOptions and
// the cookie is not null.
template <typename T>
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE void* AllocateInternal(
bool skip_explicit_ownership) {
const size_t n = internal::AlignUpTo8(sizeof(T));
AllocHook(RTTI_TYPE_ID(T), n);
// Monitor allocation if needed.
if (skip_explicit_ownership) {
return impl_.AllocateAligned(n);
} else {
return impl_.AllocateAlignedAndAddCleanup(
n, &internal::arena_destruct_object<T>);
}
}
// CreateMessage<T> requires that T supports arenas, but this private method
// works whether or not T supports arenas. These are not exposed to user code
// as it can cause confusing API usages, and end up having double free in
// user code. These are used only internally from LazyField and Repeated
// fields, since they are designed to work in all mode combinations.
template <typename Msg, typename... Args>
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE static Msg* DoCreateMaybeMessage(
Arena* arena, std::true_type, Args&&... args) {
return CreateMessageInternal<Msg>(arena, std::forward<Args>(args)...);
}
template <typename T, typename... Args>
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE static T* DoCreateMaybeMessage(
Arena* arena, std::false_type, Args&&... args) {
return CreateInternal<T>(arena, std::forward<Args>(args)...);
}
template <typename T, typename... Args>
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE static T* CreateMaybeMessage(
Arena* arena, Args&&... args) {
return DoCreateMaybeMessage<T>(arena, is_arena_constructable<T>(),
std::forward<Args>(args)...);
}
template <typename T, typename... Args>
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE static T* CreateNoMessage(
Arena* arena, std::true_type, Args&&... args) {
// User is constructing with Create() despite the fact that T supports arena
// construction. In this case we have to delegate to CreateInternal(), and
// we can't use any CreateMaybeMessage() specialization that may be defined.
return CreateInternal<T>(arena, std::forward<Args>(args)...);
}
template <typename T, typename... Args>
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE static T* CreateNoMessage(
Arena* arena, std::false_type, Args&&... args) {
// User is constructing with Create() and the type does not support arena
// construction. In this case we can delegate to CreateMaybeMessage() and
// use any specialization that may be available for that.
return CreateMaybeMessage<T>(arena, std::forward<Args>(args)...);
}
// Just allocate the required size for the given type assuming the
// type has a trivial constructor.
template <typename T>
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE T* CreateInternalRawArray(
size_t num_elements) {
GOOGLE_CHECK_LE(num_elements, std::numeric_limits<size_t>::max() / sizeof(T))
<< "Requested size is too large to fit into size_t.";
const size_t n = internal::AlignUpTo8(sizeof(T) * num_elements);
// Monitor allocation if needed.
AllocHook(RTTI_TYPE_ID(T), n);
return static_cast<T*>(impl_.AllocateAligned(n));
}
template <typename T, typename... Args>
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE T* DoCreate(
bool skip_explicit_ownership, Args&&... args) {
return new (AllocateInternal<T>(skip_explicit_ownership))
T(std::forward<Args>(args)...);
}
template <typename T, typename... Args>
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE T* DoCreateMessage(Args&&... args) {
return InternalHelper<T>::Construct(
AllocateInternal<T>(InternalHelper<T>::is_destructor_skippable::value),
this, std::forward<Args>(args)...);
}
// CreateInArenaStorage is used to implement map field. Without it,
// google::protobuf::Map need to call generated message's protected arena constructor,
// which needs to declare google::protobuf::Map as friend of generated message.
template <typename T>
static void CreateInArenaStorage(T* ptr, Arena* arena) {
CreateInArenaStorageInternal(ptr, arena,
typename is_arena_constructable<T>::type());
RegisterDestructorInternal(
ptr, arena,
typename InternalHelper<T>::is_destructor_skippable::type());
}
template <typename T>
static void CreateInArenaStorageInternal(T* ptr, Arena* arena,
std::true_type) {
InternalHelper<T>::Construct(ptr, arena);
}
template <typename T>
static void CreateInArenaStorageInternal(T* ptr, Arena* /* arena */,
std::false_type) {
new (ptr) T();
}
template <typename T>
static void RegisterDestructorInternal(T* /* ptr */, Arena* /* arena */,
std::true_type) {}
template <typename T>
static void RegisterDestructorInternal(T* ptr, Arena* arena,
std::false_type) {
arena->OwnDestructor(ptr);
}
// These implement Own(), which registers an object for deletion (destructor
// call and operator delete()). The second parameter has type 'true_type' if T
// is a subtype of ::google::protobuf::Message and 'false_type' otherwise. Collapsing
// all template instantiations to one for generic Message reduces code size,
// using the virtual destructor instead.
template <typename T>
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE void OwnInternal(T* object,
std::true_type) {
if (object != NULL) {
impl_.AddCleanup(object, &internal::arena_delete_object<Message>);
}
}
template <typename T>
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE void OwnInternal(T* object,
std::false_type) {
if (object != NULL) {
impl_.AddCleanup(object, &internal::arena_delete_object<T>);
}
}
// Implementation for GetArena(). Only message objects with
// InternalArenaConstructable_ tags can be associated with an arena, and such
// objects must implement a GetArenaNoVirtual() method.
template <typename T>
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE static Arena* GetArenaInternal(
const T* value, std::true_type) {
return InternalHelper<T>::GetArena(value);
}
template <typename T>
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE static Arena* GetArenaInternal(
const T* /* value */, std::false_type) {
return NULL;
}
// For friends of arena.
void* AllocateAligned(size_t n) {
AllocHook(NULL, n);
return impl_.AllocateAligned(internal::AlignUpTo8(n));
}
internal::ArenaImpl impl_;
void (*on_arena_allocation_)(const std::type_info* allocated_type,
uint64 alloc_size, void* cookie);
void (*on_arena_reset_)(Arena* arena, void* cookie, uint64 space_used);
void (*on_arena_destruction_)(Arena* arena, void* cookie, uint64 space_used);
// The arena may save a cookie it receives from the external on_init hook
// and then use it when calling the on_reset and on_destruction hooks.
void* hooks_cookie_;
template <typename Type>
friend class internal::GenericTypeHandler;
friend struct internal::ArenaStringPtr; // For AllocateAligned.
friend class internal::LazyField; // For CreateMaybeMessage.
friend class MessageLite;
template <typename Key, typename T>
friend class Map;
};
// Defined above for supporting environments without RTTI.
#undef RTTI_TYPE_ID
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_ARENA_H__

View File

@ -0,0 +1,321 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// This file defines an Arena allocator for better allocation performance.
#ifndef GOOGLE_PROTOBUF_ARENA_IMPL_H__
#define GOOGLE_PROTOBUF_ARENA_IMPL_H__
#include <atomic>
#include <limits>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/port.h>
#ifdef ADDRESS_SANITIZER
#include <sanitizer/asan_interface.h>
#endif // ADDRESS_SANITIZER
namespace google {
namespace protobuf {
namespace internal {
inline size_t AlignUpTo8(size_t n) {
// Align n to next multiple of 8 (from Hacker's Delight, Chapter 3.)
return (n + 7) & -8;
}
// This class provides the core Arena memory allocation library. Different
// implementations only need to implement the public interface below.
// Arena is not a template type as that would only be useful if all protos
// in turn would be templates, which will/cannot happen. However separating
// the memory allocation part from the cruft of the API users expect we can
// use #ifdef the select the best implementation based on hardware / OS.
class LIBPROTOBUF_EXPORT ArenaImpl {
public:
struct Options {
size_t start_block_size;
size_t max_block_size;
char* initial_block;
size_t initial_block_size;
void* (*block_alloc)(size_t);
void (*block_dealloc)(void*, size_t);
template <typename O>
explicit Options(const O& options)
: start_block_size(options.start_block_size),
max_block_size(options.max_block_size),
initial_block(options.initial_block),
initial_block_size(options.initial_block_size),
block_alloc(options.block_alloc),
block_dealloc(options.block_dealloc) {}
};
template <typename O>
explicit ArenaImpl(const O& options) : options_(options) {
if (options_.initial_block != NULL && options_.initial_block_size > 0) {
GOOGLE_CHECK_GE(options_.initial_block_size, sizeof(Block))
<< ": Initial block size too small for header.";
initial_block_ = reinterpret_cast<Block*>(options_.initial_block);
} else {
initial_block_ = NULL;
}
Init();
}
// Destructor deletes all owned heap allocated objects, and destructs objects
// that have non-trivial destructors, except for proto2 message objects whose
// destructors can be skipped. Also, frees all blocks except the initial block
// if it was passed in.
~ArenaImpl();
uint64 Reset();
uint64 SpaceAllocated() const;
uint64 SpaceUsed() const;
void* AllocateAligned(size_t n);
void* AllocateAlignedAndAddCleanup(size_t n, void (*cleanup)(void*));
// Add object pointer and cleanup function pointer to the list.
void AddCleanup(void* elem, void (*cleanup)(void*));
private:
void* AllocateAlignedFallback(size_t n);
void* AllocateAlignedAndAddCleanupFallback(size_t n, void (*cleanup)(void*));
void AddCleanupFallback(void* elem, void (*cleanup)(void*));
// Node contains the ptr of the object to be cleaned up and the associated
// cleanup function ptr.
struct CleanupNode {
void* elem; // Pointer to the object to be cleaned up.
void (*cleanup)(void*); // Function pointer to the destructor or deleter.
};
// Cleanup uses a chunked linked list, to reduce pointer chasing.
struct CleanupChunk {
static size_t SizeOf(size_t i) {
return sizeof(CleanupChunk) + (sizeof(CleanupNode) * (i - 1));
}
size_t size; // Total elements in the list.
CleanupChunk* next; // Next node in the list.
CleanupNode nodes[1]; // True length is |size|.
};
class Block;
// A thread-unsafe Arena that can only be used within its owning thread.
class LIBPROTOBUF_EXPORT SerialArena {
public:
// The allocate/free methods here are a little strange, since SerialArena is
// allocated inside a Block which it also manages. This is to avoid doing
// an extra allocation for the SerialArena itself.
// Creates a new SerialArena inside Block* and returns it.
static SerialArena* New(Block* b, void* owner, ArenaImpl* arena);
// Destroys this SerialArena, freeing all blocks with the given dealloc
// function, except any block equal to |initial_block|.
static uint64 Free(SerialArena* serial, Block* initial_block,
void (*block_dealloc)(void*, size_t));
void CleanupList();
uint64 SpaceUsed() const;
void* AllocateAligned(size_t n) {
GOOGLE_DCHECK_EQ(internal::AlignUpTo8(n), n); // Must be already aligned.
GOOGLE_DCHECK_GE(limit_, ptr_);
if (GOOGLE_PREDICT_FALSE(static_cast<size_t>(limit_ - ptr_) < n)) {
return AllocateAlignedFallback(n);
}
void* ret = ptr_;
ptr_ += n;
#ifdef ADDRESS_SANITIZER
ASAN_UNPOISON_MEMORY_REGION(ret, n);
#endif // ADDRESS_SANITIZER
return ret;
}
void AddCleanup(void* elem, void (*cleanup)(void*)) {
if (GOOGLE_PREDICT_FALSE(cleanup_ptr_ == cleanup_limit_)) {
AddCleanupFallback(elem, cleanup);
return;
}
cleanup_ptr_->elem = elem;
cleanup_ptr_->cleanup = cleanup;
cleanup_ptr_++;
}
void* AllocateAlignedAndAddCleanup(size_t n, void (*cleanup)(void*)) {
void* ret = AllocateAligned(n);
AddCleanup(ret, cleanup);
return ret;
}
void* owner() const { return owner_; }
SerialArena* next() const { return next_; }
void set_next(SerialArena* next) { next_ = next; }
private:
void* AllocateAlignedFallback(size_t n);
void AddCleanupFallback(void* elem, void (*cleanup)(void*));
void CleanupListFallback();
ArenaImpl* arena_; // Containing arena.
void* owner_; // &ThreadCache of this thread;
Block* head_; // Head of linked list of blocks.
CleanupChunk* cleanup_; // Head of cleanup list.
SerialArena* next_; // Next SerialArena in this linked list.
// Next pointer to allocate from. Always 8-byte aligned. Points inside
// head_ (and head_->pos will always be non-canonical). We keep these
// here to reduce indirection.
char* ptr_;
char* limit_;
// Next CleanupList members to append to. These point inside cleanup_.
CleanupNode* cleanup_ptr_;
CleanupNode* cleanup_limit_;
};
// Blocks are variable length malloc-ed objects. The following structure
// describes the common header for all blocks.
class LIBPROTOBUF_EXPORT Block {
public:
Block(size_t size, Block* next);
char* Pointer(size_t n) {
GOOGLE_DCHECK(n <= size_);
return reinterpret_cast<char*>(this) + n;
}
Block* next() const { return next_; }
size_t pos() const { return pos_; }
size_t size() const { return size_; }
void set_pos(size_t pos) { pos_ = pos; }
private:
Block* next_; // Next block for this thread.
size_t pos_;
size_t size_;
// data follows
};
struct ThreadCache {
#if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
// If we are using the ThreadLocalStorage class to store the ThreadCache,
// then the ThreadCache's default constructor has to be responsible for
// initializing it.
ThreadCache() : last_lifecycle_id_seen(-1), last_serial_arena(NULL) {}
#endif
// The ThreadCache is considered valid as long as this matches the
// lifecycle_id of the arena being used.
int64 last_lifecycle_id_seen;
SerialArena* last_serial_arena;
};
static std::atomic<int64> lifecycle_id_generator_;
#if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
// Android ndk does not support GOOGLE_THREAD_LOCAL keyword so we use a custom thread
// local storage class we implemented.
// iOS also does not support the GOOGLE_THREAD_LOCAL keyword.
static ThreadCache& thread_cache();
#elif defined(PROTOBUF_USE_DLLS)
// Thread local variables cannot be exposed through DLL interface but we can
// wrap them in static functions.
static ThreadCache& thread_cache();
#else
static GOOGLE_THREAD_LOCAL ThreadCache thread_cache_;
static ThreadCache& thread_cache() { return thread_cache_; }
#endif
void Init();
// Free all blocks and return the total space used which is the sums of sizes
// of the all the allocated blocks.
uint64 FreeBlocks();
// Delete or Destruct all objects owned by the arena.
void CleanupList();
inline void CacheSerialArena(SerialArena* serial) {
thread_cache().last_serial_arena = serial;
thread_cache().last_lifecycle_id_seen = lifecycle_id_;
// TODO(haberman): evaluate whether we would gain efficiency by getting rid
// of hint_. It's the only write we do to ArenaImpl in the allocation path,
// which will dirty the cache line.
hint_.store(serial, std::memory_order_release);
}
std::atomic<SerialArena*>
threads_; // Pointer to a linked list of SerialArena.
std::atomic<SerialArena*> hint_; // Fast thread-local block access
std::atomic<size_t> space_allocated_; // Total size of all allocated blocks.
Block *initial_block_; // If non-NULL, points to the block that came from
// user data.
Block* NewBlock(Block* last_block, size_t min_bytes);
SerialArena* GetSerialArena();
bool GetSerialArenaFast(SerialArena** arena);
SerialArena* GetSerialArenaFallback(void* me);
int64 lifecycle_id_; // Unique for each arena. Changes on Reset().
Options options_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ArenaImpl);
// All protos have pointers back to the arena hence Arena must have
// pointer stability.
ArenaImpl(ArenaImpl&&) = delete;
ArenaImpl& operator=(ArenaImpl&&) = delete;
public:
// kBlockHeaderSize is sizeof(Block), aligned up to the nearest multiple of 8
// to protect the invariant that pos is always at a multiple of 8.
static const size_t kBlockHeaderSize = (sizeof(Block) + 7) & -8;
static const size_t kSerialArenaSize = (sizeof(SerialArena) + 7) & -8;
static_assert(kBlockHeaderSize % 8 == 0,
"kBlockHeaderSize must be a multiple of 8.");
static_assert(kSerialArenaSize % 8 == 0,
"kSerialArenaSize must be a multiple of 8.");
};
} // namespace internal
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_ARENA_IMPL_H__

View File

@ -0,0 +1,50 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/arena_test_util.h>
#define EXPECT_EQ GOOGLE_CHECK_EQ
namespace google {
namespace protobuf {
namespace internal {
NoHeapChecker::~NoHeapChecker() {
capture_alloc.Unhook();
EXPECT_EQ(0, capture_alloc.alloc_count());
EXPECT_EQ(0, capture_alloc.free_count());
}
} // namespace internal
} // namespace protobuf
} // namespace google

View File

@ -0,0 +1,91 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef GOOGLE_PROTOBUF_ARENA_TEST_UTIL_H__
#define GOOGLE_PROTOBUF_ARENA_TEST_UTIL_H__
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/arena.h>
namespace google {
namespace protobuf {
template <typename T, bool use_arena>
void TestParseCorruptedString(const T& message) {
int success_count = 0;
string s = message.SerializeAsString();
const int kMaxIters = 900;
const int stride = s.size() <= kMaxIters ? 1 : s.size() / kMaxIters;
const int start = stride == 1 || use_arena ? 0 : (stride + 1) / 2;
for (int i = start; i < s.size(); i += stride) {
for (int c = 1 + (i % 17); c < 256; c += 2 * c + (i & 3)) {
s[i] ^= c;
google::protobuf::Arena arena;
T* message =
google::protobuf::Arena::CreateMessage<T>(use_arena ? &arena : nullptr);
if (message->ParseFromString(s)) {
++success_count;
}
if (!use_arena) {
delete message;
}
s[i] ^= c; // Restore s to its original state.
}
}
// This next line is a low bar. But getting through the test without crashing
// due to use-after-free or other bugs is a big part of what we're checking.
GOOGLE_CHECK_GT(success_count, 0);
}
namespace internal {
class NoHeapChecker {
public:
NoHeapChecker() {
capture_alloc.Hook();
}
~NoHeapChecker();
private:
class NewDeleteCapture {
public:
// TOOD(xiaofeng): Implement this for opensource protobuf.
void Hook() {}
void Unhook() {}
int alloc_count() { return 0; }
int free_count() { return 0; }
} capture_alloc;
};
} // namespace internal
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_ARENA_TEST_UTIL_H__

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,43 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// The ArenaString implementation is not included in the open-source release. Do
// not include this file in the distribution.
#include <google/protobuf/arenastring.h>
namespace google {
namespace protobuf {
namespace internal {
} // namespace internal
} // namespace protobuf
} // namespace google

View File

@ -0,0 +1,403 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef GOOGLE_PROTOBUF_ARENASTRING_H__
#define GOOGLE_PROTOBUF_ARENASTRING_H__
#include <string>
#include <google/protobuf/arena.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/fastmem.h>
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/port.h>
// This is the implementation of arena string fields written for the open-source
// release. The ArenaStringPtr struct below is an internal implementation class
// and *should not be used* by user code. It is used to collect string
// operations together into one place and abstract away the underlying
// string-field pointer representation, so that (for example) an alternate
// implementation that knew more about ::std::string's internals could integrate more
// closely with the arena allocator.
namespace google {
namespace protobuf {
namespace internal {
template <typename T>
class TaggedPtr {
public:
void Set(T* p) { ptr_ = reinterpret_cast<uintptr_t>(p); }
T* Get() const { return reinterpret_cast<T*>(ptr_); }
bool IsNull() { return ptr_ == 0; }
private:
uintptr_t ptr_;
};
struct LIBPROTOBUF_EXPORT ArenaStringPtr {
inline void Set(const ::std::string* default_value,
const ::std::string& value, ::google::protobuf::Arena* arena) {
if (ptr_ == default_value) {
CreateInstance(arena, &value);
} else {
*ptr_ = value;
}
}
inline void SetLite(const ::std::string* default_value,
const ::std::string& value,
::google::protobuf::Arena* arena) {
Set(default_value, value, arena);
}
// Basic accessors.
inline const ::std::string& Get() const { return *ptr_; }
inline ::std::string* Mutable(const ::std::string* default_value,
::google::protobuf::Arena* arena) {
if (ptr_ == default_value) {
CreateInstance(arena, default_value);
}
return ptr_;
}
// Release returns a ::std::string* instance that is heap-allocated and is not
// Own()'d by any arena. If the field was not set, it returns NULL. The caller
// retains ownership. Clears this field back to NULL state. Used to implement
// release_<field>() methods on generated classes.
inline ::std::string* Release(const ::std::string* default_value,
::google::protobuf::Arena* arena) {
if (ptr_ == default_value) {
return NULL;
}
return ReleaseNonDefault(default_value, arena);
}
// Similar to Release, but ptr_ cannot be the default_value.
inline ::std::string* ReleaseNonDefault(
const ::std::string* default_value, ::google::protobuf::Arena* arena) {
GOOGLE_DCHECK(!IsDefault(default_value));
::std::string* released = NULL;
if (arena != NULL) {
// ptr_ is owned by the arena.
released = new ::std::string;
released->swap(*ptr_);
} else {
released = ptr_;
}
ptr_ = const_cast< ::std::string* >(default_value);
return released;
}
// UnsafeArenaRelease returns a ::std::string*, but it may be arena-owned (i.e.
// have its destructor already registered) if arena != NULL. If the field was
// not set, this returns NULL. This method clears this field back to NULL
// state. Used to implement unsafe_arena_release_<field>() methods on
// generated classes.
inline ::std::string* UnsafeArenaRelease(const ::std::string* default_value,
::google::protobuf::Arena* /* arena */) {
if (ptr_ == default_value) {
return NULL;
}
::std::string* released = ptr_;
ptr_ = const_cast< ::std::string* >(default_value);
return released;
}
// Takes a string that is heap-allocated, and takes ownership. The string's
// destructor is registered with the arena. Used to implement
// set_allocated_<field> in generated classes.
inline void SetAllocated(const ::std::string* default_value,
::std::string* value, ::google::protobuf::Arena* arena) {
if (arena == NULL && ptr_ != default_value) {
Destroy(default_value, arena);
}
if (value != NULL) {
ptr_ = value;
if (arena != NULL) {
arena->Own(value);
}
} else {
ptr_ = const_cast< ::std::string* >(default_value);
}
}
// Takes a string that has lifetime equal to the arena's lifetime. The arena
// must be non-null. It is safe only to pass this method a value returned by
// UnsafeArenaRelease() on another field of a message in the same arena. Used
// to implement unsafe_arena_set_allocated_<field> in generated classes.
inline void UnsafeArenaSetAllocated(const ::std::string* default_value,
::std::string* value,
::google::protobuf::Arena* /* arena */) {
if (value != NULL) {
ptr_ = value;
} else {
ptr_ = const_cast< ::std::string* >(default_value);
}
}
// Swaps internal pointers. Arena-safety semantics: this is guarded by the
// logic in Swap()/UnsafeArenaSwap() at the message level, so this method is
// 'unsafe' if called directly.
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE void Swap(ArenaStringPtr* other) {
std::swap(ptr_, other->ptr_);
}
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE void Swap(
ArenaStringPtr* other, const ::std::string* default_value, Arena* arena) {
#ifndef NDEBUG
// For debug builds, we swap the contents of the string, rather than the
// string instances themselves. This invalidates previously taken const
// references that are (per our documentation) invalidated by calling Swap()
// on the message.
//
// If both strings are the default_value, swapping is uninteresting.
// Otherwise, we use ArenaStringPtr::Mutable() to access the string, to
// ensure that we do not try to mutate default_value itself.
if (IsDefault(default_value) && other->IsDefault(default_value)) {
return;
}
::std::string* this_ptr = Mutable(default_value, arena);
::std::string* other_ptr = other->Mutable(default_value, arena);
this_ptr->swap(*other_ptr);
#else
std::swap(ptr_, other->ptr_);
#endif
}
// Frees storage (if not on an arena).
inline void Destroy(const ::std::string* default_value,
::google::protobuf::Arena* arena) {
if (arena == NULL && ptr_ != default_value) {
delete ptr_;
}
}
// Clears content, but keeps allocated string if arena != NULL, to avoid the
// overhead of heap operations. After this returns, the content (as seen by
// the user) will always be the empty string. Assumes that |default_value|
// is an empty string.
inline void ClearToEmpty(const ::std::string* default_value,
::google::protobuf::Arena* /* arena */) {
if (ptr_ == default_value) {
// Already set to default (which is empty) -- do nothing.
} else {
ptr_->clear();
}
}
// Clears content, assuming that the current value is not the empty string
// default.
inline void ClearNonDefaultToEmpty() {
ptr_->clear();
}
inline void ClearNonDefaultToEmptyNoArena() {
ptr_->clear();
}
// Clears content, but keeps allocated string if arena != NULL, to avoid the
// overhead of heap operations. After this returns, the content (as seen by
// the user) will always be equal to |default_value|.
inline void ClearToDefault(const ::std::string* default_value,
::google::protobuf::Arena* /* arena */) {
if (ptr_ == default_value) {
// Already set to default -- do nothing.
} else {
// Have another allocated string -- rather than throwing this away and
// resetting ptr_ to the canonical default string instance, we just reuse
// this instance.
*ptr_ = *default_value;
}
}
// Called from generated code / reflection runtime only. Resets value to point
// to a default string pointer, with the semantics that this ArenaStringPtr
// does not own the pointed-to memory. Disregards initial value of ptr_ (so
// this is the *ONLY* safe method to call after construction or when
// reinitializing after becoming the active field in a oneof union).
inline void UnsafeSetDefault(const ::std::string* default_value) {
// Casting away 'const' is safe here: accessors ensure that ptr_ is only
// returned as a const if it is equal to default_value.
ptr_ = const_cast< ::std::string* >(default_value);
}
// The 'NoArena' variants of methods below assume arena == NULL and are
// optimized to provide very little overhead relative to a raw string pointer
// (while still being in-memory compatible with other code that assumes
// ArenaStringPtr). Note the invariant that a class instance that has only
// ever been mutated by NoArena methods must *only* be in the String state
// (i.e., tag bits are not used), *NEVER* ArenaString. This allows all
// tagged-pointer manipulations to be avoided.
inline void SetNoArena(const ::std::string* default_value,
const ::std::string& value) {
if (ptr_ == default_value) {
CreateInstanceNoArena(&value);
} else {
*ptr_ = value;
}
}
#if LANG_CXX11
void SetNoArena(const ::std::string* default_value, ::std::string&& value) {
if (IsDefault(default_value)) {
ptr_ = new ::std::string(std::move(value));
} else {
*ptr_ = std::move(value);
}
}
#endif
void AssignWithDefault(const ::std::string* default_value, ArenaStringPtr value);
inline const ::std::string& GetNoArena() const { return *ptr_; }
inline ::std::string* MutableNoArena(const ::std::string* default_value) {
if (ptr_ == default_value) {
CreateInstanceNoArena(default_value);
}
return ptr_;
}
inline ::std::string* ReleaseNoArena(const ::std::string* default_value) {
if (ptr_ == default_value) {
return NULL;
} else {
return ReleaseNonDefaultNoArena(default_value);
}
}
inline ::std::string* ReleaseNonDefaultNoArena(
const ::std::string* default_value) {
GOOGLE_DCHECK(!IsDefault(default_value));
::std::string* released = ptr_;
ptr_ = const_cast< ::std::string* >(default_value);
return released;
}
inline void SetAllocatedNoArena(const ::std::string* default_value,
::std::string* value) {
if (ptr_ != default_value) {
delete ptr_;
}
if (value != NULL) {
ptr_ = value;
} else {
ptr_ = const_cast< ::std::string* >(default_value);
}
}
inline void DestroyNoArena(const ::std::string* default_value) {
if (ptr_ != default_value) {
delete ptr_;
}
}
inline void ClearToEmptyNoArena(const ::std::string* default_value) {
if (ptr_ == default_value) {
// Nothing: already equal to default (which is the empty string).
} else {
ptr_->clear();
}
}
inline void ClearToDefaultNoArena(const ::std::string* default_value) {
if (ptr_ == default_value) {
// Nothing: already set to default.
} else {
// Reuse existing allocated instance.
*ptr_ = *default_value;
}
}
// Internal accessor used only at parse time to provide direct access to the
// raw pointer from the shared parse routine (in the non-arenas case). The
// parse routine does the string allocation in order to save code size in the
// generated parsing code.
inline ::std::string** UnsafeRawStringPointer() {
return &ptr_;
}
inline bool IsDefault(const ::std::string* default_value) const {
return ptr_ == default_value;
}
// Internal accessors!!!!
void UnsafeSetTaggedPointer(TaggedPtr< ::std::string> value) {
ptr_ = value.Get();
}
// Generated code only! An optimization, in certain cases the generated
// code is certain we can obtain a string with no default checks and
// tag tests.
::std::string* UnsafeMutablePointer() { return ptr_; }
private:
::std::string* ptr_;
GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE
void CreateInstance(::google::protobuf::Arena* arena,
const ::std::string* initial_value) {
GOOGLE_DCHECK(initial_value != NULL);
// uses "new ::std::string" when arena is nullptr
ptr_ = Arena::Create< ::std::string >(arena, *initial_value);
}
GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE
void CreateInstanceNoArena(const ::std::string* initial_value) {
GOOGLE_DCHECK(initial_value != NULL);
ptr_ = new ::std::string(*initial_value);
}
};
} // namespace internal
} // namespace protobuf
namespace protobuf {
namespace internal {
inline void ArenaStringPtr::AssignWithDefault(const ::std::string* default_value,
ArenaStringPtr value) {
const ::std::string* me = *UnsafeRawStringPointer();
const ::std::string* other = *value.UnsafeRawStringPointer();
// If the pointers are the same then do nothing.
if (me != other) {
SetNoArena(default_value, value.GetNoArena());
}
}
} // namespace internal
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_ARENASTRING_H__

View File

@ -0,0 +1,138 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Based on mvels@'s frankenstring.
#include <google/protobuf/arenastring.h>
#include <algorithm>
#include <cstdlib>
#include <memory>
#include <string>
#include <vector>
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
#include <gtest/gtest.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
namespace google {
using google::protobuf::internal::ArenaStringPtr;
namespace protobuf {
static string WrapString(const char* value) {
return value;
}
// Test ArenaStringPtr with arena == NULL.
TEST(ArenaStringPtrTest, ArenaStringPtrOnHeap) {
ArenaStringPtr field;
::std::string default_value = "default";
field.UnsafeSetDefault(&default_value);
EXPECT_EQ(string("default"), field.Get());
field.Set(&default_value, WrapString("Test short"), NULL);
EXPECT_EQ(string("Test short"), field.Get());
field.Set(&default_value, WrapString("Test long long long long value"), NULL);
EXPECT_EQ(string("Test long long long long value"), field.Get());
field.Set(&default_value, string(""), NULL);
field.Destroy(&default_value, NULL);
ArenaStringPtr field2;
field2.UnsafeSetDefault(&default_value);
::std::string* mut = field2.Mutable(&default_value, NULL);
EXPECT_EQ(mut, field2.Mutable(&default_value, NULL));
EXPECT_EQ(mut, &field2.Get());
EXPECT_NE(&default_value, mut);
EXPECT_EQ(string("default"), *mut);
*mut = "Test long long long long value"; // ensure string allocates storage
EXPECT_EQ(string("Test long long long long value"), field2.Get());
field2.Destroy(&default_value, NULL);
}
TEST(ArenaStringPtrTest, ArenaStringPtrOnArena) {
google::protobuf::Arena arena;
ArenaStringPtr field;
::std::string default_value = "default";
field.UnsafeSetDefault(&default_value);
EXPECT_EQ(string("default"), field.Get());
field.Set(&default_value, WrapString("Test short"), &arena);
EXPECT_EQ(string("Test short"), field.Get());
field.Set(&default_value, WrapString("Test long long long long value"),
&arena);
EXPECT_EQ(string("Test long long long long value"), field.Get());
field.Set(&default_value, string(""), &arena);
field.Destroy(&default_value, &arena);
ArenaStringPtr field2;
field2.UnsafeSetDefault(&default_value);
::std::string* mut = field2.Mutable(&default_value, &arena);
EXPECT_EQ(mut, field2.Mutable(&default_value, &arena));
EXPECT_EQ(mut, &field2.Get());
EXPECT_NE(&default_value, mut);
EXPECT_EQ(string("default"), *mut);
*mut = "Test long long long long value"; // ensure string allocates storage
EXPECT_EQ(string("Test long long long long value"), field2.Get());
field2.Destroy(&default_value, &arena);
}
TEST(ArenaStringPtrTest, ArenaStringPtrOnArenaNoSSO) {
google::protobuf::Arena arena;
ArenaStringPtr field;
::std::string default_value = "default";
field.UnsafeSetDefault(&default_value);
EXPECT_EQ(string("default"), field.Get());
// Avoid triggering the SSO optimization by setting the string to something
// larger than the internal buffer.
field.Set(&default_value, WrapString("Test long long long long value"),
&arena);
EXPECT_EQ(string("Test long long long long value"), field.Get());
field.Set(&default_value, string(""), &arena);
field.Destroy(&default_value, &arena);
ArenaStringPtr field2;
field2.UnsafeSetDefault(&default_value);
::std::string* mut = field2.Mutable(&default_value, &arena);
EXPECT_EQ(mut, field2.Mutable(&default_value, &arena));
EXPECT_EQ(mut, &field2.Get());
EXPECT_NE(&default_value, mut);
EXPECT_EQ(string("default"), *mut);
*mut = "Test long long long long value"; // ensure string allocates storage
EXPECT_EQ(string("Test long long long long value"), field2.Get());
field2.Destroy(&default_value, &arena);
}
} // namespace protobuf
} // namespace google

View File

@ -0,0 +1,2 @@
[LocalizedFileNames]
libprotobuf.dll=@libprotobuf.dll,0

View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6a632a75d0aa646d4acd68e765ac83277382e373d28c859a3cf8cd36d7948ba0
size 2671104

View File

@ -0,0 +1,166 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <google/protobuf/compiler/annotation_test_util.h>
#include <memory>
#include <google/protobuf/compiler/code_generator.h>
#include <google/protobuf/compiler/command_line_interface.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/testing/file.h>
#include <google/protobuf/testing/file.h>
#include <google/protobuf/testing/googletest.h>
#include <gtest/gtest.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace annotation_test_util {
namespace {
// A CodeGenerator that captures the FileDescriptor it's passed as a
// FileDescriptorProto.
class DescriptorCapturingGenerator : public CodeGenerator {
public:
// Does not own file; file must outlive the Generator.
explicit DescriptorCapturingGenerator(FileDescriptorProto* file)
: file_(file) {}
virtual bool Generate(const FileDescriptor* file, const string& parameter,
GeneratorContext* context, string* error) const {
file->CopyTo(file_);
return true;
}
private:
FileDescriptorProto* file_;
};
} // namespace
void AddFile(const string& filename, const string& data) {
GOOGLE_CHECK_OK(File::SetContents(TestTempDir() + "/" + filename, data,
true));
}
bool RunProtoCompiler(const string& filename,
const string& plugin_specific_args,
CommandLineInterface* cli, FileDescriptorProto* file) {
cli->SetInputsAreProtoPathRelative(true);
DescriptorCapturingGenerator capturing_generator(file);
cli->RegisterGenerator("--capture_out", &capturing_generator, "");
string proto_path = "-I" + TestTempDir();
string capture_out = "--capture_out=" + TestTempDir();
const char* argv[] = {"protoc", proto_path.c_str(),
plugin_specific_args.c_str(), capture_out.c_str(),
filename.c_str()};
return cli->Run(5, argv) == 0;
}
bool DecodeMetadata(const string& path, GeneratedCodeInfo* info) {
string data;
GOOGLE_CHECK_OK(File::GetContents(path, &data, true));
io::ArrayInputStream input(data.data(), data.size());
return info->ParseFromZeroCopyStream(&input);
}
void FindAnnotationsOnPath(
const GeneratedCodeInfo& info, const string& source_file,
const std::vector<int>& path,
std::vector<const GeneratedCodeInfo::Annotation*>* annotations) {
for (int i = 0; i < info.annotation_size(); ++i) {
const GeneratedCodeInfo::Annotation* annotation = &info.annotation(i);
if (annotation->source_file() != source_file ||
annotation->path_size() != path.size()) {
continue;
}
int node = 0;
for (; node < path.size(); ++node) {
if (annotation->path(node) != path[node]) {
break;
}
}
if (node == path.size()) {
annotations->push_back(annotation);
}
}
}
const GeneratedCodeInfo::Annotation* FindAnnotationOnPath(
const GeneratedCodeInfo& info, const string& source_file,
const std::vector<int>& path) {
std::vector<const GeneratedCodeInfo::Annotation*> annotations;
FindAnnotationsOnPath(info, source_file, path, &annotations);
if (annotations.empty()) {
return NULL;
}
return annotations[0];
}
bool AtLeastOneAnnotationMatchesSubstring(
const string& file_content,
const std::vector<const GeneratedCodeInfo::Annotation*>& annotations,
const string& expected_text) {
for (std::vector<const GeneratedCodeInfo::Annotation*>::const_iterator
i = annotations.begin(),
e = annotations.end();
i != e; ++i) {
const GeneratedCodeInfo::Annotation* annotation = *i;
uint32 begin = annotation->begin();
uint32 end = annotation->end();
if (end < begin || end > file_content.size()) {
return false;
}
if (file_content.substr(begin, end - begin) == expected_text) {
return true;
}
}
return false;
}
bool AnnotationMatchesSubstring(const string& file_content,
const GeneratedCodeInfo::Annotation* annotation,
const string& expected_text) {
std::vector<const GeneratedCodeInfo::Annotation*> annotations;
annotations.push_back(annotation);
return AtLeastOneAnnotationMatchesSubstring(file_content, annotations,
expected_text);
}
} // namespace annotation_test_util
} // namespace compiler
} // namespace protobuf
} // namespace google

View File

@ -0,0 +1,114 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef GOOGLE_PROTOBUF_COMPILER_ANNOTATION_TEST_UTIL_H__
#define GOOGLE_PROTOBUF_COMPILER_ANNOTATION_TEST_UTIL_H__
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/testing/googletest.h>
#include <gtest/gtest.h>
// Utilities that assist in writing tests for generator annotations.
// See java/internal/annotation_unittest.cc for an example.
namespace google {
namespace protobuf {
namespace compiler {
namespace annotation_test_util {
// Struct that contains the file generated from a .proto file and its
// GeneratedCodeInfo. For example, the Java generator will fill this struct
// (for some 'foo.proto') with:
// file_path = "Foo.java"
// file_content = content of Foo.java
// file_info = parsed content of Foo.java.pb.meta
struct ExpectedOutput {
string file_path;
string file_content;
GeneratedCodeInfo file_info;
explicit ExpectedOutput(const string& file_path) : file_path(file_path) {}
};
// Creates a file with name `filename` and content `data` in temp test
// directory.
void AddFile(const string& filename, const string& data);
// Runs proto compiler. Captures proto file structrue in FileDescriptorProto.
// Files will be generated in TestTempDir() folder. Callers of this
// function must read generated files themselves.
//
// filename: source .proto file used to generate code.
// plugin_specific_args: command line arguments specific to current generator.
// For Java, this value might be "--java_out=annotate_code:test_temp_dir"
// cli: instance of command line interface to run generator. See Java's
// annotation_unittest.cc for an example of how to initialize it.
// file: output parameter, will be set to the descriptor of the proto file
// specified in filename.
bool RunProtoCompiler(const string& filename,
const string& plugin_specific_args,
CommandLineInterface* cli, FileDescriptorProto* file);
bool DecodeMetadata(const string& path, GeneratedCodeInfo* info);
// Finds all of the Annotations for a given source file and path.
// See Location.path in http://google/protobuf/descriptor.proto for
// explanation of what path vector is.
void FindAnnotationsOnPath(
const GeneratedCodeInfo& info, const string& source_file,
const std::vector<int>& path,
std::vector<const GeneratedCodeInfo::Annotation*>* annotations);
// Finds the Annotation for a given source file and path (or returns null if it
// couldn't). If there are several annotations for given path, returns the first
// one. See Location.path in
// http://google/protobuf/descriptor.proto for explanation of what path
// vector is.
const GeneratedCodeInfo::Annotation* FindAnnotationOnPath(
const GeneratedCodeInfo& info, const string& source_file,
const std::vector<int>& path);
// Returns true if at least one of the provided annotations covers a given
// substring in file_content.
bool AtLeastOneAnnotationMatchesSubstring(
const string& file_content,
const std::vector<const GeneratedCodeInfo::Annotation*>& annotations,
const string& expected_text);
// Returns true if the provided annotation covers a given substring in
// file_content.
bool AnnotationMatchesSubstring(const string& file_content,
const GeneratedCodeInfo::Annotation* annotation,
const string& expected_text);
} // namespace annotation_test_util
} // namespace compiler
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_COMPILER_ANNOTATION_TEST_UTIL_H__

View File

@ -0,0 +1,121 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
#include <google/protobuf/compiler/code_generator.h>
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/compiler/plugin.pb.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/stubs/strutil.h>
namespace google {
namespace protobuf {
namespace compiler {
CodeGenerator::~CodeGenerator() {}
bool CodeGenerator::GenerateAll(
const std::vector<const FileDescriptor*>& files,
const string& parameter,
GeneratorContext* generator_context,
string* error) const {
// Default implemenation is just to call the per file method, and prefix any
// error string with the file to provide context.
bool succeeded = true;
for (int i = 0; i < files.size(); i++) {
const FileDescriptor* file = files[i];
succeeded = Generate(file, parameter, generator_context, error);
if (!succeeded && error && error->empty()) {
*error = "Code generator returned false but provided no error "
"description.";
}
if (error && !error->empty()) {
*error = file->name() + ": " + *error;
break;
}
if (!succeeded) {
break;
}
}
return succeeded;
}
GeneratorContext::~GeneratorContext() {}
io::ZeroCopyOutputStream*
GeneratorContext::OpenForAppend(const string& filename) {
return NULL;
}
io::ZeroCopyOutputStream* GeneratorContext::OpenForInsert(
const string& filename, const string& insertion_point) {
GOOGLE_LOG(FATAL) << "This GeneratorContext does not support insertion.";
return NULL; // make compiler happy
}
void GeneratorContext::ListParsedFiles(
std::vector<const FileDescriptor*>* output) {
GOOGLE_LOG(FATAL) << "This GeneratorContext does not support ListParsedFiles";
}
void GeneratorContext::GetCompilerVersion(Version* version) const {
version->set_major(GOOGLE_PROTOBUF_VERSION / 1000000);
version->set_minor(GOOGLE_PROTOBUF_VERSION / 1000 % 1000);
version->set_patch(GOOGLE_PROTOBUF_VERSION % 1000);
version->set_suffix(GOOGLE_PROTOBUF_VERSION_SUFFIX);
}
// Parses a set of comma-delimited name/value pairs.
void ParseGeneratorParameter(const string& text,
std::vector<std::pair<string, string> >* output) {
std::vector<string> parts = Split(text, ",", true);
for (int i = 0; i < parts.size(); i++) {
string::size_type equals_pos = parts[i].find_first_of('=');
std::pair<string, string> value;
if (equals_pos == string::npos) {
value.first = parts[i];
value.second = "";
} else {
value.first = parts[i].substr(0, equals_pos);
value.second = parts[i].substr(equals_pos + 1);
}
output->push_back(value);
}
}
} // namespace compiler
} // namespace protobuf
} // namespace google

View File

@ -0,0 +1,176 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
//
// Defines the abstract interface implemented by each of the language-specific
// code generators.
#ifndef GOOGLE_PROTOBUF_COMPILER_CODE_GENERATOR_H__
#define GOOGLE_PROTOBUF_COMPILER_CODE_GENERATOR_H__
#include <google/protobuf/stubs/common.h>
#include <string>
#include <vector>
#include <utility>
namespace google {
namespace protobuf {
namespace io { class ZeroCopyOutputStream; }
class FileDescriptor;
namespace compiler {
class AccessInfoMap;
class Version;
// Defined in this file.
class CodeGenerator;
class GeneratorContext;
// The abstract interface to a class which generates code implementing a
// particular proto file in a particular language. A number of these may
// be registered with CommandLineInterface to support various languages.
class LIBPROTOC_EXPORT CodeGenerator {
public:
inline CodeGenerator() {}
virtual ~CodeGenerator();
// Generates code for the given proto file, generating one or more files in
// the given output directory.
//
// A parameter to be passed to the generator can be specified on the command
// line. This is intended to be used to pass generator specific parameters.
// It is empty if no parameter was given. ParseGeneratorParameter (below),
// can be used to accept multiple parameters within the single parameter
// command line flag.
//
// Returns true if successful. Otherwise, sets *error to a description of
// the problem (e.g. "invalid parameter") and returns false.
virtual bool Generate(const FileDescriptor* file,
const string& parameter,
GeneratorContext* generator_context,
string* error) const = 0;
// Generates code for all given proto files.
//
// WARNING: The canonical code generator design produces one or two output
// files per input .proto file, and we do not wish to encourage alternate
// designs.
//
// A parameter is given as passed on the command line, as in |Generate()|
// above.
//
// Returns true if successful. Otherwise, sets *error to a description of
// the problem (e.g. "invalid parameter") and returns false.
virtual bool GenerateAll(const std::vector<const FileDescriptor*>& files,
const string& parameter,
GeneratorContext* generator_context,
string* error) const;
// This is no longer used, but this class is part of the opensource protobuf
// library, so it has to remain to keep vtables the same for the current
// version of the library. When protobufs does a api breaking change, the
// method can be removed.
virtual bool HasGenerateAll() const { return true; }
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CodeGenerator);
};
// CodeGenerators generate one or more files in a given directory. This
// abstract interface represents the directory to which the CodeGenerator is
// to write and other information about the context in which the Generator
// runs.
class LIBPROTOC_EXPORT GeneratorContext {
public:
inline GeneratorContext() {
}
virtual ~GeneratorContext();
// Opens the given file, truncating it if it exists, and returns a
// ZeroCopyOutputStream that writes to the file. The caller takes ownership
// of the returned object. This method never fails (a dummy stream will be
// returned instead).
//
// The filename given should be relative to the root of the source tree.
// E.g. the C++ generator, when generating code for "foo/bar.proto", will
// generate the files "foo/bar.pb.h" and "foo/bar.pb.cc"; note that
// "foo/" is included in these filenames. The filename is not allowed to
// contain "." or ".." components.
virtual io::ZeroCopyOutputStream* Open(const string& filename) = 0;
// Similar to Open() but the output will be appended to the file if exists
virtual io::ZeroCopyOutputStream* OpenForAppend(const string& filename);
// Creates a ZeroCopyOutputStream which will insert code into the given file
// at the given insertion point. See plugin.proto (plugin.pb.h) for more
// information on insertion points. The default implementation
// assert-fails -- it exists only for backwards-compatibility.
//
// WARNING: This feature is currently EXPERIMENTAL and is subject to change.
virtual io::ZeroCopyOutputStream* OpenForInsert(
const string& filename, const string& insertion_point);
// Returns a vector of FileDescriptors for all the files being compiled
// in this run. Useful for languages, such as Go, that treat files
// differently when compiled as a set rather than individually.
virtual void ListParsedFiles(std::vector<const FileDescriptor*>* output);
// Retrieves the version number of the protocol compiler associated with
// this GeneratorContext.
virtual void GetCompilerVersion(Version* version) const;
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GeneratorContext);
};
// The type GeneratorContext was once called OutputDirectory. This typedef
// provides backward compatibility.
typedef GeneratorContext OutputDirectory;
// Several code generators treat the parameter argument as holding a
// list of options separated by commas. This helper function parses
// a set of comma-delimited name/value pairs: e.g.,
// "foo=bar,baz,qux=corge"
// parses to the pairs:
// ("foo", "bar"), ("baz", ""), ("qux", "corge")
LIBPROTOC_EXPORT void ParseGeneratorParameter(
const string&, std::vector<std::pair<string, string> >*);
} // namespace compiler
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_COMPILER_CODE_GENERATOR_H__

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,435 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
//
// Implements the Protocol Compiler front-end such that it may be reused by
// custom compilers written to support other languages.
#ifndef GOOGLE_PROTOBUF_COMPILER_COMMAND_LINE_INTERFACE_H__
#define GOOGLE_PROTOBUF_COMPILER_COMMAND_LINE_INTERFACE_H__
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/hash.h>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <utility>
namespace google {
namespace protobuf {
class Descriptor; // descriptor.h
class DescriptorPool; // descriptor.h
class FileDescriptor; // descriptor.h
class FileDescriptorSet; // descriptor.h
class FileDescriptorProto; // descriptor.pb.h
template<typename T> class RepeatedPtrField; // repeated_field.h
class SimpleDescriptorDatabase; // descriptor_database.h
namespace compiler {
class CodeGenerator; // code_generator.h
class GeneratorContext; // code_generator.h
class DiskSourceTree; // importer.h
// This class implements the command-line interface to the protocol compiler.
// It is designed to make it very easy to create a custom protocol compiler
// supporting the languages of your choice. For example, if you wanted to
// create a custom protocol compiler binary which includes both the regular
// C++ support plus support for your own custom output "Foo", you would
// write a class "FooGenerator" which implements the CodeGenerator interface,
// then write a main() procedure like this:
//
// int main(int argc, char* argv[]) {
// google::protobuf::compiler::CommandLineInterface cli;
//
// // Support generation of C++ source and headers.
// google::protobuf::compiler::cpp::CppGenerator cpp_generator;
// cli.RegisterGenerator("--cpp_out", &cpp_generator,
// "Generate C++ source and header.");
//
// // Support generation of Foo code.
// FooGenerator foo_generator;
// cli.RegisterGenerator("--foo_out", &foo_generator,
// "Generate Foo file.");
//
// return cli.Run(argc, argv);
// }
//
// The compiler is invoked with syntax like:
// protoc --cpp_out=outdir --foo_out=outdir --proto_path=src src/foo.proto
//
// The .proto file to compile can be specified on the command line using either
// its physical file path, or a virtual path relative to a diretory specified
// in --proto_path. For example, for src/foo.proto, the following two protoc
// invocations work the same way:
// 1. protoc --proto_path=src src/foo.proto (physical file path)
// 2. protoc --proto_path=src foo.proto (virtual path relative to src)
//
// If a file path can be interpreted both as a physical file path and as a
// relative virtual path, the physical file path takes precendence.
//
// For a full description of the command-line syntax, invoke it with --help.
class LIBPROTOC_EXPORT CommandLineInterface {
public:
static const char* const kPathSeparator;
CommandLineInterface();
~CommandLineInterface();
// Register a code generator for a language.
//
// Parameters:
// * flag_name: The command-line flag used to specify an output file of
// this type. The name must start with a '-'. If the name is longer
// than one letter, it must start with two '-'s.
// * generator: The CodeGenerator which will be called to generate files
// of this type.
// * help_text: Text describing this flag in the --help output.
//
// Some generators accept extra parameters. You can specify this parameter
// on the command-line by placing it before the output directory, separated
// by a colon:
// protoc --foo_out=enable_bar:outdir
// The text before the colon is passed to CodeGenerator::Generate() as the
// "parameter".
void RegisterGenerator(const string& flag_name,
CodeGenerator* generator,
const string& help_text);
// Register a code generator for a language.
// Besides flag_name you can specify another option_flag_name that could be
// used to pass extra parameters to the registered code generator.
// Suppose you have registered a generator by calling:
// command_line_interface.RegisterGenerator("--foo_out", "--foo_opt", ...)
// Then you could invoke the compiler with a command like:
// protoc --foo_out=enable_bar:outdir --foo_opt=enable_baz
// This will pass "enable_bar,enable_baz" as the parameter to the generator.
void RegisterGenerator(const string& flag_name,
const string& option_flag_name,
CodeGenerator* generator,
const string& help_text);
// Enables "plugins". In this mode, if a command-line flag ends with "_out"
// but does not match any registered generator, the compiler will attempt to
// find a "plugin" to implement the generator. Plugins are just executables.
// They should live somewhere in the PATH.
//
// The compiler determines the executable name to search for by concatenating
// exe_name_prefix with the unrecognized flag name, removing "_out". So, for
// example, if exe_name_prefix is "protoc-" and you pass the flag --foo_out,
// the compiler will try to run the program "protoc-foo".
//
// The plugin program should implement the following usage:
// plugin [--out=OUTDIR] [--parameter=PARAMETER] PROTO_FILES < DESCRIPTORS
// --out indicates the output directory (as passed to the --foo_out
// parameter); if omitted, the current directory should be used. --parameter
// gives the generator parameter, if any was provided (see below). The
// PROTO_FILES list the .proto files which were given on the compiler
// command-line; these are the files for which the plugin is expected to
// generate output code. Finally, DESCRIPTORS is an encoded FileDescriptorSet
// (as defined in descriptor.proto). This is piped to the plugin's stdin.
// The set will include descriptors for all the files listed in PROTO_FILES as
// well as all files that they import. The plugin MUST NOT attempt to read
// the PROTO_FILES directly -- it must use the FileDescriptorSet.
//
// The plugin should generate whatever files are necessary, as code generators
// normally do. It should write the names of all files it generates to
// stdout. The names should be relative to the output directory, NOT absolute
// names or relative to the current directory. If any errors occur, error
// messages should be written to stderr. If an error is fatal, the plugin
// should exit with a non-zero exit code.
//
// Plugins can have generator parameters similar to normal built-in
// generators. Extra generator parameters can be passed in via a matching
// "_opt" parameter. For example:
// protoc --plug_out=enable_bar:outdir --plug_opt=enable_baz
// This will pass "enable_bar,enable_baz" as the parameter to the plugin.
//
void AllowPlugins(const string& exe_name_prefix);
// Run the Protocol Compiler with the given command-line parameters.
// Returns the error code which should be returned by main().
//
// It may not be safe to call Run() in a multi-threaded environment because
// it calls strerror(). I'm not sure why you'd want to do this anyway.
int Run(int argc, const char* const argv[]);
// DEPRECATED. Calling this method has no effect. Protocol compiler now
// always try to find the .proto file relative to the current directory
// first and if the file is not found, it will then treat the input path
// as a virutal path.
void SetInputsAreProtoPathRelative(bool /* enable */) {}
// Provides some text which will be printed when the --version flag is
// used. The version of libprotoc will also be printed on the next line
// after this text.
void SetVersionInfo(const string& text) {
version_info_ = text;
}
private:
// -----------------------------------------------------------------
class ErrorPrinter;
class GeneratorContextImpl;
class MemoryOutputStream;
typedef hash_map<string, GeneratorContextImpl*> GeneratorContextMap;
// Clear state from previous Run().
void Clear();
// Remaps each file in input_files_ so that it is relative to one of the
// directories in proto_path_. Returns false if an error occurred. This
// is only used if inputs_are_proto_path_relative_ is false.
bool MakeInputsBeProtoPathRelative(
DiskSourceTree* source_tree);
// Return status for ParseArguments() and InterpretArgument().
enum ParseArgumentStatus {
PARSE_ARGUMENT_DONE_AND_CONTINUE,
PARSE_ARGUMENT_DONE_AND_EXIT,
PARSE_ARGUMENT_FAIL
};
// Parse all command-line arguments.
ParseArgumentStatus ParseArguments(int argc, const char* const argv[]);
// Read an argument file and append the file's content to the list of
// arguments. Return false if the file cannot be read.
bool ExpandArgumentFile(const string& file, std::vector<string>* arguments);
// Parses a command-line argument into a name/value pair. Returns
// true if the next argument in the argv should be used as the value,
// false otherwise.
//
// Examples:
// "-Isrc/protos" ->
// name = "-I", value = "src/protos"
// "--cpp_out=src/foo.pb2.cc" ->
// name = "--cpp_out", value = "src/foo.pb2.cc"
// "foo.proto" ->
// name = "", value = "foo.proto"
bool ParseArgument(const char* arg, string* name, string* value);
// Interprets arguments parsed with ParseArgument.
ParseArgumentStatus InterpretArgument(const string& name,
const string& value);
// Print the --help text to stderr.
void PrintHelpText();
// Loads proto_path_ into the provided source_tree.
bool InitializeDiskSourceTree(DiskSourceTree* source_tree);
// Loads descriptor_set_in into the provided database
bool PopulateSimpleDescriptorDatabase(SimpleDescriptorDatabase* database);
// Parses input_files_ into parsed_files
bool ParseInputFiles(DescriptorPool* descriptor_pool,
std::vector<const FileDescriptor*>* parsed_files);
// Generate the given output file from the given input.
struct OutputDirective; // see below
bool GenerateOutput(const std::vector<const FileDescriptor*>& parsed_files,
const OutputDirective& output_directive,
GeneratorContext* generator_context);
bool GeneratePluginOutput(
const std::vector<const FileDescriptor*>& parsed_files,
const string& plugin_name, const string& parameter,
GeneratorContext* generator_context, string* error);
// Implements --encode and --decode.
bool EncodeOrDecode(const DescriptorPool* pool);
// Implements the --descriptor_set_out option.
bool WriteDescriptorSet(
const std::vector<const FileDescriptor*>& parsed_files);
// Implements the --dependency_out option
bool GenerateDependencyManifestFile(
const std::vector<const FileDescriptor*>& parsed_files,
const GeneratorContextMap& output_directories,
DiskSourceTree* source_tree);
// Get all transitive dependencies of the given file (including the file
// itself), adding them to the given list of FileDescriptorProtos. The
// protos will be ordered such that every file is listed before any file that
// depends on it, so that you can call DescriptorPool::BuildFile() on them
// in order. Any files in *already_seen will not be added, and each file
// added will be inserted into *already_seen. If include_source_code_info is
// true then include the source code information in the FileDescriptorProtos.
// If include_json_name is true, populate the json_name field of
// FieldDescriptorProto for all fields.
static void GetTransitiveDependencies(
const FileDescriptor* file,
bool include_json_name,
bool include_source_code_info,
std::set<const FileDescriptor*>* already_seen,
RepeatedPtrField<FileDescriptorProto>* output);
// Implements the --print_free_field_numbers. This function prints free field
// numbers into stdout for the message and it's nested message types in
// post-order, i.e. nested types first. Printed range are left-right
// inclusive, i.e. [a, b].
//
// Groups:
// For historical reasons, groups are considered to share the same
// field number space with the parent message, thus it will not print free
// field numbers for groups. The field numbers used in the groups are
// excluded in the free field numbers of the parent message.
//
// Extension Ranges:
// Extension ranges are considered ocuppied field numbers and they will not be
// listed as free numbers in the output.
void PrintFreeFieldNumbers(const Descriptor* descriptor);
// -----------------------------------------------------------------
// The name of the executable as invoked (i.e. argv[0]).
string executable_name_;
// Version info set with SetVersionInfo().
string version_info_;
// Registered generators.
struct GeneratorInfo {
string flag_name;
string option_flag_name;
CodeGenerator* generator;
string help_text;
};
typedef std::map<string, GeneratorInfo> GeneratorMap;
GeneratorMap generators_by_flag_name_;
GeneratorMap generators_by_option_name_;
// A map from generator names to the parameters specified using the option
// flag. For example, if the user invokes the compiler with:
// protoc --foo_out=outputdir --foo_opt=enable_bar ...
// Then there will be an entry ("--foo_out", "enable_bar") in this map.
std::map<string, string> generator_parameters_;
// Similar to generator_parameters_, but stores the parameters for plugins.
std::map<string, string> plugin_parameters_;
// See AllowPlugins(). If this is empty, plugins aren't allowed.
string plugin_prefix_;
// Maps specific plugin names to files. When executing a plugin, this map
// is searched first to find the plugin executable. If not found here, the
// PATH (or other OS-specific search strategy) is searched.
std::map<string, string> plugins_;
// Stuff parsed from command line.
enum Mode {
MODE_COMPILE, // Normal mode: parse .proto files and compile them.
MODE_ENCODE, // --encode: read text from stdin, write binary to stdout.
MODE_DECODE, // --decode: read binary from stdin, write text to stdout.
MODE_PRINT, // Print mode: print info of the given .proto files and exit.
};
Mode mode_;
enum PrintMode {
PRINT_NONE, // Not in MODE_PRINT
PRINT_FREE_FIELDS, // --print_free_fields
};
PrintMode print_mode_;
enum ErrorFormat {
ERROR_FORMAT_GCC, // GCC error output format (default).
ERROR_FORMAT_MSVS // Visual Studio output (--error_format=msvs).
};
ErrorFormat error_format_;
std::vector<std::pair<string, string> >
proto_path_; // Search path for proto files.
std::vector<string> input_files_; // Names of the input proto files.
// Names of proto files which are allowed to be imported. Used by build
// systems to enforce depend-on-what-you-import.
std::set<string> direct_dependencies_;
bool direct_dependencies_explicitly_set_;
// If there's a violation of depend-on-what-you-import, this string will be
// presented to the user. "%s" will be replaced with the violating import.
string direct_dependencies_violation_msg_;
// output_directives_ lists all the files we are supposed to output and what
// generator to use for each.
struct OutputDirective {
string name; // E.g. "--foo_out"
CodeGenerator* generator; // NULL for plugins
string parameter;
string output_location;
};
std::vector<OutputDirective> output_directives_;
// When using --encode or --decode, this names the type we are encoding or
// decoding. (Empty string indicates --decode_raw.)
string codec_type_;
// If --descriptor_set_in was given, these are filenames containing
// parsed FileDescriptorSets to be used for loading protos. Otherwise, empty.
std::vector<string> descriptor_set_in_names_;
// If --descriptor_set_out was given, this is the filename to which the
// FileDescriptorSet should be written. Otherwise, empty.
string descriptor_set_out_name_;
// If --dependency_out was given, this is the path to the file where the
// dependency file will be written. Otherwise, empty.
string dependency_out_name_;
// True if --include_imports was given, meaning that we should
// write all transitive dependencies to the DescriptorSet. Otherwise, only
// the .proto files listed on the command-line are added.
bool imports_in_descriptor_set_;
// True if --include_source_info was given, meaning that we should not strip
// SourceCodeInfo from the DescriptorSet.
bool source_info_in_descriptor_set_;
// Was the --disallow_services flag used?
bool disallow_services_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CommandLineInterface);
};
} // namespace compiler
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_COMPILER_COMMAND_LINE_INTERFACE_H__

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,172 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
//
// This test insures that google/protobuf/descriptor.pb.{h,cc} match exactly
// what would be generated by the protocol compiler. These files are not
// generated automatically at build time because they are compiled into the
// protocol compiler itself. So, if they were auto-generated, you'd have a
// chicken-and-egg problem.
//
// If this test fails, run the script
// "generate_descriptor_proto.sh" and add
// descriptor.pb.{h,cc} to your changelist.
#include <map>
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
#include <google/protobuf/compiler/cpp/cpp_generator.h>
#include <google/protobuf/compiler/importer.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/stubs/substitute.h>
#include <google/protobuf/stubs/map_util.h>
#include <google/protobuf/stubs/stl_util.h>
#include <google/protobuf/testing/file.h>
#include <google/protobuf/testing/file.h>
#include <google/protobuf/testing/googletest.h>
#include <gtest/gtest.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {
namespace {
class MockErrorCollector : public MultiFileErrorCollector {
public:
MockErrorCollector() {}
~MockErrorCollector() {}
string text_;
// implements ErrorCollector ---------------------------------------
void AddError(const string& filename, int line, int column,
const string& message) {
strings::SubstituteAndAppend(&text_, "$0:$1:$2: $3\n",
filename, line, column, message);
}
};
class MockGeneratorContext : public GeneratorContext {
public:
MockGeneratorContext() {}
~MockGeneratorContext() {
STLDeleteValues(&files_);
}
void ExpectFileMatches(const string& virtual_filename,
const string& physical_filename) {
string* expected_contents = FindPtrOrNull(files_, virtual_filename);
ASSERT_TRUE(expected_contents != NULL)
<< "Generator failed to generate file: " << virtual_filename;
string actual_contents;
GOOGLE_CHECK_OK(
File::GetContents(TestSourceDir() + "/" + physical_filename,
&actual_contents, true));
EXPECT_TRUE(actual_contents == *expected_contents)
<< physical_filename
<< " needs to be regenerated. Please run "
"generate_descriptor_proto.sh. "
"Then add this file to your CL.";
}
// implements GeneratorContext --------------------------------------
virtual io::ZeroCopyOutputStream* Open(const string& filename) {
string** map_slot = &files_[filename];
delete *map_slot;
*map_slot = new string;
return new io::StringOutputStream(*map_slot);
}
private:
std::map<string, string*> files_;
};
const char kDescriptorParameter[] = "dllexport_decl=LIBPROTOBUF_EXPORT";
const char kPluginParameter[] = "dllexport_decl=LIBPROTOC_EXPORT";
const char kNormalParameter[] = "";
const char* test_protos[][2] = {
{"google/protobuf/descriptor", kDescriptorParameter},
{"google/protobuf/compiler/plugin", kPluginParameter},
};
TEST(BootstrapTest, GeneratedFilesMatch) {
// We need a mapping from the actual file to virtual and actual path
// of the data to compare to.
std::map<string, string> vpath_map;
std::map<string, string> rpath_map;
rpath_map["third_party/protobuf/src/google/protobuf/test_messages_proto2"] =
"net/proto2/z_generated_example/test_messages_proto2";
rpath_map["third_party/protobuf/src/google/protobuf/test_messages_proto3"] =
"net/proto2/z_generated_example/test_messages_proto3";
rpath_map["google/protobuf/proto2_weak"] =
"net/proto2/z_generated_example/proto2_weak";
DiskSourceTree source_tree;
source_tree.MapPath("", TestSourceDir());
for (auto file_parameter : test_protos) {
MockErrorCollector error_collector;
Importer importer(&source_tree, &error_collector);
const FileDescriptor* file =
importer.Import(file_parameter[0] + string(".proto"));
ASSERT_TRUE(file != nullptr)
<< "Can't import file " << file_parameter[0] + string(".proto") << "\n";
EXPECT_EQ("", error_collector.text_);
CppGenerator generator;
MockGeneratorContext context;
string error;
ASSERT_TRUE(generator.Generate(file, file_parameter[1], &context, &error));
string vpath =
FindWithDefault(vpath_map, file_parameter[0], file_parameter[0]);
string rpath =
FindWithDefault(rpath_map, file_parameter[0], file_parameter[0]);
context.ExpectFileMatches(vpath + ".pb.cc", rpath + ".pb.cc");
context.ExpectFileMatches(vpath + ".pb.h", rpath + ".pb.h");
}
}
} // namespace
} // namespace cpp
} // namespace compiler
} // namespace protobuf
} // namespace google

View File

@ -0,0 +1,327 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
#include <map>
#include <google/protobuf/compiler/cpp/cpp_enum.h>
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/stubs/strutil.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {
namespace {
// The GOOGLE_ARRAYSIZE constant is the max enum value plus 1. If the max enum value
// is ::google::protobuf::kint32max, GOOGLE_ARRAYSIZE will overflow. In such cases we should omit the
// generation of the GOOGLE_ARRAYSIZE constant.
bool ShouldGenerateArraySize(const EnumDescriptor* descriptor) {
int32 max_value = descriptor->value(0)->number();
for (int i = 0; i < descriptor->value_count(); i++) {
if (descriptor->value(i)->number() > max_value) {
max_value = descriptor->value(i)->number();
}
}
return max_value != ::google::protobuf::kint32max;
}
} // namespace
EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor,
const Options& options)
: descriptor_(descriptor),
classname_(ClassName(descriptor, false)),
options_(options),
generate_array_size_(ShouldGenerateArraySize(descriptor)) {
}
EnumGenerator::~EnumGenerator() {}
void EnumGenerator::FillForwardDeclaration(
std::map<string, const EnumDescriptor*>* enum_names) {
if (!options_.proto_h) {
return;
}
(*enum_names)[classname_] = descriptor_;
}
void EnumGenerator::GenerateDefinition(io::Printer* printer) {
std::map<string, string> vars;
vars["classname"] = classname_;
vars["short_name"] = descriptor_->name();
vars["enumbase"] = options_.proto_h ? " : int" : "";
// These variables are placeholders to pick out the beginning and ends of
// identifiers for annotations (when doing so with existing variables would
// be ambiguous or impossible). They should never be set to anything but the
// empty string.
vars["{"] = "";
vars["}"] = "";
printer->Print(vars, "enum $classname$$enumbase$ {\n");
printer->Annotate("classname", descriptor_);
printer->Indent();
const EnumValueDescriptor* min_value = descriptor_->value(0);
const EnumValueDescriptor* max_value = descriptor_->value(0);
for (int i = 0; i < descriptor_->value_count(); i++) {
vars["name"] = EnumValueName(descriptor_->value(i));
// In C++, an value of -2147483648 gets interpreted as the negative of
// 2147483648, and since 2147483648 can't fit in an integer, this produces a
// compiler warning. This works around that issue.
vars["number"] = Int32ToString(descriptor_->value(i)->number());
vars["prefix"] = (descriptor_->containing_type() == NULL) ?
"" : classname_ + "_";
vars["deprecation"] = descriptor_->value(i)->options().deprecated() ?
" PROTOBUF_DEPRECATED" : "";
if (i > 0) printer->Print(",\n");
printer->Print(vars, "${$$prefix$$name$$}$$deprecation$ = $number$");
printer->Annotate("{", "}", descriptor_->value(i));
if (descriptor_->value(i)->number() < min_value->number()) {
min_value = descriptor_->value(i);
}
if (descriptor_->value(i)->number() > max_value->number()) {
max_value = descriptor_->value(i);
}
}
if (HasPreservingUnknownEnumSemantics(descriptor_->file())) {
// For new enum semantics: generate min and max sentinel values equal to
// INT32_MIN and INT32_MAX
if (descriptor_->value_count() > 0) printer->Print(",\n");
printer->Print(vars,
"$classname$_$prefix$INT_MIN_SENTINEL_DO_NOT_USE_ = ::google::protobuf::kint32min,\n"
"$classname$_$prefix$INT_MAX_SENTINEL_DO_NOT_USE_ = ::google::protobuf::kint32max");
}
printer->Outdent();
printer->Print("\n};\n");
vars["min_name"] = EnumValueName(min_value);
vars["max_name"] = EnumValueName(max_value);
if (options_.dllexport_decl.empty()) {
vars["dllexport"] = "";
} else {
vars["dllexport"] = options_.dllexport_decl + " ";
}
printer->Print(vars,
"$dllexport$bool $classname$_IsValid(int value);\n"
"const $classname$ ${$$prefix$$short_name$_MIN$}$ = "
"$prefix$$min_name$;\n");
printer->Annotate("{", "}", descriptor_);
printer->Print(vars,
"const $classname$ ${$$prefix$$short_name$_MAX$}$ = "
"$prefix$$max_name$;\n");
printer->Annotate("{", "}", descriptor_);
if (generate_array_size_) {
printer->Print(vars,
"const int ${$$prefix$$short_name$_ARRAYSIZE$}$ = "
"$prefix$$short_name$_MAX + 1;\n\n");
printer->Annotate("{", "}", descriptor_);
}
if (HasDescriptorMethods(descriptor_->file(), options_)) {
printer->Print(vars,
"$dllexport$const ::google::protobuf::EnumDescriptor* $classname$_descriptor();\n");
// The _Name and _Parse methods
printer->Print(
vars,
"inline const ::std::string& $classname$_Name($classname$ value) {\n"
" return ::google::protobuf::internal::NameOfEnum(\n"
" $classname$_descriptor(), value);\n"
"}\n");
printer->Print(vars,
"inline bool $classname$_Parse(\n"
" const ::std::string& name, $classname$* value) {\n"
" return ::google::protobuf::internal::ParseNamedEnum<$classname$>(\n"
" $classname$_descriptor(), name, value);\n"
"}\n");
}
}
void EnumGenerator::
GenerateGetEnumDescriptorSpecializations(io::Printer* printer) {
printer->Print(
"template <> struct is_proto_enum< $classname$> : ::std::true_type "
"{};\n",
"classname", ClassName(descriptor_, true));
if (HasDescriptorMethods(descriptor_->file(), options_)) {
printer->Print(
"template <>\n"
"inline const EnumDescriptor* GetEnumDescriptor< $classname$>() {\n"
" return $classname$_descriptor();\n"
"}\n",
"classname", ClassName(descriptor_, true));
}
}
void EnumGenerator::GenerateSymbolImports(io::Printer* printer) {
std::map<string, string> vars;
vars["nested_name"] = descriptor_->name();
vars["classname"] = classname_;
vars["constexpr"] = options_.proto_h ? "constexpr " : "";
vars["{"] = "";
vars["}"] = "";
printer->Print(vars, "typedef $classname$ $nested_name$;\n");
for (int j = 0; j < descriptor_->value_count(); j++) {
vars["tag"] = EnumValueName(descriptor_->value(j));
vars["deprecated_attr"] = descriptor_->value(j)->options().deprecated() ?
"GOOGLE_PROTOBUF_DEPRECATED_ATTR " : "";
printer->Print(vars,
"$deprecated_attr$static $constexpr$const $nested_name$ ${$$tag$$}$ =\n"
" $classname$_$tag$;\n");
printer->Annotate("{", "}", descriptor_->value(j));
}
printer->Print(vars,
"static inline bool $nested_name$_IsValid(int value) {\n"
" return $classname$_IsValid(value);\n"
"}\n"
"static const $nested_name$ ${$$nested_name$_MIN$}$ =\n"
" $classname$_$nested_name$_MIN;\n");
printer->Annotate("{", "}", descriptor_);
printer->Print(vars,
"static const $nested_name$ ${$$nested_name$_MAX$}$ =\n"
" $classname$_$nested_name$_MAX;\n");
printer->Annotate("{", "}", descriptor_);
if (generate_array_size_) {
printer->Print(vars,
"static const int ${$$nested_name$_ARRAYSIZE$}$ =\n"
" $classname$_$nested_name$_ARRAYSIZE;\n");
printer->Annotate("{", "}", descriptor_);
}
if (HasDescriptorMethods(descriptor_->file(), options_)) {
printer->Print(vars,
"static inline const ::google::protobuf::EnumDescriptor*\n"
"$nested_name$_descriptor() {\n"
" return $classname$_descriptor();\n"
"}\n");
printer->Print(vars,
"static inline const ::std::string& "
"$nested_name$_Name($nested_name$ value) {"
"\n"
" return $classname$_Name(value);\n"
"}\n");
printer->Print(vars,
"static inline bool $nested_name$_Parse(const ::std::string& name,\n"
" $nested_name$* value) {\n"
" return $classname$_Parse(name, value);\n"
"}\n");
}
}
void EnumGenerator::GenerateMethods(int idx, io::Printer* printer) {
std::map<string, string> vars;
vars["classname"] = classname_;
vars["index_in_metadata"] = SimpleItoa(idx);
vars["constexpr"] = options_.proto_h ? "constexpr " : "";
vars["file_namespace"] = FileLevelNamespace(descriptor_->file()->name());
if (HasDescriptorMethods(descriptor_->file(), options_)) {
printer->Print(
vars,
"const ::google::protobuf::EnumDescriptor* $classname$_descriptor() {\n"
" $file_namespace$::protobuf_AssignDescriptorsOnce();\n"
" return "
"$file_namespace$::file_level_enum_descriptors[$index_in_metadata$];\n"
"}\n");
}
printer->Print(vars,
"bool $classname$_IsValid(int value) {\n"
" switch (value) {\n");
// Multiple values may have the same number. Make sure we only cover
// each number once by first constructing a set containing all valid
// numbers, then printing a case statement for each element.
std::set<int> numbers;
for (int j = 0; j < descriptor_->value_count(); j++) {
const EnumValueDescriptor* value = descriptor_->value(j);
numbers.insert(value->number());
}
for (std::set<int>::iterator iter = numbers.begin();
iter != numbers.end(); ++iter) {
printer->Print(
" case $number$:\n",
"number", Int32ToString(*iter));
}
printer->Print(vars,
" return true;\n"
" default:\n"
" return false;\n"
" }\n"
"}\n"
"\n");
if (descriptor_->containing_type() != NULL) {
// We need to "define" the static constants which were declared in the
// header, to give the linker a place to put them. Or at least the C++
// standard says we have to. MSVC actually insists that we do _not_ define
// them again in the .cc file, prior to VC++ 2015.
printer->Print("#if !defined(_MSC_VER) || _MSC_VER >= 1900\n");
vars["parent"] = ClassName(descriptor_->containing_type(), false);
vars["nested_name"] = descriptor_->name();
for (int i = 0; i < descriptor_->value_count(); i++) {
vars["value"] = EnumValueName(descriptor_->value(i));
printer->Print(vars,
"$constexpr$const $classname$ $parent$::$value$;\n");
}
printer->Print(vars,
"const $classname$ $parent$::$nested_name$_MIN;\n"
"const $classname$ $parent$::$nested_name$_MAX;\n");
if (generate_array_size_) {
printer->Print(vars,
"const int $parent$::$nested_name$_ARRAYSIZE;\n");
}
printer->Print("#endif // !defined(_MSC_VER) || _MSC_VER >= 1900\n");
}
}
} // namespace cpp
} // namespace compiler
} // namespace protobuf
} // namespace google

View File

@ -0,0 +1,110 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__
#define GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__
#include <map>
#include <set>
#include <string>
#include <google/protobuf/compiler/cpp/cpp_options.h>
#include <google/protobuf/descriptor.h>
namespace google {
namespace protobuf {
namespace io {
class Printer; // printer.h
}
}
namespace protobuf {
namespace compiler {
namespace cpp {
class EnumGenerator {
public:
// See generator.cc for the meaning of dllexport_decl.
EnumGenerator(const EnumDescriptor* descriptor, const Options& options);
~EnumGenerator();
// Header stuff.
// Fills the name to use when declaring the enum. This is for use when
// generating other .proto.h files. This code should be placed within the
// enum's package namespace, but NOT within any class, even for nested
// enums. A given key in enum_names will map from an enum class name to the
// EnumDescriptor that was responsible for its inclusion in the map. This can
// be used to associate the descriptor with the code generated for it.
void FillForwardDeclaration(
std::map<string, const EnumDescriptor*>* enum_names);
// Generate header code defining the enum. This code should be placed
// within the enum's package namespace, but NOT within any class, even for
// nested enums.
void GenerateDefinition(io::Printer* printer);
// Generate specialization of GetEnumDescriptor<MyEnum>().
// Precondition: in ::google::protobuf namespace.
void GenerateGetEnumDescriptorSpecializations(io::Printer* printer);
// For enums nested within a message, generate code to import all the enum's
// symbols (e.g. the enum type name, all its values, etc.) into the class's
// namespace. This should be placed inside the class definition in the
// header.
void GenerateSymbolImports(io::Printer* printer);
// Source file stuff.
// Generate non-inline methods related to the enum, such as IsValidValue().
// Goes in the .cc file. EnumDescriptors are stored in an array, idx is
// the index in this array that corresponds with this enum.
void GenerateMethods(int idx, io::Printer* printer);
private:
const EnumDescriptor* descriptor_;
const string classname_;
const Options& options_;
// whether to generate the *_ARRAYSIZE constant.
const bool generate_array_size_;
friend class FileGenerator;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator);
};
} // namespace cpp
} // namespace compiler
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__

View File

@ -0,0 +1,520 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
#include <google/protobuf/compiler/cpp/cpp_enum_field.h>
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/wire_format.h>
#include <google/protobuf/stubs/strutil.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {
namespace {
void SetEnumVariables(const FieldDescriptor* descriptor,
std::map<string, string>* variables,
const Options& options) {
SetCommonFieldVariables(descriptor, variables, options);
const EnumValueDescriptor* default_value = descriptor->default_value_enum();
(*variables)["type"] = ClassName(descriptor->enum_type(), true);
(*variables)["default"] = Int32ToString(default_value->number());
(*variables)["full_name"] = descriptor->full_name();
}
} // namespace
// ===================================================================
EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor,
const Options& options)
: FieldGenerator(options), descriptor_(descriptor) {
SetEnumVariables(descriptor, &variables_, options);
}
EnumFieldGenerator::~EnumFieldGenerator() {}
void EnumFieldGenerator::
GeneratePrivateMembers(io::Printer* printer) const {
printer->Print(variables_, "int $name$_;\n");
}
void EnumFieldGenerator::
GenerateAccessorDeclarations(io::Printer* printer) const {
printer->Print(variables_, "$deprecated_attr$$type$ $name$() const;\n");
printer->Annotate("name", descriptor_);
printer->Print(variables_,
"$deprecated_attr$void ${$set_$name$$}$($type$ value);\n");
printer->Annotate("{", "}", descriptor_);
}
void EnumFieldGenerator::
GenerateInlineAccessorDefinitions(io::Printer* printer) const {
printer->Print(variables_,
"inline $type$ $classname$::$name$() const {\n"
" // @@protoc_insertion_point(field_get:$full_name$)\n"
" return static_cast< $type$ >($name$_);\n"
"}\n"
"inline void $classname$::set_$name$($type$ value) {\n");
if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) {
printer->Print(variables_,
" assert($type$_IsValid(value));\n");
}
printer->Print(variables_,
" $set_hasbit$\n"
" $name$_ = value;\n"
" // @@protoc_insertion_point(field_set:$full_name$)\n"
"}\n");
}
void EnumFieldGenerator::
GenerateClearingCode(io::Printer* printer) const {
printer->Print(variables_, "$name$_ = $default$;\n");
}
void EnumFieldGenerator::
GenerateMergingCode(io::Printer* printer) const {
printer->Print(variables_, "set_$name$(from.$name$());\n");
}
void EnumFieldGenerator::
GenerateSwappingCode(io::Printer* printer) const {
printer->Print(variables_, "swap($name$_, other->$name$_);\n");
}
void EnumFieldGenerator::
GenerateConstructorCode(io::Printer* printer) const {
printer->Print(variables_, "$name$_ = $default$;\n");
}
void EnumFieldGenerator::
GenerateCopyConstructorCode(io::Printer* printer) const {
printer->Print(variables_, "$name$_ = from.$name$_;\n");
}
void EnumFieldGenerator::
GenerateMergeFromCodedStream(io::Printer* printer) const {
printer->Print(variables_,
"int value;\n"
"DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n"
" int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n"
" input, &value)));\n");
if (HasPreservingUnknownEnumSemantics(descriptor_->file())) {
printer->Print(variables_,
"set_$name$(static_cast< $type$ >(value));\n");
} else {
printer->Print(variables_,
"if ($type$_IsValid(value)) {\n"
" set_$name$(static_cast< $type$ >(value));\n");
if (UseUnknownFieldSet(descriptor_->file(), options_)) {
printer->Print(variables_,
"} else {\n"
" mutable_unknown_fields()->AddVarint(\n"
" $number$, static_cast< ::google::protobuf::uint64>(value));\n");
} else {
printer->Print(
"} else {\n"
" unknown_fields_stream.WriteVarint32($tag$u);\n"
" unknown_fields_stream.WriteVarint32(\n"
" static_cast< ::google::protobuf::uint32>(value));\n",
"tag", SimpleItoa(internal::WireFormat::MakeTag(descriptor_)));
}
printer->Print(variables_,
"}\n");
}
}
void EnumFieldGenerator::
GenerateSerializeWithCachedSizes(io::Printer* printer) const {
printer->Print(variables_,
"::google::protobuf::internal::WireFormatLite::WriteEnum(\n"
" $number$, this->$name$(), output);\n");
}
void EnumFieldGenerator::
GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
printer->Print(variables_,
"target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(\n"
" $number$, this->$name$(), target);\n");
}
void EnumFieldGenerator::
GenerateByteSize(io::Printer* printer) const {
printer->Print(variables_,
"total_size += $tag_size$ +\n"
" ::google::protobuf::internal::WireFormatLite::EnumSize(this->$name$());\n");
}
// ===================================================================
EnumOneofFieldGenerator::
EnumOneofFieldGenerator(const FieldDescriptor* descriptor,
const Options& options)
: EnumFieldGenerator(descriptor, options) {
SetCommonOneofFieldVariables(descriptor, &variables_);
}
EnumOneofFieldGenerator::~EnumOneofFieldGenerator() {}
void EnumOneofFieldGenerator::
GenerateInlineAccessorDefinitions(io::Printer* printer) const {
printer->Print(variables_,
"inline $type$ $classname$::$name$() const {\n"
" // @@protoc_insertion_point(field_get:$full_name$)\n"
" if (has_$name$()) {\n"
" return static_cast< $type$ >($field_member$);\n"
" }\n"
" return static_cast< $type$ >($default$);\n"
"}\n"
"inline void $classname$::set_$name$($type$ value) {\n");
if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) {
printer->Print(variables_,
" assert($type$_IsValid(value));\n");
}
printer->Print(variables_,
" if (!has_$name$()) {\n"
" clear_$oneof_name$();\n"
" set_has_$name$();\n"
" }\n"
" $field_member$ = value;\n"
" // @@protoc_insertion_point(field_set:$full_name$)\n"
"}\n");
}
void EnumOneofFieldGenerator::
GenerateClearingCode(io::Printer* printer) const {
printer->Print(variables_, "$field_member$ = $default$;\n");
}
void EnumOneofFieldGenerator::
GenerateSwappingCode(io::Printer* printer) const {
// Don't print any swapping code. Swapping the union will swap this field.
}
void EnumOneofFieldGenerator::
GenerateConstructorCode(io::Printer* printer) const {
printer->Print(variables_,
"$ns$::_$classname$_default_instance_.$name$_ = $default$;\n");
}
// ===================================================================
RepeatedEnumFieldGenerator::RepeatedEnumFieldGenerator(
const FieldDescriptor* descriptor, const Options& options)
: FieldGenerator(options), descriptor_(descriptor) {
SetEnumVariables(descriptor, &variables_, options);
}
RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {}
void RepeatedEnumFieldGenerator::
GeneratePrivateMembers(io::Printer* printer) const {
printer->Print(variables_,
"::google::protobuf::RepeatedField<int> $name$_;\n");
if (descriptor_->is_packed() &&
HasGeneratedMethods(descriptor_->file(), options_)) {
printer->Print(variables_,
"mutable int _$name$_cached_byte_size_;\n");
}
}
void RepeatedEnumFieldGenerator::
GenerateAccessorDeclarations(io::Printer* printer) const {
printer->Print(variables_,
"$deprecated_attr$$type$ $name$(int index) const;\n");
printer->Annotate("name", descriptor_);
printer->Print(
variables_,
"$deprecated_attr$void ${$set_$name$$}$(int index, $type$ value);\n");
printer->Annotate("{", "}", descriptor_);
printer->Print(variables_,
"$deprecated_attr$void ${$add_$name$$}$($type$ value);\n");
printer->Annotate("{", "}", descriptor_);
printer->Print(
variables_,
"$deprecated_attr$const ::google::protobuf::RepeatedField<int>& $name$() const;\n");
printer->Annotate("name", descriptor_);
printer->Print(variables_,
"$deprecated_attr$::google::protobuf::RepeatedField<int>* "
"${$mutable_$name$$}$();\n");
printer->Annotate("{", "}", descriptor_);
}
void RepeatedEnumFieldGenerator::
GenerateInlineAccessorDefinitions(io::Printer* printer) const {
printer->Print(variables_,
"inline $type$ $classname$::$name$(int index) const {\n"
" // @@protoc_insertion_point(field_get:$full_name$)\n"
" return static_cast< $type$ >($name$_.Get(index));\n"
"}\n"
"inline void $classname$::set_$name$(int index, $type$ value) {\n");
if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) {
printer->Print(variables_,
" assert($type$_IsValid(value));\n");
}
printer->Print(variables_,
" $name$_.Set(index, value);\n"
" // @@protoc_insertion_point(field_set:$full_name$)\n"
"}\n"
"inline void $classname$::add_$name$($type$ value) {\n");
if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) {
printer->Print(variables_,
" assert($type$_IsValid(value));\n");
}
printer->Print(variables_,
" $name$_.Add(value);\n"
" // @@protoc_insertion_point(field_add:$full_name$)\n"
"}\n"
"inline const ::google::protobuf::RepeatedField<int>&\n"
"$classname$::$name$() const {\n"
" // @@protoc_insertion_point(field_list:$full_name$)\n"
" return $name$_;\n"
"}\n"
"inline ::google::protobuf::RepeatedField<int>*\n"
"$classname$::mutable_$name$() {\n"
" // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
" return &$name$_;\n"
"}\n");
}
void RepeatedEnumFieldGenerator::
GenerateClearingCode(io::Printer* printer) const {
printer->Print(variables_, "$name$_.Clear();\n");
}
void RepeatedEnumFieldGenerator::
GenerateMergingCode(io::Printer* printer) const {
printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n");
}
void RepeatedEnumFieldGenerator::
GenerateSwappingCode(io::Printer* printer) const {
printer->Print(variables_, "$name$_.InternalSwap(&other->$name$_);\n");
}
void RepeatedEnumFieldGenerator::
GenerateConstructorCode(io::Printer* printer) const {
// Not needed for repeated fields.
}
void RepeatedEnumFieldGenerator::
GenerateMergeFromCodedStream(io::Printer* printer) const {
// Don't use ReadRepeatedPrimitive here so that the enum can be validated.
printer->Print(variables_,
"int value;\n"
"DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n"
" int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n"
" input, &value)));\n");
if (HasPreservingUnknownEnumSemantics(descriptor_->file())) {
printer->Print(variables_,
"add_$name$(static_cast< $type$ >(value));\n");
} else {
printer->Print(variables_,
"if ($type$_IsValid(value)) {\n"
" add_$name$(static_cast< $type$ >(value));\n");
if (UseUnknownFieldSet(descriptor_->file(), options_)) {
printer->Print(variables_,
"} else {\n"
" mutable_unknown_fields()->AddVarint(\n"
" $number$, static_cast< ::google::protobuf::uint64>(value));\n");
} else {
printer->Print(
"} else {\n"
" unknown_fields_stream.WriteVarint32(tag);\n"
" unknown_fields_stream.WriteVarint32(\n"
" static_cast< ::google::protobuf::uint32>(value));\n");
}
printer->Print("}\n");
}
}
void RepeatedEnumFieldGenerator::
GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const {
if (!descriptor_->is_packed()) {
// This path is rarely executed, so we use a non-inlined implementation.
if (HasPreservingUnknownEnumSemantics(descriptor_->file())) {
printer->Print(variables_,
"DO_((::google::protobuf::internal::"
"WireFormatLite::ReadPackedEnumPreserveUnknowns(\n"
" input,\n"
" $number$,\n"
" NULL,\n"
" NULL,\n"
" this->mutable_$name$())));\n");
} else if (UseUnknownFieldSet(descriptor_->file(), options_)) {
printer->Print(variables_,
"DO_((::google::protobuf::internal::WireFormat::ReadPackedEnumPreserveUnknowns(\n"
" input,\n"
" $number$,\n"
" $type$_IsValid,\n"
" mutable_unknown_fields(),\n"
" this->mutable_$name$())));\n");
} else {
printer->Print(variables_,
"DO_((::google::protobuf::internal::"
"WireFormatLite::ReadPackedEnumPreserveUnknowns(\n"
" input,\n"
" $number$,\n"
" $type$_IsValid,\n"
" &unknown_fields_stream,\n"
" this->mutable_$name$())));\n");
}
} else {
printer->Print(variables_,
"::google::protobuf::uint32 length;\n"
"DO_(input->ReadVarint32(&length));\n"
"::google::protobuf::io::CodedInputStream::Limit limit = "
"input->PushLimit(static_cast<int>(length));\n"
"while (input->BytesUntilLimit() > 0) {\n"
" int value;\n"
" DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n"
" int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n"
" input, &value)));\n");
if (HasPreservingUnknownEnumSemantics(descriptor_->file())) {
printer->Print(variables_,
" add_$name$(static_cast< $type$ >(value));\n");
} else {
printer->Print(variables_,
" if ($type$_IsValid(value)) {\n"
" add_$name$(static_cast< $type$ >(value));\n"
" } else {\n");
if (UseUnknownFieldSet(descriptor_->file(), options_)) {
printer->Print(variables_,
" mutable_unknown_fields()->AddVarint(\n"
" $number$, static_cast< ::google::protobuf::uint64>(value));\n");
} else {
printer->Print(variables_,
" unknown_fields_stream.WriteVarint32(tag);\n"
" unknown_fields_stream.WriteVarint32(\n"
" static_cast< ::google::protobuf::uint32>(value));\n");
}
printer->Print(
" }\n");
}
printer->Print(variables_,
"}\n"
"input->PopLimit(limit);\n");
}
}
void RepeatedEnumFieldGenerator::
GenerateSerializeWithCachedSizes(io::Printer* printer) const {
if (descriptor_->is_packed()) {
// Write the tag and the size.
printer->Print(variables_,
"if (this->$name$_size() > 0) {\n"
" ::google::protobuf::internal::WireFormatLite::WriteTag(\n"
" $number$,\n"
" ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n"
" output);\n"
" output->WriteVarint32(\n"
" static_cast< ::google::protobuf::uint32>(_$name$_cached_byte_size_));\n"
"}\n");
}
printer->Print(variables_,
"for (int i = 0, n = this->$name$_size(); i < n; i++) {\n");
if (descriptor_->is_packed()) {
printer->Print(variables_,
" ::google::protobuf::internal::WireFormatLite::WriteEnumNoTag(\n"
" this->$name$(i), output);\n");
} else {
printer->Print(variables_,
" ::google::protobuf::internal::WireFormatLite::WriteEnum(\n"
" $number$, this->$name$(i), output);\n");
}
printer->Print("}\n");
}
void RepeatedEnumFieldGenerator::
GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
if (descriptor_->is_packed()) {
// Write the tag and the size.
printer->Print(variables_,
"if (this->$name$_size() > 0) {\n"
" target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(\n"
" $number$,\n"
" ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n"
" target);\n"
" target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray("
" static_cast< ::google::protobuf::uint32>(\n"
" _$name$_cached_byte_size_), target);\n"
" target = ::google::protobuf::internal::WireFormatLite::WriteEnumNoTagToArray(\n"
" this->$name$_, target);\n"
"}\n");
} else {
printer->Print(variables_,
"target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(\n"
" $number$, this->$name$_, target);\n");
}
}
void RepeatedEnumFieldGenerator::
GenerateByteSize(io::Printer* printer) const {
printer->Print(variables_,
"{\n"
" size_t data_size = 0;\n"
" unsigned int count = static_cast<unsigned int>(this->$name$_size());");
printer->Indent();
printer->Print(variables_,
"for (unsigned int i = 0; i < count; i++) {\n"
" data_size += ::google::protobuf::internal::WireFormatLite::EnumSize(\n"
" this->$name$(static_cast<int>(i)));\n"
"}\n");
if (descriptor_->is_packed()) {
printer->Print(variables_,
"if (data_size > 0) {\n"
" total_size += $tag_size$ +\n"
" ::google::protobuf::internal::WireFormatLite::Int32Size(\n"
" static_cast< ::google::protobuf::int32>(data_size));\n"
"}\n"
"int cached_size = ::google::protobuf::internal::ToCachedSize(data_size);\n"
"GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n"
"_$name$_cached_byte_size_ = cached_size;\n"
"GOOGLE_SAFE_CONCURRENT_WRITES_END();\n"
"total_size += data_size;\n");
} else {
printer->Print(variables_,
"total_size += ($tag_size$UL * count) + data_size;\n");
}
printer->Outdent();
printer->Print("}\n");
}
} // namespace cpp
} // namespace compiler
} // namespace protobuf
} // namespace google

View File

@ -0,0 +1,123 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_FIELD_H__
#define GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_FIELD_H__
#include <map>
#include <string>
#include <google/protobuf/compiler/cpp/cpp_field.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {
class EnumFieldGenerator : public FieldGenerator {
public:
EnumFieldGenerator(const FieldDescriptor* descriptor, const Options& options);
~EnumFieldGenerator();
// implements FieldGenerator ---------------------------------------
void GeneratePrivateMembers(io::Printer* printer) const;
void GenerateAccessorDeclarations(io::Printer* printer) const;
void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
void GenerateClearingCode(io::Printer* printer) const;
void GenerateMergingCode(io::Printer* printer) const;
void GenerateSwappingCode(io::Printer* printer) const;
void GenerateConstructorCode(io::Printer* printer) const;
void GenerateCopyConstructorCode(io::Printer* printer) const;
void GenerateMergeFromCodedStream(io::Printer* printer) const;
void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
void GenerateByteSize(io::Printer* printer) const;
protected:
const FieldDescriptor* descriptor_;
std::map<string, string> variables_;
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator);
};
class EnumOneofFieldGenerator : public EnumFieldGenerator {
public:
EnumOneofFieldGenerator(const FieldDescriptor* descriptor,
const Options& options);
~EnumOneofFieldGenerator();
// implements FieldGenerator ---------------------------------------
void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
void GenerateClearingCode(io::Printer* printer) const;
void GenerateSwappingCode(io::Printer* printer) const;
void GenerateConstructorCode(io::Printer* printer) const;
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumOneofFieldGenerator);
};
class RepeatedEnumFieldGenerator : public FieldGenerator {
public:
RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor,
const Options& options);
~RepeatedEnumFieldGenerator();
// implements FieldGenerator ---------------------------------------
void GeneratePrivateMembers(io::Printer* printer) const;
void GenerateAccessorDeclarations(io::Printer* printer) const;
void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
void GenerateClearingCode(io::Printer* printer) const;
void GenerateMergingCode(io::Printer* printer) const;
void GenerateSwappingCode(io::Printer* printer) const;
void GenerateConstructorCode(io::Printer* printer) const;
void GenerateCopyConstructorCode(io::Printer* printer) const {}
void GenerateMergeFromCodedStream(io::Printer* printer) const;
void GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const;
void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
void GenerateByteSize(io::Printer* printer) const;
private:
const FieldDescriptor* descriptor_;
std::map<string, string> variables_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedEnumFieldGenerator);
};
} // namespace cpp
} // namespace compiler
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_FIELD_H__

View File

@ -0,0 +1,172 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
#include <google/protobuf/compiler/cpp/cpp_extension.h>
#include <map>
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/stubs/strutil.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {
namespace {
// Returns the fully-qualified class name of the message that this field
// extends. This function is used in the Google-internal code to handle some
// legacy cases.
string ExtendeeClassName(const FieldDescriptor* descriptor) {
const Descriptor* extendee = descriptor->containing_type();
return ClassName(extendee, true);
}
} // anonymous namespace
ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor,
const Options& options)
: descriptor_(descriptor),
options_(options) {
// Construct type_traits_.
if (descriptor_->is_repeated()) {
type_traits_ = "Repeated";
}
switch (descriptor_->cpp_type()) {
case FieldDescriptor::CPPTYPE_ENUM:
type_traits_.append("EnumTypeTraits< ");
type_traits_.append(ClassName(descriptor_->enum_type(), true));
type_traits_.append(", ");
type_traits_.append(ClassName(descriptor_->enum_type(), true));
type_traits_.append("_IsValid>");
break;
case FieldDescriptor::CPPTYPE_STRING:
type_traits_.append("StringTypeTraits");
break;
case FieldDescriptor::CPPTYPE_MESSAGE:
type_traits_.append("MessageTypeTraits< ");
type_traits_.append(ClassName(descriptor_->message_type(), true));
type_traits_.append(" >");
break;
default:
type_traits_.append("PrimitiveTypeTraits< ");
type_traits_.append(PrimitiveTypeName(descriptor_->cpp_type()));
type_traits_.append(" >");
break;
}
}
ExtensionGenerator::~ExtensionGenerator() {}
void ExtensionGenerator::GenerateDeclaration(io::Printer* printer) {
std::map<string, string> vars;
vars["extendee" ] = ExtendeeClassName(descriptor_);
vars["number" ] = SimpleItoa(descriptor_->number());
vars["type_traits" ] = type_traits_;
vars["name" ] = descriptor_->name();
vars["field_type" ] = SimpleItoa(static_cast<int>(descriptor_->type()));
vars["packed" ] = descriptor_->options().packed() ? "true" : "false";
vars["constant_name"] = FieldConstantName(descriptor_);
// If this is a class member, it needs to be declared "static". Otherwise,
// it needs to be "extern". In the latter case, it also needs the DLL
// export/import specifier.
if (descriptor_->extension_scope() == NULL) {
vars["qualifier"] = "extern";
if (!options_.dllexport_decl.empty()) {
vars["qualifier"] = options_.dllexport_decl + " " + vars["qualifier"];
}
} else {
vars["qualifier"] = "static";
}
printer->Print(vars,
"static const int $constant_name$ = $number$;\n"
"$qualifier$ ::google::protobuf::internal::ExtensionIdentifier< $extendee$,\n"
" ::google::protobuf::internal::$type_traits$, $field_type$, $packed$ >\n"
" $name$;\n"
);
}
void ExtensionGenerator::GenerateDefinition(io::Printer* printer) {
// If this is a class member, it needs to be declared in its class scope.
string scope = (descriptor_->extension_scope() == NULL) ? "" :
ClassName(descriptor_->extension_scope(), false) + "::";
string name = scope + descriptor_->name();
std::map<string, string> vars;
vars["extendee" ] = ExtendeeClassName(descriptor_);
vars["type_traits" ] = type_traits_;
vars["name" ] = name;
vars["constant_name"] = FieldConstantName(descriptor_);
vars["default" ] = DefaultValue(descriptor_);
vars["field_type" ] = SimpleItoa(static_cast<int>(descriptor_->type()));
vars["packed" ] = descriptor_->options().packed() ? "true" : "false";
vars["scope" ] = scope;
if (descriptor_->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
// We need to declare a global string which will contain the default value.
// We cannot declare it at class scope because that would require exposing
// it in the header which would be annoying for other reasons. So we
// replace :: with _ in the name and declare it as a global.
string global_name = StringReplace(name, "::", "_", true);
vars["global_name"] = global_name;
printer->Print(vars,
"const ::std::string $global_name$_default($default$);\n");
// Update the default to refer to the string global.
vars["default"] = global_name + "_default";
}
// Likewise, class members need to declare the field constant variable.
if (descriptor_->extension_scope() != NULL) {
printer->Print(vars,
"#if !defined(_MSC_VER) || _MSC_VER >= 1900\n"
"const int $scope$$constant_name$;\n"
"#endif\n");
}
printer->Print(vars,
"::google::protobuf::internal::ExtensionIdentifier< $extendee$,\n"
" ::google::protobuf::internal::$type_traits$, $field_type$, $packed$ >\n"
" $name$($constant_name$, $default$);\n");
}
} // namespace cpp
} // namespace compiler
} // namespace protobuf
} // namespace google

View File

@ -0,0 +1,83 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_EXTENSION_H__
#define GOOGLE_PROTOBUF_COMPILER_CPP_EXTENSION_H__
#include <string>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/compiler/cpp/cpp_options.h>
namespace google {
namespace protobuf {
class FieldDescriptor; // descriptor.h
namespace io {
class Printer; // printer.h
}
}
namespace protobuf {
namespace compiler {
namespace cpp {
// Generates code for an extension, which may be within the scope of some
// message or may be at file scope. This is much simpler than FieldGenerator
// since extensions are just simple identifiers with interesting types.
class ExtensionGenerator {
public:
// See generator.cc for the meaning of dllexport_decl.
explicit ExtensionGenerator(const FieldDescriptor* descriptor,
const Options& options);
~ExtensionGenerator();
// Header stuff.
void GenerateDeclaration(io::Printer* printer);
// Source file stuff.
void GenerateDefinition(io::Printer* printer);
private:
const FieldDescriptor* descriptor_;
string type_traits_;
Options options_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionGenerator);
};
} // namespace cpp
} // namespace compiler
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_H__

View File

@ -0,0 +1,195 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
#include <google/protobuf/compiler/cpp/cpp_field.h>
#include <memory>
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
#include <google/protobuf/compiler/cpp/cpp_primitive_field.h>
#include <google/protobuf/compiler/cpp/cpp_string_field.h>
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/compiler/cpp/cpp_enum_field.h>
#include <google/protobuf/compiler/cpp/cpp_map_field.h>
#include <google/protobuf/compiler/cpp/cpp_message_field.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/wire_format.h>
#include <google/protobuf/stubs/strutil.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {
using internal::WireFormat;
void SetCommonFieldVariables(const FieldDescriptor* descriptor,
std::map<string, string>* variables,
const Options& options) {
(*variables)["ns"] = Namespace(descriptor);
(*variables)["name"] = FieldName(descriptor);
(*variables)["index"] = SimpleItoa(descriptor->index());
(*variables)["number"] = SimpleItoa(descriptor->number());
(*variables)["classname"] = ClassName(FieldScope(descriptor), false);
(*variables)["declared_type"] = DeclaredTypeMethodName(descriptor->type());
(*variables)["field_member"] = FieldName(descriptor) + "_";
(*variables)["tag_size"] = SimpleItoa(
WireFormat::TagSize(descriptor->number(), descriptor->type()));
(*variables)["deprecation"] = descriptor->options().deprecated()
? " PROTOBUF_DEPRECATED" : "";
(*variables)["deprecated_attr"] = descriptor->options().deprecated()
? "GOOGLE_PROTOBUF_DEPRECATED_ATTR " : "";
if (HasFieldPresence(descriptor->file())) {
(*variables)["set_hasbit"] =
"set_has_" + FieldName(descriptor) + "();";
(*variables)["clear_hasbit"] =
"clear_has_" + FieldName(descriptor) + "();";
} else {
(*variables)["set_hasbit"] = "";
(*variables)["clear_hasbit"] = "";
}
// These variables are placeholders to pick out the beginning and ends of
// identifiers for annotations (when doing so with existing variables would
// be ambiguous or impossible). They should never be set to anything but the
// empty string.
(*variables)["{"] = "";
(*variables)["}"] = "";
}
void SetCommonOneofFieldVariables(const FieldDescriptor* descriptor,
std::map<string, string>* variables) {
const string prefix = descriptor->containing_oneof()->name() + "_.";
(*variables)["oneof_name"] = descriptor->containing_oneof()->name();
(*variables)["field_member"] = StrCat(prefix, (*variables)["name"], "_");
}
FieldGenerator::~FieldGenerator() {}
void FieldGenerator::
GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const {
// Reaching here indicates a bug. Cases are:
// - This FieldGenerator should support packing, but this method should be
// overridden.
// - This FieldGenerator doesn't support packing, and this method should
// never have been called.
GOOGLE_LOG(FATAL) << "GenerateMergeFromCodedStreamWithPacking() "
<< "called on field generator that does not support packing.";
}
FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor,
const Options& options,
SCCAnalyzer* scc_analyzer)
: descriptor_(descriptor),
options_(options),
field_generators_(descriptor->field_count()) {
// Construct all the FieldGenerators.
for (int i = 0; i < descriptor->field_count(); i++) {
field_generators_[i].reset(
MakeGenerator(descriptor->field(i), options, scc_analyzer));
}
}
FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field,
const Options& options,
SCCAnalyzer* scc_analyzer) {
if (field->is_repeated()) {
switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_MESSAGE:
if (field->is_map()) {
return new MapFieldGenerator(field, options);
} else {
return new RepeatedMessageFieldGenerator(field, options,
scc_analyzer);
}
case FieldDescriptor::CPPTYPE_STRING:
switch (field->options().ctype()) {
default: // RepeatedStringFieldGenerator handles unknown ctypes.
case FieldOptions::STRING:
return new RepeatedStringFieldGenerator(field, options);
}
case FieldDescriptor::CPPTYPE_ENUM:
return new RepeatedEnumFieldGenerator(field, options);
default:
return new RepeatedPrimitiveFieldGenerator(field, options);
}
} else if (field->containing_oneof()) {
switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_MESSAGE:
return new MessageOneofFieldGenerator(field, options, scc_analyzer);
case FieldDescriptor::CPPTYPE_STRING:
switch (field->options().ctype()) {
default: // StringOneofFieldGenerator handles unknown ctypes.
case FieldOptions::STRING:
return new StringOneofFieldGenerator(field, options);
}
case FieldDescriptor::CPPTYPE_ENUM:
return new EnumOneofFieldGenerator(field, options);
default:
return new PrimitiveOneofFieldGenerator(field, options);
}
} else {
switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_MESSAGE:
return new MessageFieldGenerator(field, options, scc_analyzer);
case FieldDescriptor::CPPTYPE_STRING:
switch (field->options().ctype()) {
default: // StringFieldGenerator handles unknown ctypes.
case FieldOptions::STRING:
return new StringFieldGenerator(field, options);
}
case FieldDescriptor::CPPTYPE_ENUM:
return new EnumFieldGenerator(field, options);
default:
return new PrimitiveFieldGenerator(field, options);
}
}
}
FieldGeneratorMap::~FieldGeneratorMap() {}
const FieldGenerator& FieldGeneratorMap::get(
const FieldDescriptor* field) const {
GOOGLE_CHECK_EQ(field->containing_type(), descriptor_);
return *field_generators_[field->index()];
}
} // namespace cpp
} // namespace compiler
} // namespace protobuf
} // namespace google

View File

@ -0,0 +1,220 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_FIELD_H__
#define GOOGLE_PROTOBUF_COMPILER_CPP_FIELD_H__
#include <map>
#include <memory>
#include <string>
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
#include <google/protobuf/compiler/cpp/cpp_options.h>
#include <google/protobuf/descriptor.h>
namespace google {
namespace protobuf {
namespace io {
class Printer; // printer.h
}
}
namespace protobuf {
namespace compiler {
namespace cpp {
// Helper function: set variables in the map that are the same for all
// field code generators.
// ['name', 'index', 'number', 'classname', 'declared_type', 'tag_size',
// 'deprecation'].
void SetCommonFieldVariables(const FieldDescriptor* descriptor,
std::map<string, string>* variables,
const Options& options);
void SetCommonOneofFieldVariables(const FieldDescriptor* descriptor,
std::map<string, string>* variables);
class FieldGenerator {
public:
explicit FieldGenerator(const Options& options) : options_(options) {}
virtual ~FieldGenerator();
// Generate lines of code declaring members fields of the message class
// needed to represent this field. These are placed inside the message
// class.
virtual void GeneratePrivateMembers(io::Printer* printer) const = 0;
// Generate static default variable for this field. These are placed inside
// the message class. Most field types don't need this, so the default
// implementation is empty.
virtual void GenerateStaticMembers(io::Printer* /*printer*/) const {}
// Generate prototypes for all of the accessor functions related to this
// field. These are placed inside the class definition.
virtual void GenerateAccessorDeclarations(io::Printer* printer) const = 0;
// Generate inline definitions of accessor functions for this field.
// These are placed inside the header after all class definitions.
virtual void GenerateInlineAccessorDefinitions(
io::Printer* printer) const = 0;
// Generate definitions of accessors that aren't inlined. These are
// placed somewhere in the .cc file.
// Most field types don't need this, so the default implementation is empty.
virtual void GenerateNonInlineAccessorDefinitions(
io::Printer* /*printer*/) const {}
// Generate lines of code (statements, not declarations) which clear the
// field. This is used to define the clear_$name$() method
virtual void GenerateClearingCode(io::Printer* printer) const = 0;
// Generate lines of code (statements, not declarations) which clear the field
// as part of the Clear() method for the whole message. For message types
// which have field presence bits, MessageGenerator::GenerateClear will have
// already checked the presence bits.
//
// Since most field types can re-use GenerateClearingCode, this method is not
// pure virtual.
virtual void GenerateMessageClearingCode(io::Printer* printer) const {
GenerateClearingCode(printer);
}
// Generate lines of code (statements, not declarations) which merges the
// contents of the field from the current message to the target message,
// which is stored in the generated code variable "from".
// This is used to fill in the MergeFrom method for the whole message.
// Details of this usage can be found in message.cc under the
// GenerateMergeFrom method.
virtual void GenerateMergingCode(io::Printer* printer) const = 0;
// Generates a copy constructor
virtual void GenerateCopyConstructorCode(io::Printer* printer) const = 0;
// Generate lines of code (statements, not declarations) which swaps
// this field and the corresponding field of another message, which
// is stored in the generated code variable "other". This is used to
// define the Swap method. Details of usage can be found in
// message.cc under the GenerateSwap method.
virtual void GenerateSwappingCode(io::Printer* printer) const = 0;
// Generate initialization code for private members declared by
// GeneratePrivateMembers(). These go into the message class's SharedCtor()
// method, invoked by each of the generated constructors.
virtual void GenerateConstructorCode(io::Printer* printer) const = 0;
// Generate any code that needs to go in the class's SharedDtor() method,
// invoked by the destructor.
// Most field types don't need this, so the default implementation is empty.
virtual void GenerateDestructorCode(io::Printer* /*printer*/) const {}
// Generate a manual destructor invocation for use when the message is on an
// arena. The code that this method generates will be executed inside a
// shared-for-the-whole-message-class method registered with OwnDestructor().
// The method should return |true| if it generated any code that requires a
// call; this allows the message generator to eliminate the OwnDestructor()
// registration if no fields require it.
virtual bool GenerateArenaDestructorCode(io::Printer* printer) const {
return false;
}
// Generate code that allocates the fields's default instance.
virtual void GenerateDefaultInstanceAllocator(io::Printer* /*printer*/)
const {}
// Generate lines to decode this field, which will be placed inside the
// message's MergeFromCodedStream() method.
virtual void GenerateMergeFromCodedStream(io::Printer* printer) const = 0;
// Returns true if this field's "MergeFromCodedStream" code needs the arena
// to be defined as a variable.
virtual bool MergeFromCodedStreamNeedsArena() const { return false; }
// Generate lines to decode this field from a packed value, which will be
// placed inside the message's MergeFromCodedStream() method.
virtual void GenerateMergeFromCodedStreamWithPacking(io::Printer* printer)
const;
// Generate lines to serialize this field, which are placed within the
// message's SerializeWithCachedSizes() method.
virtual void GenerateSerializeWithCachedSizes(io::Printer* printer) const = 0;
// Generate lines to serialize this field directly to the array "target",
// which are placed within the message's SerializeWithCachedSizesToArray()
// method. This must also advance "target" past the written bytes.
virtual void GenerateSerializeWithCachedSizesToArray(
io::Printer* printer) const = 0;
// Generate lines to compute the serialized size of this field, which
// are placed in the message's ByteSize() method.
virtual void GenerateByteSize(io::Printer* printer) const = 0;
// Any tags about field layout decisions (such as inlining) to embed in the
// offset.
virtual uint32 CalculateFieldTag() const { return 0; }
virtual bool IsInlined() const { return false; }
protected:
const Options& options_;
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGenerator);
};
// Convenience class which constructs FieldGenerators for a Descriptor.
class FieldGeneratorMap {
public:
FieldGeneratorMap(const Descriptor* descriptor, const Options& options,
SCCAnalyzer* scc_analyzer);
~FieldGeneratorMap();
const FieldGenerator& get(const FieldDescriptor* field) const;
private:
const Descriptor* descriptor_;
const Options& options_;
std::vector<std::unique_ptr<FieldGenerator>> field_generators_;
static FieldGenerator* MakeGenerator(const FieldDescriptor* field,
const Options& options,
SCCAnalyzer* scc_analyzer);
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap);
};
} // namespace cpp
} // namespace compiler
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_FIELD_H__

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,193 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_FILE_H__
#define GOOGLE_PROTOBUF_COMPILER_CPP_FILE_H__
#include <algorithm>
#include <memory>
#include <set>
#include <string>
#include <vector>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/compiler/cpp/cpp_field.h>
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
#include <google/protobuf/compiler/cpp/cpp_options.h>
namespace google {
namespace protobuf {
class FileDescriptor; // descriptor.h
namespace io {
class Printer; // printer.h
}
}
namespace protobuf {
namespace compiler {
namespace cpp {
class EnumGenerator; // enum.h
class MessageGenerator; // message.h
class ServiceGenerator; // service.h
class ExtensionGenerator; // extension.h
class FileGenerator {
public:
// See generator.cc for the meaning of dllexport_decl.
FileGenerator(const FileDescriptor* file, const Options& options);
~FileGenerator();
// Shared code between the two header generators below.
void GenerateHeader(io::Printer* printer);
// info_path, if non-empty, should be the path (relative to printer's output)
// to the metadata file describing this proto header.
void GenerateProtoHeader(io::Printer* printer,
const string& info_path);
// info_path, if non-empty, should be the path (relative to printer's output)
// to the metadata file describing this PB header.
void GeneratePBHeader(io::Printer* printer,
const string& info_path);
void GenerateSource(io::Printer* printer);
int NumMessages() const { return message_generators_.size(); }
// Similar to GenerateSource but generates only one message
void GenerateSourceForMessage(int idx, io::Printer* printer);
void GenerateGlobalSource(io::Printer* printer);
private:
// Internal type used by GenerateForwardDeclarations (defined in file.cc).
class ForwardDeclarations;
void GenerateSourceIncludes(io::Printer* printer);
void GenerateSourceDefaultInstance(int idx, io::Printer* printer);
void GenerateInitForSCC(const SCC* scc, io::Printer* printer);
void GenerateTables(io::Printer* printer);
void GenerateReflectionInitializationCode(io::Printer* printer);
// For other imports, generates their forward-declarations.
void GenerateForwardDeclarations(io::Printer* printer);
// Internal helper used by GenerateForwardDeclarations: fills 'decls'
// with all necessary forward-declarations for this file and its
// transient depednencies.
void FillForwardDeclarations(ForwardDeclarations* decls);
// Generates top or bottom of a header file.
void GenerateTopHeaderGuard(io::Printer* printer,
const string& filename_identifier);
void GenerateBottomHeaderGuard(io::Printer* printer,
const string& filename_identifier);
// Generates #include directives.
void GenerateLibraryIncludes(io::Printer* printer);
void GenerateDependencyIncludes(io::Printer* printer);
// Generate a pragma to pull in metadata using the given info_path (if
// non-empty). info_path should be relative to printer's output.
void GenerateMetadataPragma(io::Printer* printer, const string& info_path);
// Generates a couple of different pieces before definitions:
void GenerateGlobalStateFunctionDeclarations(io::Printer* printer);
// Generates types for classes.
void GenerateMessageDefinitions(io::Printer* printer);
void GenerateEnumDefinitions(io::Printer* printer);
// Generates generic service definitions.
void GenerateServiceDefinitions(io::Printer* printer);
// Generates extension identifiers.
void GenerateExtensionIdentifiers(io::Printer* printer);
// Generates inline function defintions.
void GenerateInlineFunctionDefinitions(io::Printer* printer);
void GenerateProto2NamespaceEnumSpecializations(io::Printer* printer);
// Sometimes the names we use in a .proto file happen to be defined as macros
// on some platforms (e.g., macro/minor used in plugin.proto are defined as
// macros in sys/types.h on FreeBSD and a few other platforms). To make the
// generated code compile on these platforms, we either have to undef the
// macro for these few platforms, or rename the field name for all platforms.
// Since these names are part of protobuf public API, renaming is generally
// a breaking change so we prefer the #undef approach.
void GenerateMacroUndefs(io::Printer* printer);
bool IsSCCRepresentative(const Descriptor* d) {
return GetSCCRepresentative(d) == d;
}
const Descriptor* GetSCCRepresentative(const Descriptor* d) {
return GetSCC(d)->GetRepresentative();
}
const SCC* GetSCC(const Descriptor* d) {
return scc_analyzer_.GetSCC(d);
}
const FileDescriptor* file_;
const Options options_;
SCCAnalyzer scc_analyzer_;
// Contains the post-order walk of all the messages (and child messages) in
// this file. If you need a pre-order walk just reverse iterate.
std::vector<MessageGenerator*> message_generators_;
std::vector<EnumGenerator*> enum_generators_;
std::vector<ServiceGenerator*> service_generators_;
std::vector<ExtensionGenerator*> extension_generators_;
// These members are just for owning (and thus proper deleting).
// Nested (enum/extension)_generators are owned by child messages.
std::unique_ptr<std::unique_ptr<EnumGenerator> []> enum_generators_owner_;
std::unique_ptr<std::unique_ptr<ServiceGenerator> []>
service_generators_owner_;
std::unique_ptr<std::unique_ptr<ExtensionGenerator> []>
extension_generators_owner_;
// E.g. if the package is foo.bar, package_parts_ is {"foo", "bar"}.
std::vector<string> package_parts_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator);
};
} // namespace cpp
} // namespace compiler
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_FILE_H__

View File

@ -0,0 +1,207 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
#include <google/protobuf/compiler/cpp/cpp_generator.h>
#include <vector>
#include <memory>
#include <utility>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/compiler/cpp/cpp_file.h>
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/zero_copy_stream.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {
CppGenerator::CppGenerator() {}
CppGenerator::~CppGenerator() {}
bool CppGenerator::Generate(const FileDescriptor* file,
const string& parameter,
GeneratorContext* generator_context,
string* error) const {
std::vector<std::pair<string, string> > options;
ParseGeneratorParameter(parameter, &options);
// -----------------------------------------------------------------
// parse generator options
// If the dllexport_decl option is passed to the compiler, we need to write
// it in front of every symbol that should be exported if this .proto is
// compiled into a Windows DLL. E.g., if the user invokes the protocol
// compiler as:
// protoc --cpp_out=dllexport_decl=FOO_EXPORT:outdir foo.proto
// then we'll define classes like this:
// class FOO_EXPORT Foo {
// ...
// }
// FOO_EXPORT is a macro which should expand to __declspec(dllexport) or
// __declspec(dllimport) depending on what is being compiled.
//
Options file_options;
for (int i = 0; i < options.size(); i++) {
if (options[i].first == "dllexport_decl") {
file_options.dllexport_decl = options[i].second;
} else if (options[i].first == "safe_boundary_check") {
file_options.safe_boundary_check = true;
} else if (options[i].first == "annotate_headers") {
file_options.annotate_headers = true;
} else if (options[i].first == "annotation_pragma_name") {
file_options.annotation_pragma_name = options[i].second;
} else if (options[i].first == "annotation_guard_name") {
file_options.annotation_guard_name = options[i].second;
} else if (options[i].first == "lite") {
file_options.enforce_lite = true;
} else if (options[i].first == "lite_implicit_weak_fields") {
file_options.lite_implicit_weak_fields = true;
if (!options[i].second.empty()) {
file_options.num_cc_files = strto32(options[i].second.c_str(),
NULL, 10);
}
} else if (options[i].first == "table_driven_parsing") {
file_options.table_driven_parsing = true;
} else if (options[i].first == "table_driven_serialization") {
file_options.table_driven_serialization = true;
} else {
*error = "Unknown generator option: " + options[i].first;
return false;
}
}
// The safe_boundary_check option controls behavior for Google-internal
// protobuf APIs.
if (file_options.safe_boundary_check) {
*error =
"The safe_boundary_check option is not supported outside of Google.";
return false;
}
// -----------------------------------------------------------------
string basename = StripProto(file->name());
FileGenerator file_generator(file, file_options);
// Generate header(s).
if (file_options.proto_h) {
std::unique_ptr<io::ZeroCopyOutputStream> output(
generator_context->Open(basename + ".proto.h"));
GeneratedCodeInfo annotations;
io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
&annotations);
string info_path = basename + ".proto.h.meta";
io::Printer printer(output.get(), '$', file_options.annotate_headers
? &annotation_collector
: NULL);
file_generator.GenerateProtoHeader(
&printer, file_options.annotate_headers ? info_path : "");
if (file_options.annotate_headers) {
std::unique_ptr<io::ZeroCopyOutputStream> info_output(
generator_context->Open(info_path));
annotations.SerializeToZeroCopyStream(info_output.get());
}
}
{
std::unique_ptr<io::ZeroCopyOutputStream> output(
generator_context->Open(basename + ".pb.h"));
GeneratedCodeInfo annotations;
io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
&annotations);
string info_path = basename + ".pb.h.meta";
io::Printer printer(output.get(), '$', file_options.annotate_headers
? &annotation_collector
: NULL);
file_generator.GeneratePBHeader(
&printer, file_options.annotate_headers ? info_path : "");
if (file_options.annotate_headers) {
std::unique_ptr<io::ZeroCopyOutputStream> info_output(
generator_context->Open(info_path));
annotations.SerializeToZeroCopyStream(info_output.get());
}
}
// Generate cc file(s).
if (UsingImplicitWeakFields(file, file_options)) {
{
// This is the global .cc file, containing enum/services/tables/reflection
std::unique_ptr<io::ZeroCopyOutputStream> output(
generator_context->Open(basename + ".pb.cc"));
io::Printer printer(output.get(), '$');
file_generator.GenerateGlobalSource(&printer);
}
int num_cc_files = file_generator.NumMessages();
// If we're using implicit weak fields then we allow the user to optionally
// specify how many files to generate, not counting the global pb.cc file.
// If we have more files than messages, then some files will be generated as
// empty placeholders.
if (file_options.num_cc_files > 0) {
GOOGLE_CHECK_LE(file_generator.NumMessages(), file_options.num_cc_files)
<< "There must be at least as many numbered .cc files as messages.";
num_cc_files = file_options.num_cc_files;
}
for (int i = 0; i < num_cc_files; i++) {
// TODO(gerbens) Agree on naming scheme.
std::unique_ptr<io::ZeroCopyOutputStream> output(
generator_context->Open(basename + "." + SimpleItoa(i) + ".cc"));
io::Printer printer(output.get(), '$');
if (i < file_generator.NumMessages()) {
file_generator.GenerateSourceForMessage(i, &printer);
}
}
} else {
std::unique_ptr<io::ZeroCopyOutputStream> output(
generator_context->Open(basename + ".pb.cc"));
io::Printer printer(output.get(), '$');
file_generator.GenerateSource(&printer);
}
return true;
}
} // namespace cpp
} // namespace compiler
} // namespace protobuf
} // namespace google

View File

@ -0,0 +1,72 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
//
// Generates C++ code for a given .proto file.
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_GENERATOR_H__
#define GOOGLE_PROTOBUF_COMPILER_CPP_GENERATOR_H__
#include <string>
#include <google/protobuf/compiler/code_generator.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {
// CodeGenerator implementation which generates a C++ source file and
// header. If you create your own protocol compiler binary and you want
// it to support C++ output, you can do so by registering an instance of this
// CodeGenerator with the CommandLineInterface in your main() function.
class LIBPROTOC_EXPORT CppGenerator : public CodeGenerator {
public:
CppGenerator();
~CppGenerator();
// implements CodeGenerator ----------------------------------------
bool Generate(const FileDescriptor* file,
const string& parameter,
GeneratorContext* generator_context,
string* error) const;
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CppGenerator);
};
} // namespace cpp
} // namespace compiler
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_GENERATOR_H__

View File

@ -0,0 +1,867 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
#include <google/protobuf/stubs/hash.h>
#include <limits>
#include <map>
#include <queue>
#include <vector>
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/substitute.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {
namespace {
static const char kAnyMessageName[] = "Any";
static const char kAnyProtoFile[] = "google/protobuf/any.proto";
static const char kGoogleProtobufPrefix[] = "google/protobuf/";
string DotsToUnderscores(const string& name) {
return StringReplace(name, ".", "_", true);
}
string DotsToColons(const string& name) {
return StringReplace(name, ".", "::", true);
}
const char* const kKeywordList[] = {
"alignas", "alignof", "and", "and_eq", "asm", "auto", "bitand", "bitor",
"bool", "break", "case", "catch", "char", "class", "compl", "const",
"constexpr", "const_cast", "continue", "decltype", "default", "delete", "do",
"double", "dynamic_cast", "else", "enum", "explicit", "export", "extern",
"false", "float", "for", "friend", "goto", "if", "inline", "int", "long",
"mutable", "namespace", "new", "noexcept", "not", "not_eq", "nullptr",
"operator", "or", "or_eq", "private", "protected", "public", "register",
"reinterpret_cast", "return", "short", "signed", "sizeof", "static",
"static_assert", "static_cast", "struct", "switch", "template", "this",
"thread_local", "throw", "true", "try", "typedef", "typeid", "typename",
"union", "unsigned", "using", "virtual", "void", "volatile", "wchar_t",
"while", "xor", "xor_eq"
};
hash_set<string> MakeKeywordsMap() {
hash_set<string> result;
for (int i = 0; i < GOOGLE_ARRAYSIZE(kKeywordList); i++) {
result.insert(kKeywordList[i]);
}
return result;
}
hash_set<string> kKeywords = MakeKeywordsMap();
// Returns whether the provided descriptor has an extension. This includes its
// nested types.
bool HasExtension(const Descriptor* descriptor) {
if (descriptor->extension_count() > 0) {
return true;
}
for (int i = 0; i < descriptor->nested_type_count(); ++i) {
if (HasExtension(descriptor->nested_type(i))) {
return true;
}
}
return false;
}
// Encode [0..63] as 'A'-'Z', 'a'-'z', '0'-'9', '_'
char Base63Char(int value) {
GOOGLE_CHECK_GE(value, 0);
if (value < 26) return 'A' + value;
value -= 26;
if (value < 26) return 'a' + value;
value -= 26;
if (value < 10) return '0' + value;
GOOGLE_CHECK_EQ(value, 10);
return '_';
}
// Given a c identifier has 63 legal characters we can't implement base64
// encoding. So we return the k least significant "digits" in base 63.
template <typename I>
string Base63(I n, int k) {
string res;
while (k-- > 0) {
res += Base63Char(static_cast<int>(n % 63));
n /= 63;
}
return res;
}
} // namespace
string UnderscoresToCamelCase(const string& input, bool cap_next_letter) {
string result;
// Note: I distrust ctype.h due to locales.
for (int i = 0; i < input.size(); i++) {
if ('a' <= input[i] && input[i] <= 'z') {
if (cap_next_letter) {
result += input[i] + ('A' - 'a');
} else {
result += input[i];
}
cap_next_letter = false;
} else if ('A' <= input[i] && input[i] <= 'Z') {
// Capital letters are left as-is.
result += input[i];
cap_next_letter = false;
} else if ('0' <= input[i] && input[i] <= '9') {
result += input[i];
cap_next_letter = true;
} else {
cap_next_letter = true;
}
}
return result;
}
const char kThickSeparator[] =
"// ===================================================================\n";
const char kThinSeparator[] =
"// -------------------------------------------------------------------\n";
bool CanInitializeByZeroing(const FieldDescriptor* field) {
if (field->is_repeated() || field->is_extension()) return false;
switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_ENUM:
return field->default_value_enum()->number() == 0;
case FieldDescriptor::CPPTYPE_INT32:
return field->default_value_int32() == 0;
case FieldDescriptor::CPPTYPE_INT64:
return field->default_value_int64() == 0;
case FieldDescriptor::CPPTYPE_UINT32:
return field->default_value_uint32() == 0;
case FieldDescriptor::CPPTYPE_UINT64:
return field->default_value_uint64() == 0;
case FieldDescriptor::CPPTYPE_FLOAT:
return field->default_value_float() == 0;
case FieldDescriptor::CPPTYPE_DOUBLE:
return field->default_value_double() == 0;
case FieldDescriptor::CPPTYPE_BOOL:
return field->default_value_bool() == false;
default:
return false;
}
}
string ClassName(const Descriptor* descriptor) {
const Descriptor* parent = descriptor->containing_type();
string res;
if (parent) res += ClassName(parent) + "_";
res += descriptor->name();
if (IsMapEntryMessage(descriptor)) res += "_DoNotUse";
return res;
}
string ClassName(const EnumDescriptor* enum_descriptor) {
if (enum_descriptor->containing_type() == NULL) {
return enum_descriptor->name();
} else {
return ClassName(enum_descriptor->containing_type()) + "_" +
enum_descriptor->name();
}
}
string Namespace(const string& package) {
if (package.empty()) return "";
return "::" + DotsToColons(package);
}
string DefaultInstanceName(const Descriptor* descriptor) {
string prefix = descriptor->file()->package().empty() ? "" : "::";
return prefix + DotsToColons(descriptor->file()->package()) + "::_" +
ClassName(descriptor, false) + "_default_instance_";
}
string ReferenceFunctionName(const Descriptor* descriptor) {
return QualifiedClassName(descriptor) + "_ReferenceStrong";
}
string SuperClassName(const Descriptor* descriptor, const Options& options) {
return HasDescriptorMethods(descriptor->file(), options)
? "::google::protobuf::Message"
: "::google::protobuf::MessageLite";
}
string FieldName(const FieldDescriptor* field) {
string result = field->name();
LowerString(&result);
if (kKeywords.count(result) > 0) {
result.append("_");
}
return result;
}
string EnumValueName(const EnumValueDescriptor* enum_value) {
string result = enum_value->name();
if (kKeywords.count(result) > 0) {
result.append("_");
}
return result;
}
int EstimateAlignmentSize(const FieldDescriptor* field) {
if (field == NULL) return 0;
if (field->is_repeated()) return 8;
switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_BOOL:
return 1;
case FieldDescriptor::CPPTYPE_INT32:
case FieldDescriptor::CPPTYPE_UINT32:
case FieldDescriptor::CPPTYPE_ENUM:
case FieldDescriptor::CPPTYPE_FLOAT:
return 4;
case FieldDescriptor::CPPTYPE_INT64:
case FieldDescriptor::CPPTYPE_UINT64:
case FieldDescriptor::CPPTYPE_DOUBLE:
case FieldDescriptor::CPPTYPE_STRING:
case FieldDescriptor::CPPTYPE_MESSAGE:
return 8;
}
GOOGLE_LOG(FATAL) << "Can't get here.";
return -1; // Make compiler happy.
}
string FieldConstantName(const FieldDescriptor *field) {
string field_name = UnderscoresToCamelCase(field->name(), true);
string result = "k" + field_name + "FieldNumber";
if (!field->is_extension() &&
field->containing_type()->FindFieldByCamelcaseName(
field->camelcase_name()) != field) {
// This field's camelcase name is not unique. As a hack, add the field
// number to the constant name. This makes the constant rather useless,
// but what can we do?
result += "_" + SimpleItoa(field->number());
}
return result;
}
string FieldMessageTypeName(const FieldDescriptor* field) {
// Note: The Google-internal version of Protocol Buffers uses this function
// as a hook point for hacks to support legacy code.
return ClassName(field->message_type(), true);
}
string StripProto(const string& filename) {
if (HasSuffixString(filename, ".protodevel")) {
return StripSuffixString(filename, ".protodevel");
} else {
return StripSuffixString(filename, ".proto");
}
}
const char* PrimitiveTypeName(FieldDescriptor::CppType type) {
switch (type) {
case FieldDescriptor::CPPTYPE_INT32 : return "::google::protobuf::int32";
case FieldDescriptor::CPPTYPE_INT64 : return "::google::protobuf::int64";
case FieldDescriptor::CPPTYPE_UINT32 : return "::google::protobuf::uint32";
case FieldDescriptor::CPPTYPE_UINT64 : return "::google::protobuf::uint64";
case FieldDescriptor::CPPTYPE_DOUBLE : return "double";
case FieldDescriptor::CPPTYPE_FLOAT : return "float";
case FieldDescriptor::CPPTYPE_BOOL : return "bool";
case FieldDescriptor::CPPTYPE_ENUM : return "int";
case FieldDescriptor::CPPTYPE_STRING : return "::std::string";
case FieldDescriptor::CPPTYPE_MESSAGE: return NULL;
// No default because we want the compiler to complain if any new
// CppTypes are added.
}
GOOGLE_LOG(FATAL) << "Can't get here.";
return NULL;
}
const char* DeclaredTypeMethodName(FieldDescriptor::Type type) {
switch (type) {
case FieldDescriptor::TYPE_INT32 : return "Int32";
case FieldDescriptor::TYPE_INT64 : return "Int64";
case FieldDescriptor::TYPE_UINT32 : return "UInt32";
case FieldDescriptor::TYPE_UINT64 : return "UInt64";
case FieldDescriptor::TYPE_SINT32 : return "SInt32";
case FieldDescriptor::TYPE_SINT64 : return "SInt64";
case FieldDescriptor::TYPE_FIXED32 : return "Fixed32";
case FieldDescriptor::TYPE_FIXED64 : return "Fixed64";
case FieldDescriptor::TYPE_SFIXED32: return "SFixed32";
case FieldDescriptor::TYPE_SFIXED64: return "SFixed64";
case FieldDescriptor::TYPE_FLOAT : return "Float";
case FieldDescriptor::TYPE_DOUBLE : return "Double";
case FieldDescriptor::TYPE_BOOL : return "Bool";
case FieldDescriptor::TYPE_ENUM : return "Enum";
case FieldDescriptor::TYPE_STRING : return "String";
case FieldDescriptor::TYPE_BYTES : return "Bytes";
case FieldDescriptor::TYPE_GROUP : return "Group";
case FieldDescriptor::TYPE_MESSAGE : return "Message";
// No default because we want the compiler to complain if any new
// types are added.
}
GOOGLE_LOG(FATAL) << "Can't get here.";
return "";
}
string Int32ToString(int number) {
// gcc rejects the decimal form of kint32min.
if (number == kint32min) {
GOOGLE_COMPILE_ASSERT(kint32min == (~0x7fffffff), kint32min_value_error);
return "(~0x7fffffff)";
} else {
return SimpleItoa(number);
}
}
string Int64ToString(int64 number) {
// gcc rejects the decimal form of kint64min
if (number == kint64min) {
// Make sure we are in a 2's complement system.
GOOGLE_COMPILE_ASSERT(kint64min == GOOGLE_LONGLONG(~0x7fffffffffffffff),
kint64min_value_error);
return "GOOGLE_LONGLONG(~0x7fffffffffffffff)";
}
return "GOOGLE_LONGLONG(" + SimpleItoa(number) + ")";
}
string DefaultValue(const FieldDescriptor* field) {
switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_INT32:
return Int32ToString(field->default_value_int32());
case FieldDescriptor::CPPTYPE_UINT32:
return SimpleItoa(field->default_value_uint32()) + "u";
case FieldDescriptor::CPPTYPE_INT64:
return Int64ToString(field->default_value_int64());
case FieldDescriptor::CPPTYPE_UINT64:
return "GOOGLE_ULONGLONG(" + SimpleItoa(field->default_value_uint64())+ ")";
case FieldDescriptor::CPPTYPE_DOUBLE: {
double value = field->default_value_double();
if (value == std::numeric_limits<double>::infinity()) {
return "::google::protobuf::internal::Infinity()";
} else if (value == -std::numeric_limits<double>::infinity()) {
return "-::google::protobuf::internal::Infinity()";
} else if (value != value) {
return "::google::protobuf::internal::NaN()";
} else {
return SimpleDtoa(value);
}
}
case FieldDescriptor::CPPTYPE_FLOAT:
{
float value = field->default_value_float();
if (value == std::numeric_limits<float>::infinity()) {
return "static_cast<float>(::google::protobuf::internal::Infinity())";
} else if (value == -std::numeric_limits<float>::infinity()) {
return "static_cast<float>(-::google::protobuf::internal::Infinity())";
} else if (value != value) {
return "static_cast<float>(::google::protobuf::internal::NaN())";
} else {
string float_value = SimpleFtoa(value);
// If floating point value contains a period (.) or an exponent
// (either E or e), then append suffix 'f' to make it a float
// literal.
if (float_value.find_first_of(".eE") != string::npos) {
float_value.push_back('f');
}
return float_value;
}
}
case FieldDescriptor::CPPTYPE_BOOL:
return field->default_value_bool() ? "true" : "false";
case FieldDescriptor::CPPTYPE_ENUM:
// Lazy: Generate a static_cast because we don't have a helper function
// that constructs the full name of an enum value.
return strings::Substitute(
"static_cast< $0 >($1)",
ClassName(field->enum_type(), true),
Int32ToString(field->default_value_enum()->number()));
case FieldDescriptor::CPPTYPE_STRING:
return "\"" + EscapeTrigraphs(
CEscape(field->default_value_string())) +
"\"";
case FieldDescriptor::CPPTYPE_MESSAGE:
return "*" + FieldMessageTypeName(field) +
"::internal_default_instance()";
}
// Can't actually get here; make compiler happy. (We could add a default
// case above but then we wouldn't get the nice compiler warning when a
// new type is added.)
GOOGLE_LOG(FATAL) << "Can't get here.";
return "";
}
// Convert a file name into a valid identifier.
string FilenameIdentifier(const string& filename) {
string result;
for (int i = 0; i < filename.size(); i++) {
if (ascii_isalnum(filename[i])) {
result.push_back(filename[i]);
} else {
// Not alphanumeric. To avoid any possibility of name conflicts we
// use the hex code for the character.
StrAppend(&result, "_", strings::Hex(static_cast<uint8>(filename[i])));
}
}
return result;
}
string FileLevelNamespace(const string& filename) {
return "protobuf_" + FilenameIdentifier(filename);
}
// Return the qualified C++ name for a file level symbol.
string QualifiedFileLevelSymbol(const string& package, const string& name) {
if (package.empty()) {
return StrCat("::", name);
}
return StrCat("::", DotsToColons(package), "::", name);
}
// Escape C++ trigraphs by escaping question marks to \?
string EscapeTrigraphs(const string& to_escape) {
return StringReplace(to_escape, "?", "\\?", true);
}
// Escaped function name to eliminate naming conflict.
string SafeFunctionName(const Descriptor* descriptor,
const FieldDescriptor* field,
const string& prefix) {
// Do not use FieldName() since it will escape keywords.
string name = field->name();
LowerString(&name);
string function_name = prefix + name;
if (descriptor->FindFieldByName(function_name)) {
// Single underscore will also make it conflicting with the private data
// member. We use double underscore to escape function names.
function_name.append("__");
} else if (kKeywords.count(name) > 0) {
// If the field name is a keyword, we append the underscore back to keep it
// consistent with other function names.
function_name.append("_");
}
return function_name;
}
static bool HasMapFields(const Descriptor* descriptor) {
for (int i = 0; i < descriptor->field_count(); ++i) {
if (descriptor->field(i)->is_map()) {
return true;
}
}
for (int i = 0; i < descriptor->nested_type_count(); ++i) {
if (HasMapFields(descriptor->nested_type(i))) return true;
}
return false;
}
bool HasMapFields(const FileDescriptor* file) {
for (int i = 0; i < file->message_type_count(); ++i) {
if (HasMapFields(file->message_type(i))) return true;
}
return false;
}
static bool HasEnumDefinitions(const Descriptor* message_type) {
if (message_type->enum_type_count() > 0) return true;
for (int i = 0; i < message_type->nested_type_count(); ++i) {
if (HasEnumDefinitions(message_type->nested_type(i))) return true;
}
return false;
}
bool HasEnumDefinitions(const FileDescriptor* file) {
if (file->enum_type_count() > 0) return true;
for (int i = 0; i < file->message_type_count(); ++i) {
if (HasEnumDefinitions(file->message_type(i))) return true;
}
return false;
}
bool IsStringOrMessage(const FieldDescriptor* field) {
switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_INT32:
case FieldDescriptor::CPPTYPE_INT64:
case FieldDescriptor::CPPTYPE_UINT32:
case FieldDescriptor::CPPTYPE_UINT64:
case FieldDescriptor::CPPTYPE_DOUBLE:
case FieldDescriptor::CPPTYPE_FLOAT:
case FieldDescriptor::CPPTYPE_BOOL:
case FieldDescriptor::CPPTYPE_ENUM:
return false;
case FieldDescriptor::CPPTYPE_STRING:
case FieldDescriptor::CPPTYPE_MESSAGE:
return true;
}
GOOGLE_LOG(FATAL) << "Can't get here.";
return false;
}
FieldOptions::CType EffectiveStringCType(const FieldDescriptor* field) {
GOOGLE_DCHECK(field->cpp_type() == FieldDescriptor::CPPTYPE_STRING);
// Open-source protobuf release only supports STRING ctype.
return FieldOptions::STRING;
}
bool IsAnyMessage(const FileDescriptor* descriptor) {
return descriptor->name() == kAnyProtoFile;
}
bool IsAnyMessage(const Descriptor* descriptor) {
return descriptor->name() == kAnyMessageName &&
descriptor->file()->name() == kAnyProtoFile;
}
bool IsWellKnownMessage(const FileDescriptor* descriptor) {
return !descriptor->name().compare(0, 16, kGoogleProtobufPrefix);
}
enum Utf8CheckMode {
STRICT = 0, // Parsing will fail if non UTF-8 data is in string fields.
VERIFY = 1, // Only log an error but parsing will succeed.
NONE = 2, // No UTF-8 check.
};
// Which level of UTF-8 enforcemant is placed on this file.
static Utf8CheckMode GetUtf8CheckMode(const FieldDescriptor* field,
const Options& options) {
if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) {
return STRICT;
} else if (GetOptimizeFor(field->file(), options) !=
FileOptions::LITE_RUNTIME) {
return VERIFY;
} else {
return NONE;
}
}
static void GenerateUtf8CheckCode(const FieldDescriptor* field,
const Options& options, bool for_parse,
const std::map<string, string>& variables,
const char* parameters,
const char* strict_function,
const char* verify_function,
io::Printer* printer) {
switch (GetUtf8CheckMode(field, options)) {
case STRICT: {
if (for_parse) {
printer->Print("DO_(");
}
printer->Print(
"::google::protobuf::internal::WireFormatLite::$function$(\n",
"function", strict_function);
printer->Indent();
printer->Print(variables, parameters);
if (for_parse) {
printer->Print("::google::protobuf::internal::WireFormatLite::PARSE,\n");
} else {
printer->Print("::google::protobuf::internal::WireFormatLite::SERIALIZE,\n");
}
printer->Print("\"$full_name$\")", "full_name", field->full_name());
if (for_parse) {
printer->Print(")");
}
printer->Print(";\n");
printer->Outdent();
break;
}
case VERIFY: {
printer->Print(
"::google::protobuf::internal::WireFormat::$function$(\n",
"function", verify_function);
printer->Indent();
printer->Print(variables, parameters);
if (for_parse) {
printer->Print("::google::protobuf::internal::WireFormat::PARSE,\n");
} else {
printer->Print("::google::protobuf::internal::WireFormat::SERIALIZE,\n");
}
printer->Print("\"$full_name$\");\n", "full_name", field->full_name());
printer->Outdent();
break;
}
case NONE:
break;
}
}
void GenerateUtf8CheckCodeForString(const FieldDescriptor* field,
const Options& options, bool for_parse,
const std::map<string, string>& variables,
const char* parameters,
io::Printer* printer) {
GenerateUtf8CheckCode(field, options, for_parse, variables, parameters,
"VerifyUtf8String", "VerifyUTF8StringNamedField",
printer);
}
void GenerateUtf8CheckCodeForCord(const FieldDescriptor* field,
const Options& options, bool for_parse,
const std::map<string, string>& variables,
const char* parameters,
io::Printer* printer) {
GenerateUtf8CheckCode(field, options, for_parse, variables, parameters,
"VerifyUtf8Cord", "VerifyUTF8CordNamedField", printer);
}
namespace {
void Flatten(const Descriptor* descriptor,
std::vector<const Descriptor*>* flatten) {
for (int i = 0; i < descriptor->nested_type_count(); i++)
Flatten(descriptor->nested_type(i), flatten);
flatten->push_back(descriptor);
}
} // namespace
void FlattenMessagesInFile(const FileDescriptor* file,
std::vector<const Descriptor*>* result) {
for (int i = 0; i < file->message_type_count(); i++) {
Flatten(file->message_type(i), result);
}
}
bool HasWeakFields(const Descriptor* descriptor) {
return false;
}
bool HasWeakFields(const FileDescriptor* file) {
return false;
}
bool UsingImplicitWeakFields(const FileDescriptor* file,
const Options& options) {
return options.lite_implicit_weak_fields &&
GetOptimizeFor(file, options) == FileOptions::LITE_RUNTIME;
}
bool IsImplicitWeakField(const FieldDescriptor* field, const Options& options,
SCCAnalyzer* scc_analyzer) {
return UsingImplicitWeakFields(field->file(), options) &&
field->type() == FieldDescriptor::TYPE_MESSAGE &&
!field->is_required() && !field->is_map() &&
field->containing_oneof() == NULL &&
!IsWellKnownMessage(field->message_type()->file()) &&
// We do not support implicit weak fields between messages in the same
// strongly-connected component.
scc_analyzer->GetSCC(field->containing_type()) !=
scc_analyzer->GetSCC(field->message_type());
}
struct CompareDescriptors {
bool operator()(const Descriptor* a, const Descriptor* b) {
return a->full_name() < b->full_name();
}
};
SCCAnalyzer::NodeData SCCAnalyzer::DFS(const Descriptor* descriptor) {
// Must not have visited already.
GOOGLE_DCHECK_EQ(cache_.count(descriptor), 0);
// Mark visited by inserting in map.
NodeData& result = cache_[descriptor];
// Initialize data structures.
result.index = result.lowlink = index_++;
stack_.push_back(descriptor);
// Recurse the fields / nodes in graph
for (int i = 0; i < descriptor->field_count(); i++) {
const Descriptor* child = descriptor->field(i)->message_type();
if (child) {
if (cache_.count(child) == 0) {
// unexplored node
NodeData child_data = DFS(child);
result.lowlink = std::min(result.lowlink, child_data.lowlink);
} else {
NodeData child_data = cache_[child];
if (child_data.scc == NULL) {
// Still in the stack_ so we found a back edge
result.lowlink = std::min(result.lowlink, child_data.index);
}
}
}
}
if (result.index == result.lowlink) {
// This is the root of a strongly connected component
SCC* scc = CreateSCC();
while (true) {
const Descriptor* scc_desc = stack_.back();
scc->descriptors.push_back(scc_desc);
// Remove from stack
stack_.pop_back();
cache_[scc_desc].scc = scc;
if (scc_desc == descriptor) break;
}
// The order of descriptors is random and depends how this SCC was
// discovered. In-order to ensure maximum stability we sort it by name.
std::sort(scc->descriptors.begin(), scc->descriptors.end(),
CompareDescriptors());
AddChildren(scc);
}
return result;
}
void SCCAnalyzer::AddChildren(SCC* scc) {
std::set<const SCC*> seen;
for (int i = 0; i < scc->descriptors.size(); i++) {
const Descriptor* descriptor = scc->descriptors[i];
for (int j = 0; j < descriptor->field_count(); j++) {
const Descriptor* child_msg = descriptor->field(j)->message_type();
if (child_msg) {
const SCC* child = GetSCC(child_msg);
if (child == scc) continue;
if (seen.insert(child).second) {
scc->children.push_back(child);
}
}
}
}
}
MessageAnalysis SCCAnalyzer::GetSCCAnalysis(const SCC* scc) {
if (analysis_cache_.count(scc)) return analysis_cache_[scc];
MessageAnalysis result = MessageAnalysis();
for (int i = 0; i < scc->descriptors.size(); i++) {
const Descriptor* descriptor = scc->descriptors[i];
if (descriptor->extension_range_count() > 0) {
result.contains_extension = true;
}
for (int i = 0; i < descriptor->field_count(); i++) {
const FieldDescriptor* field = descriptor->field(i);
if (field->is_required()) {
result.contains_required = true;
}
switch (field->type()) {
case FieldDescriptor::TYPE_STRING:
case FieldDescriptor::TYPE_BYTES: {
if (field->options().ctype() == FieldOptions::CORD) {
result.contains_cord = true;
}
break;
}
case FieldDescriptor::TYPE_GROUP:
case FieldDescriptor::TYPE_MESSAGE: {
const SCC* child = GetSCC(field->message_type());
if (child != scc) {
MessageAnalysis analysis = GetSCCAnalysis(child);
result.contains_cord |= analysis.contains_cord;
result.contains_extension |= analysis.contains_extension;
if (!ShouldIgnoreRequiredFieldCheck(field, options_)) {
result.contains_required |= analysis.contains_required;
}
} else {
// This field points back into the same SCC hence the messages
// in the SCC are recursive. Note if SCC contains more than two
// nodes it has to be recursive, however this test also works for
// a single node that is recursive.
result.is_recursive = true;
}
break;
}
default:
break;
}
}
}
// We deliberately only insert the result here. After we contracted the SCC
// in the graph, the graph should be a DAG. Hence we shouldn't need to mark
// nodes visited as we can never return to them. By inserting them here
// we will go in an infinite loop if the SCC is not correct.
return analysis_cache_[scc] = result;
}
void ListAllFields(const Descriptor* d,
std::vector<const FieldDescriptor*>* fields) {
// Collect sub messages
for (int i = 0; i < d->nested_type_count(); i++) {
ListAllFields(d->nested_type(i), fields);
}
// Collect message level extensions.
for (int i = 0; i < d->extension_count(); i++) {
fields->push_back(d->extension(i));
}
// Add types of fields necessary
for (int i = 0; i < d->field_count(); i++) {
fields->push_back(d->field(i));
}
}
void ListAllFields(const FileDescriptor* d,
std::vector<const FieldDescriptor*>* fields) {
// Collect file level message.
for (int i = 0; i < d->message_type_count(); i++) {
ListAllFields(d->message_type(i), fields);
}
// Collect message level extensions.
for (int i = 0; i < d->extension_count(); i++) {
fields->push_back(d->extension(i));
}
}
void ListAllTypesForServices(const FileDescriptor* fd,
std::vector<const Descriptor*>* types) {
for (int i = 0; i < fd->service_count(); i++) {
const ServiceDescriptor* sd = fd->service(i);
for (int j = 0; j < sd->method_count(); j++) {
const MethodDescriptor* method = sd->method(j);
types->push_back(method->input_type());
types->push_back(method->output_type());
}
}
}
} // namespace cpp
} // namespace compiler
} // namespace protobuf
} // namespace google

View File

@ -0,0 +1,461 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__
#define GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__
#include <map>
#include <string>
#include <google/protobuf/compiler/cpp/cpp_options.h>
#include <google/protobuf/compiler/code_generator.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/stubs/strutil.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {
// Commonly-used separator comments. Thick is a line of '=', thin is a line
// of '-'.
extern const char kThickSeparator[];
extern const char kThinSeparator[];
// Name space of the proto file. This namespace is such that the string
// "<namespace>::some_name" is the correct fully qualified namespace.
// This means if the package is empty the namespace is "", and otherwise
// the namespace is "::foo::bar::...::baz" without trailing semi-colons.
string Namespace(const string& package);
inline string Namespace(const FileDescriptor* d) {
return Namespace(d->package());
}
template <typename Desc>
string Namespace(const Desc* d) {
return Namespace(d->file());
}
// Returns true if it's safe to reset "field" to zero.
bool CanInitializeByZeroing(const FieldDescriptor* field);
string ClassName(const Descriptor* descriptor);
string ClassName(const EnumDescriptor* enum_descriptor);
template <typename Desc>
string QualifiedClassName(const Desc* d) {
return Namespace(d) + "::" + ClassName(d);
}
// DEPRECATED just use ClassName or QualifiedClassName, a boolean is very
// unreadable at the callsite.
// Returns the non-nested type name for the given type. If "qualified" is
// true, prefix the type with the full namespace. For example, if you had:
// package foo.bar;
// message Baz { message Qux {} }
// Then the qualified ClassName for Qux would be:
// ::foo::bar::Baz_Qux
// While the non-qualified version would be:
// Baz_Qux
inline string ClassName(const Descriptor* descriptor, bool qualified) {
return qualified ? QualifiedClassName(descriptor) : ClassName(descriptor);
}
inline string ClassName(const EnumDescriptor* descriptor, bool qualified) {
return qualified ? QualifiedClassName(descriptor) : ClassName(descriptor);
}
// Fully qualified name of the default_instance of this message.
string DefaultInstanceName(const Descriptor* descriptor);
// Returns the name of a no-op function that we can call to introduce a linker
// dependency on the given message type. This is used to implement implicit weak
// fields.
string ReferenceFunctionName(const Descriptor* descriptor);
// Name of the base class: google::protobuf::Message or google::protobuf::MessageLite.
string SuperClassName(const Descriptor* descriptor, const Options& options);
// Get the (unqualified) name that should be used for this field in C++ code.
// The name is coerced to lower-case to emulate proto1 behavior. People
// should be using lowercase-with-underscores style for proto field names
// anyway, so normally this just returns field->name().
string FieldName(const FieldDescriptor* field);
// Get the sanitized name that should be used for the given enum in C++ code.
string EnumValueName(const EnumValueDescriptor* enum_value);
// Returns an estimate of the compiler's alignment for the field. This
// can't guarantee to be correct because the generated code could be compiled on
// different systems with different alignment rules. The estimates below assume
// 64-bit pointers.
int EstimateAlignmentSize(const FieldDescriptor* field);
// Get the unqualified name that should be used for a field's field
// number constant.
string FieldConstantName(const FieldDescriptor *field);
// Returns the scope where the field was defined (for extensions, this is
// different from the message type to which the field applies).
inline const Descriptor* FieldScope(const FieldDescriptor* field) {
return field->is_extension() ?
field->extension_scope() : field->containing_type();
}
// Returns the fully-qualified type name field->message_type(). Usually this
// is just ClassName(field->message_type(), true);
string FieldMessageTypeName(const FieldDescriptor* field);
// Strips ".proto" or ".protodevel" from the end of a filename.
LIBPROTOC_EXPORT string StripProto(const string& filename);
// Get the C++ type name for a primitive type (e.g. "double", "::google::protobuf::int32", etc.).
// Note: non-built-in type names will be qualified, meaning they will start
// with a ::. If you are using the type as a template parameter, you will
// need to insure there is a space between the < and the ::, because the
// ridiculous C++ standard defines "<:" to be a synonym for "[".
const char* PrimitiveTypeName(FieldDescriptor::CppType type);
// Get the declared type name in CamelCase format, as is used e.g. for the
// methods of WireFormat. For example, TYPE_INT32 becomes "Int32".
const char* DeclaredTypeMethodName(FieldDescriptor::Type type);
// Return the code that evaluates to the number when compiled.
string Int32ToString(int number);
// Return the code that evaluates to the number when compiled.
string Int64ToString(int64 number);
// Get code that evaluates to the field's default value.
string DefaultValue(const FieldDescriptor* field);
// Convert a file name into a valid identifier.
string FilenameIdentifier(const string& filename);
// For each .proto file generates a unique namespace. In this namespace global
// definitions are put to prevent collisions.
string FileLevelNamespace(const string& filename);
inline string FileLevelNamespace(const FileDescriptor* file) {
return FileLevelNamespace(file->name());
}
inline string FileLevelNamespace(const Descriptor* d) {
return FileLevelNamespace(d->file());
}
// Return the qualified C++ name for a file level symbol.
string QualifiedFileLevelSymbol(const string& package, const string& name);
// Escape C++ trigraphs by escaping question marks to \?
string EscapeTrigraphs(const string& to_escape);
// Escaped function name to eliminate naming conflict.
string SafeFunctionName(const Descriptor* descriptor,
const FieldDescriptor* field,
const string& prefix);
// Returns true if unknown fields are always preserved after parsing.
inline bool AlwaysPreserveUnknownFields(const FileDescriptor* file) {
return file->syntax() != FileDescriptor::SYNTAX_PROTO3;
}
// Returns true if unknown fields are preserved after parsing.
inline bool AlwaysPreserveUnknownFields(const Descriptor* message) {
return AlwaysPreserveUnknownFields(message->file());
}
// Returns true if generated messages have public unknown fields accessors
inline bool PublicUnknownFieldsAccessors(const Descriptor* message) {
return message->file()->syntax() != FileDescriptor::SYNTAX_PROTO3;
}
// Returns the optimize mode for <file>, respecting <options.enforce_lite>.
::google::protobuf::FileOptions_OptimizeMode GetOptimizeFor(
const FileDescriptor* file, const Options& options);
// Determines whether unknown fields will be stored in an UnknownFieldSet or
// a string.
inline bool UseUnknownFieldSet(const FileDescriptor* file,
const Options& options) {
return GetOptimizeFor(file, options) != FileOptions::LITE_RUNTIME;
}
// Does the file have any map fields, necessitating the file to include
// map_field_inl.h and map.h.
bool HasMapFields(const FileDescriptor* file);
// Does this file have any enum type definitions?
bool HasEnumDefinitions(const FileDescriptor* file);
// Does this file have generated parsing, serialization, and other
// standard methods for which reflection-based fallback implementations exist?
inline bool HasGeneratedMethods(const FileDescriptor* file,
const Options& options) {
return GetOptimizeFor(file, options) != FileOptions::CODE_SIZE;
}
// Do message classes in this file have descriptor and reflection methods?
inline bool HasDescriptorMethods(const FileDescriptor* file,
const Options& options) {
return GetOptimizeFor(file, options) != FileOptions::LITE_RUNTIME;
}
// Should we generate generic services for this file?
inline bool HasGenericServices(const FileDescriptor* file,
const Options& options) {
return file->service_count() > 0 &&
GetOptimizeFor(file, options) != FileOptions::LITE_RUNTIME &&
file->options().cc_generic_services();
}
// Should we generate a separate, super-optimized code path for serializing to
// flat arrays? We don't do this in Lite mode because we'd rather reduce code
// size.
inline bool HasFastArraySerialization(const FileDescriptor* file,
const Options& options) {
return GetOptimizeFor(file, options) == FileOptions::SPEED;
}
inline bool IsMapEntryMessage(const Descriptor* descriptor) {
return descriptor->options().map_entry();
}
// Returns true if the field's CPPTYPE is string or message.
bool IsStringOrMessage(const FieldDescriptor* field);
// For a string field, returns the effective ctype. If the actual ctype is
// not supported, returns the default of STRING.
FieldOptions::CType EffectiveStringCType(const FieldDescriptor* field);
string UnderscoresToCamelCase(const string& input, bool cap_next_letter);
inline bool HasFieldPresence(const FileDescriptor* file) {
return file->syntax() != FileDescriptor::SYNTAX_PROTO3;
}
// Returns true if 'enum' semantics are such that unknown values are preserved
// in the enum field itself, rather than going to the UnknownFieldSet.
inline bool HasPreservingUnknownEnumSemantics(const FileDescriptor* file) {
return file->syntax() == FileDescriptor::SYNTAX_PROTO3;
}
inline bool SupportsArenas(const FileDescriptor* file) {
return file->options().cc_enable_arenas();
}
inline bool SupportsArenas(const Descriptor* desc) {
return SupportsArenas(desc->file());
}
inline bool SupportsArenas(const FieldDescriptor* field) {
return SupportsArenas(field->file());
}
inline bool IsCrossFileMessage(const FieldDescriptor* field) {
return field->type() == FieldDescriptor::TYPE_MESSAGE &&
field->message_type()->file() != field->file();
}
inline string MessageCreateFunction(const Descriptor* d) {
return SupportsArenas(d) ? "CreateMessage" : "Create";
}
inline string MakeDefaultName(const FieldDescriptor* field) {
return "_i_give_permission_to_break_this_code_default_" + FieldName(field) +
"_";
}
bool IsAnyMessage(const FileDescriptor* descriptor);
bool IsAnyMessage(const Descriptor* descriptor);
bool IsWellKnownMessage(const FileDescriptor* descriptor);
void GenerateUtf8CheckCodeForString(const FieldDescriptor* field,
const Options& options, bool for_parse,
const std::map<string, string>& variables,
const char* parameters,
io::Printer* printer);
void GenerateUtf8CheckCodeForCord(const FieldDescriptor* field,
const Options& options, bool for_parse,
const std::map<string, string>& variables,
const char* parameters, io::Printer* printer);
inline ::google::protobuf::FileOptions_OptimizeMode GetOptimizeFor(
const FileDescriptor* file, const Options& options) {
return options.enforce_lite
? FileOptions::LITE_RUNTIME
: file->options().optimize_for();
}
// This orders the messages in a .pb.cc as it's outputted by file.cc
void FlattenMessagesInFile(const FileDescriptor* file,
std::vector<const Descriptor*>* result);
inline std::vector<const Descriptor*> FlattenMessagesInFile(
const FileDescriptor* file) {
std::vector<const Descriptor*> result;
FlattenMessagesInFile(file, &result);
return result;
}
bool HasWeakFields(const Descriptor* desc);
bool HasWeakFields(const FileDescriptor* desc);
// Returns true if the "required" restriction check should be ignored for the
// given field.
inline static bool ShouldIgnoreRequiredFieldCheck(const FieldDescriptor* field,
const Options& options) {
return false;
}
class LIBPROTOC_EXPORT NamespaceOpener {
public:
explicit NamespaceOpener(io::Printer* printer) : printer_(printer) {}
NamespaceOpener(const string& name, io::Printer* printer)
: printer_(printer) {
ChangeTo(name);
}
~NamespaceOpener() { ChangeTo(""); }
void ChangeTo(const string& name) {
std::vector<string> new_stack_ =
Split(name, "::", true);
int len = std::min(name_stack_.size(), new_stack_.size());
int common_idx = 0;
while (common_idx < len) {
if (name_stack_[common_idx] != new_stack_[common_idx]) break;
common_idx++;
}
for (int i = name_stack_.size() - 1; i >= common_idx; i--) {
printer_->Print("} // namespace $ns$\n", "ns", name_stack_[i]);
}
name_stack_.swap(new_stack_);
for (int i = common_idx; i < name_stack_.size(); i++) {
printer_->Print("namespace $ns$ {\n", "ns", name_stack_[i]);
}
}
private:
io::Printer* printer_;
std::vector<string> name_stack_;
};
// Description of each strongly connected component. Note that the order
// of both the descriptors in this SCC and the order of children is
// deterministic.
struct SCC {
std::vector<const Descriptor*> descriptors;
std::vector<const SCC*> children;
const Descriptor* GetRepresentative() const { return descriptors[0]; }
};
struct MessageAnalysis {
bool is_recursive;
bool contains_cord;
bool contains_extension;
bool contains_required;
};
// This class is used in FileGenerator, to ensure linear instead of
// quadratic performance, if we do this per message we would get O(V*(V+E)).
// Logically this is just only used in message.cc, but in the header for
// FileGenerator to help share it.
class LIBPROTOC_EXPORT SCCAnalyzer {
public:
explicit SCCAnalyzer(const Options& options) : options_(options), index_(0) {}
~SCCAnalyzer() {
for (int i = 0; i < garbage_bin_.size(); i++) delete garbage_bin_[i];
}
const SCC* GetSCC(const Descriptor* descriptor) {
if (cache_.count(descriptor)) return cache_[descriptor].scc;
return DFS(descriptor).scc;
}
MessageAnalysis GetSCCAnalysis(const SCC* scc);
bool HasRequiredFields(const Descriptor* descriptor) {
MessageAnalysis result = GetSCCAnalysis(GetSCC(descriptor));
return result.contains_required || result.contains_extension;
}
private:
struct NodeData {
const SCC* scc; // if null it means its still on the stack
int index;
int lowlink;
};
Options options_;
std::map<const Descriptor*, NodeData> cache_;
std::map<const SCC*, MessageAnalysis> analysis_cache_;
std::vector<const Descriptor*> stack_;
int index_;
std::vector<SCC*> garbage_bin_;
SCC* CreateSCC() {
garbage_bin_.push_back(new SCC());
return garbage_bin_.back();
}
// Tarjan's Strongly Connected Components algo
NodeData DFS(const Descriptor* descriptor);
// Add the SCC's that are children of this SCC to its children.
void AddChildren(SCC* scc);
};
void ListAllFields(const Descriptor* d,
std::vector<const FieldDescriptor*>* fields);
void ListAllFields(const FileDescriptor* d,
std::vector<const FieldDescriptor*>* fields);
void ListAllTypesForServices(const FileDescriptor* fd,
std::vector<const Descriptor*>* types);
// Indicates whether we should use implicit weak fields for this file.
bool UsingImplicitWeakFields(const FileDescriptor* file,
const Options& options);
// Indicates whether to treat this field as implicitly weak.
bool IsImplicitWeakField(const FieldDescriptor* field, const Options& options,
SCCAnalyzer* scc_analyzer);
} // namespace cpp
} // namespace compiler
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__

View File

@ -0,0 +1,436 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <google/protobuf/compiler/cpp/cpp_map_field.h>
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/wire_format.h>
#include <google/protobuf/stubs/strutil.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {
bool IsProto3Field(const FieldDescriptor* field_descriptor) {
const FileDescriptor* file_descriptor = field_descriptor->file();
return file_descriptor->syntax() == FileDescriptor::SYNTAX_PROTO3;
}
void SetMessageVariables(const FieldDescriptor* descriptor,
std::map<string, string>* variables,
const Options& options) {
SetCommonFieldVariables(descriptor, variables, options);
(*variables)["type"] = ClassName(descriptor->message_type(), false);
(*variables)["file_namespace"] =
FileLevelNamespace(descriptor->file()->name());
(*variables)["stream_writer"] =
(*variables)["declared_type"] +
(HasFastArraySerialization(descriptor->message_type()->file(), options)
? "MaybeToArray"
: "");
(*variables)["full_name"] = descriptor->full_name();
const FieldDescriptor* key =
descriptor->message_type()->FindFieldByName("key");
const FieldDescriptor* val =
descriptor->message_type()->FindFieldByName("value");
(*variables)["key_cpp"] = PrimitiveTypeName(key->cpp_type());
switch (val->cpp_type()) {
case FieldDescriptor::CPPTYPE_MESSAGE:
(*variables)["val_cpp"] = FieldMessageTypeName(val);
(*variables)["wrapper"] = "EntryWrapper";
break;
case FieldDescriptor::CPPTYPE_ENUM:
(*variables)["val_cpp"] = ClassName(val->enum_type(), true);
(*variables)["wrapper"] = "EnumEntryWrapper";
break;
default:
(*variables)["val_cpp"] = PrimitiveTypeName(val->cpp_type());
(*variables)["wrapper"] = "EntryWrapper";
}
(*variables)["key_wire_type"] =
"::google::protobuf::internal::WireFormatLite::TYPE_" +
ToUpper(DeclaredTypeMethodName(key->type()));
(*variables)["val_wire_type"] =
"::google::protobuf::internal::WireFormatLite::TYPE_" +
ToUpper(DeclaredTypeMethodName(val->type()));
(*variables)["map_classname"] = ClassName(descriptor->message_type(), false);
(*variables)["number"] = SimpleItoa(descriptor->number());
(*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
if (HasDescriptorMethods(descriptor->file(), options)) {
(*variables)["lite"] = "";
} else {
(*variables)["lite"] = "Lite";
}
if (!IsProto3Field(descriptor) &&
val->type() == FieldDescriptor::TYPE_ENUM) {
const EnumValueDescriptor* default_value = val->default_value_enum();
(*variables)["default_enum_value"] = Int32ToString(default_value->number());
} else {
(*variables)["default_enum_value"] = "0";
}
}
MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor,
const Options& options)
: FieldGenerator(options), descriptor_(descriptor) {
SetMessageVariables(descriptor, &variables_, options);
}
MapFieldGenerator::~MapFieldGenerator() {}
void MapFieldGenerator::
GeneratePrivateMembers(io::Printer* printer) const {
printer->Print(variables_,
"::google::protobuf::internal::MapField$lite$<\n"
" $map_classname$,\n"
" $key_cpp$, $val_cpp$,\n"
" $key_wire_type$,\n"
" $val_wire_type$,\n"
" $default_enum_value$ > $name$_;\n");
}
void MapFieldGenerator::
GenerateAccessorDeclarations(io::Printer* printer) const {
printer->Print(
variables_,
"$deprecated_attr$const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n"
" $name$() const;\n");
printer->Annotate("name", descriptor_);
printer->Print(variables_,
"$deprecated_attr$::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n"
" ${$mutable_$name$$}$();\n");
printer->Annotate("{", "}", descriptor_);
}
void MapFieldGenerator::
GenerateInlineAccessorDefinitions(io::Printer* printer) const {
printer->Print(variables_,
"inline const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n"
"$classname$::$name$() const {\n"
" // @@protoc_insertion_point(field_map:$full_name$)\n"
" return $name$_.GetMap();\n"
"}\n"
"inline ::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n"
"$classname$::mutable_$name$() {\n"
" // @@protoc_insertion_point(field_mutable_map:$full_name$)\n"
" return $name$_.MutableMap();\n"
"}\n");
}
void MapFieldGenerator::
GenerateClearingCode(io::Printer* printer) const {
printer->Print(variables_, "$name$_.Clear();\n");
}
void MapFieldGenerator::
GenerateMergingCode(io::Printer* printer) const {
printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n");
}
void MapFieldGenerator::
GenerateSwappingCode(io::Printer* printer) const {
printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n");
}
void MapFieldGenerator::
GenerateCopyConstructorCode(io::Printer* printer) const {
GenerateConstructorCode(printer);
GenerateMergingCode(printer);
}
void MapFieldGenerator::
GenerateMergeFromCodedStream(io::Printer* printer) const {
const FieldDescriptor* key_field =
descriptor_->message_type()->FindFieldByName("key");
const FieldDescriptor* value_field =
descriptor_->message_type()->FindFieldByName("value");
bool using_entry = false;
string key;
string value;
if (IsProto3Field(descriptor_) ||
value_field->type() != FieldDescriptor::TYPE_ENUM) {
printer->Print(
variables_,
"$map_classname$::Parser< ::google::protobuf::internal::MapField$lite$<\n"
" $map_classname$,\n"
" $key_cpp$, $val_cpp$,\n"
" $key_wire_type$,\n"
" $val_wire_type$,\n"
" $default_enum_value$ >,\n"
" ::google::protobuf::Map< $key_cpp$, $val_cpp$ > >"
" parser(&$name$_);\n"
"DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(\n"
" input, &parser));\n");
key = "parser.key()";
value = "parser.value()";
} else {
using_entry = true;
key = "entry->key()";
value = "entry->value()";
printer->Print(variables_,
"::std::unique_ptr<$map_classname$> entry($name$_.NewEntry());\n");
printer->Print(variables_,
"{\n"
" ::std::string data;\n"
" DO_(::google::protobuf::internal::WireFormatLite::ReadString(input, &data));\n"
" DO_(entry->ParseFromString(data));\n"
" if ($val_cpp$_IsValid(*entry->mutable_value())) {\n"
" (*mutable_$name$())[entry->key()] =\n"
" static_cast< $val_cpp$ >(*entry->mutable_value());\n"
" } else {\n");
if (HasDescriptorMethods(descriptor_->file(), options_)) {
printer->Print(variables_,
" mutable_unknown_fields()"
"->AddLengthDelimited($number$, data);\n");
} else {
printer->Print(variables_,
" unknown_fields_stream.WriteVarint32($tag$u);\n"
" unknown_fields_stream.WriteVarint32(\n"
" static_cast< ::google::protobuf::uint32>(data.size()));\n"
" unknown_fields_stream.WriteString(data);\n");
}
printer->Print(variables_,
" }\n"
"}\n");
}
if (key_field->type() == FieldDescriptor::TYPE_STRING) {
GenerateUtf8CheckCodeForString(
key_field, options_, true, variables_,
StrCat(key, ".data(), static_cast<int>(", key, ".length()),\n").data(),
printer);
}
if (value_field->type() == FieldDescriptor::TYPE_STRING) {
GenerateUtf8CheckCodeForString(
value_field, options_, true, variables_,
StrCat(value, ".data(), static_cast<int>(", value, ".length()),\n")
.data(),
printer);
}
// If entry is allocated by arena, its desctructor should be avoided.
if (using_entry && SupportsArenas(descriptor_)) {
printer->Print(variables_,
"if (entry->GetArena() != NULL) entry.release();\n");
}
}
static void GenerateSerializationLoop(io::Printer* printer,
const std::map<string, string>& variables,
bool supports_arenas,
const string& utf8_check,
const string& loop_header,
const string& ptr,
bool loop_via_iterators) {
printer->Print(variables,
StrCat("::std::unique_ptr<$map_classname$> entry;\n",
loop_header, " {\n").c_str());
printer->Indent();
printer->Print(variables, StrCat(
"entry.reset($name$_.New$wrapper$(\n"
" ", ptr, "->first, ", ptr, "->second));\n"
"$write_entry$;\n").c_str());
// If entry is allocated by arena, its desctructor should be avoided.
if (supports_arenas) {
printer->Print(
"if (entry->GetArena() != NULL) {\n"
" entry.release();\n"
"}\n");
}
if (!utf8_check.empty()) {
// If loop_via_iterators is true then ptr is actually an iterator, and we
// create a pointer by prefixing it with "&*".
printer->Print(
StrCat(utf8_check, "(", (loop_via_iterators ? "&*" : ""), ptr, ");\n")
.c_str());
}
printer->Outdent();
printer->Print(
"}\n");
}
void MapFieldGenerator::
GenerateSerializeWithCachedSizes(io::Printer* printer) const {
std::map<string, string> variables(variables_);
variables["write_entry"] = "::google::protobuf::internal::WireFormatLite::Write" +
variables["stream_writer"] + "(\n " +
variables["number"] + ", *entry, output)";
variables["deterministic"] = "output->IsSerializationDeterministic()";
GenerateSerializeWithCachedSizes(printer, variables);
}
void MapFieldGenerator::
GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
std::map<string, string> variables(variables_);
variables["write_entry"] =
"target = ::google::protobuf::internal::WireFormatLite::\n"
" InternalWrite" + variables["declared_type"] +
"NoVirtualToArray(\n " + variables["number"] +
", *entry, deterministic, target);\n";
variables["deterministic"] = "deterministic";
GenerateSerializeWithCachedSizes(printer, variables);
}
void MapFieldGenerator::GenerateSerializeWithCachedSizes(
io::Printer* printer, const std::map<string, string>& variables) const {
printer->Print(variables,
"if (!this->$name$().empty()) {\n");
printer->Indent();
const FieldDescriptor* key_field =
descriptor_->message_type()->FindFieldByName("key");
const FieldDescriptor* value_field =
descriptor_->message_type()->FindFieldByName("value");
const bool string_key = key_field->type() == FieldDescriptor::TYPE_STRING;
const bool string_value = value_field->type() == FieldDescriptor::TYPE_STRING;
printer->Print(variables,
"typedef ::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_pointer\n"
" ConstPtr;\n");
if (string_key) {
printer->Print(variables,
"typedef ConstPtr SortItem;\n"
"typedef ::google::protobuf::internal::"
"CompareByDerefFirst<SortItem> Less;\n");
} else {
printer->Print(variables,
"typedef ::google::protobuf::internal::SortItem< $key_cpp$, ConstPtr > "
"SortItem;\n"
"typedef ::google::protobuf::internal::CompareByFirstField<SortItem> Less;\n");
}
string utf8_check;
if (string_key || string_value) {
printer->Print(
"struct Utf8Check {\n"
" static void Check(ConstPtr p) {\n");
printer->Indent();
printer->Indent();
if (string_key) {
GenerateUtf8CheckCodeForString(
key_field, options_, false, variables,
"p->first.data(), static_cast<int>(p->first.length()),\n", printer);
}
if (string_value) {
GenerateUtf8CheckCodeForString(
value_field, options_, false, variables,
"p->second.data(), static_cast<int>(p->second.length()),\n", printer);
}
printer->Outdent();
printer->Outdent();
printer->Print(
" }\n"
"};\n");
utf8_check = "Utf8Check::Check";
}
printer->Print(variables,
"\n"
"if ($deterministic$ &&\n"
" this->$name$().size() > 1) {\n"
" ::std::unique_ptr<SortItem[]> items(\n"
" new SortItem[this->$name$().size()]);\n"
" typedef ::google::protobuf::Map< $key_cpp$, $val_cpp$ >::size_type size_type;\n"
" size_type n = 0;\n"
" for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
" it = this->$name$().begin();\n"
" it != this->$name$().end(); ++it, ++n) {\n"
" items[static_cast<ptrdiff_t>(n)] = SortItem(&*it);\n"
" }\n"
" ::std::sort(&items[0], &items[static_cast<ptrdiff_t>(n)], Less());\n");
printer->Indent();
GenerateSerializationLoop(printer, variables, SupportsArenas(descriptor_),
utf8_check, "for (size_type i = 0; i < n; i++)",
string_key ? "items[static_cast<ptrdiff_t>(i)]" :
"items[static_cast<ptrdiff_t>(i)].second", false);
printer->Outdent();
printer->Print(
"} else {\n");
printer->Indent();
GenerateSerializationLoop(
printer, variables, SupportsArenas(descriptor_), utf8_check,
"for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
" it = this->$name$().begin();\n"
" it != this->$name$().end(); ++it)",
"it", true);
printer->Outdent();
printer->Print("}\n");
printer->Outdent();
printer->Print("}\n");
}
void MapFieldGenerator::
GenerateByteSize(io::Printer* printer) const {
printer->Print(variables_,
"total_size += $tag_size$ *\n"
" ::google::protobuf::internal::FromIntSize(this->$name$_size());\n"
"{\n"
" ::std::unique_ptr<$map_classname$> entry;\n"
" for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
" it = this->$name$().begin();\n"
" it != this->$name$().end(); ++it) {\n");
// If entry is allocated by arena, its desctructor should be avoided.
if (SupportsArenas(descriptor_)) {
printer->Print(variables_,
" if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
" entry.release();\n"
" }\n");
}
printer->Print(variables_,
" entry.reset($name$_.New$wrapper$(it->first, it->second));\n"
" total_size += ::google::protobuf::internal::WireFormatLite::\n"
" $declared_type$SizeNoVirtual(*entry);\n"
" }\n");
// If entry is allocated by arena, its desctructor should be avoided.
if (SupportsArenas(descriptor_)) {
printer->Print(variables_,
" if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
" entry.release();\n"
" }\n");
}
printer->Print("}\n");
}
} // namespace cpp
} // namespace compiler
} // namespace protobuf
} // namespace google

View File

@ -0,0 +1,79 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_MAP_FIELD_H__
#define GOOGLE_PROTOBUF_COMPILER_CPP_MAP_FIELD_H__
#include <map>
#include <string>
#include <google/protobuf/compiler/cpp/cpp_message_field.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {
class MapFieldGenerator : public FieldGenerator {
public:
MapFieldGenerator(const FieldDescriptor* descriptor, const Options& options);
~MapFieldGenerator();
// implements FieldGenerator ---------------------------------------
void GeneratePrivateMembers(io::Printer* printer) const;
void GenerateAccessorDeclarations(io::Printer* printer) const;
void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
void GenerateClearingCode(io::Printer* printer) const;
void GenerateMergingCode(io::Printer* printer) const;
void GenerateSwappingCode(io::Printer* printer) const;
void GenerateConstructorCode(io::Printer* printer) const {}
void GenerateCopyConstructorCode(io::Printer* printer) const;
void GenerateMergeFromCodedStream(io::Printer* printer) const;
void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
void GenerateByteSize(io::Printer* printer) const;
private:
// A helper for GenerateSerializeWithCachedSizes{,ToArray}.
void GenerateSerializeWithCachedSizes(
io::Printer* printer, const std::map<string, string>& variables) const;
const FieldDescriptor* descriptor_;
std::map<string, string> variables_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapFieldGenerator);
};
} // namespace cpp
} // namespace compiler
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_MAP_FIELD_H__

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,237 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_H__
#define GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_H__
#include <memory>
#include <set>
#include <string>
#include <google/protobuf/compiler/cpp/cpp_field.h>
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
#include <google/protobuf/compiler/cpp/cpp_message_layout_helper.h>
#include <google/protobuf/compiler/cpp/cpp_options.h>
namespace google {
namespace protobuf {
namespace io {
class Printer; // printer.h
}
}
namespace protobuf {
namespace compiler {
namespace cpp {
class EnumGenerator; // enum.h
class ExtensionGenerator; // extension.h
class MessageGenerator {
public:
// See generator.cc for the meaning of dllexport_decl.
MessageGenerator(const Descriptor* descriptor, int index_in_file_messages,
const Options& options, SCCAnalyzer* scc_analyzer);
~MessageGenerator();
// Append the two types of nested generators to the corresponding vector.
void AddGenerators(std::vector<EnumGenerator*>* enum_generators,
std::vector<ExtensionGenerator*>* extension_generators);
// Header stuff.
// Return names for forward declarations of this class and all its nested
// types. A given key in {class,enum}_names will map from a class name to the
// descriptor that was responsible for its inclusion in the map. This can be
// used to associate the descriptor with the code generated for it.
void FillMessageForwardDeclarations(
std::map<string, const Descriptor*>* class_names);
// Generate definitions for this class and all its nested types.
void GenerateClassDefinition(io::Printer* printer);
// Generate definitions of inline methods (placed at the end of the header
// file).
void GenerateInlineMethods(io::Printer* printer);
// Source file stuff.
// Generate extra fields
void GenerateExtraDefaultFields(io::Printer* printer);
// Generates code that creates default instances for fields.
void GenerateFieldDefaultInstances(io::Printer* printer);
// Generates code that initializes the message's default instance. This
// is separate from allocating because all default instances must be
// allocated before any can be initialized.
void GenerateDefaultInstanceInitializer(io::Printer* printer);
// Generate all non-inline methods for this class.
void GenerateClassMethods(io::Printer* printer);
// Generate source file code that should go outside any namespace.
void GenerateSourceInProto2Namespace(io::Printer* printer);
private:
// Generate declarations and definitions of accessors for fields.
void GenerateFieldAccessorDeclarations(io::Printer* printer);
void GenerateFieldAccessorDefinitions(io::Printer* printer);
// Generate the table-driven parsing array. Returns the number of entries
// generated.
size_t GenerateParseOffsets(io::Printer* printer);
size_t GenerateParseAuxTable(io::Printer* printer);
// Generates a ParseTable entry. Returns whether the proto uses table-driven
// parsing.
bool GenerateParseTable(io::Printer* printer, size_t offset,
size_t aux_offset);
// Generate the field offsets array. Returns the a pair of the total numer
// of entries generated and the index of the first has_bit entry.
std::pair<size_t, size_t> GenerateOffsets(io::Printer* printer);
void GenerateSchema(io::Printer* printer, int offset, int has_offset);
// For each field generates a table entry describing the field for the
// table driven serializer.
int GenerateFieldMetadata(io::Printer* printer);
// Generate constructors and destructor.
void GenerateStructors(io::Printer* printer);
// The compiler typically generates multiple copies of each constructor and
// destructor: http://gcc.gnu.org/bugs.html#nonbugs_cxx
// Placing common code in a separate method reduces the generated code size.
//
// Generate the shared constructor code.
void GenerateSharedConstructorCode(io::Printer* printer);
// Generate the shared destructor code.
void GenerateSharedDestructorCode(io::Printer* printer);
// Generate the arena-specific destructor code.
void GenerateArenaDestructorCode(io::Printer* printer);
// Helper for GenerateClear and others. Optionally emits a condition that
// assumes the existence of the cached_has_bits variable, and returns true if
// the condition was printed.
bool MaybeGenerateOptionalFieldCondition(io::Printer* printer,
const FieldDescriptor* field,
int expected_has_bits_index);
// Generate standard Message methods.
void GenerateClear(io::Printer* printer);
void GenerateOneofClear(io::Printer* printer);
void GenerateMergeFromCodedStream(io::Printer* printer);
void GenerateSerializeWithCachedSizes(io::Printer* printer);
void GenerateSerializeWithCachedSizesToArray(io::Printer* printer);
void GenerateSerializeWithCachedSizesBody(io::Printer* printer,
bool to_array);
void GenerateByteSize(io::Printer* printer);
void GenerateMergeFrom(io::Printer* printer);
void GenerateCopyFrom(io::Printer* printer);
void GenerateSwap(io::Printer* printer);
void GenerateIsInitialized(io::Printer* printer);
// Helpers for GenerateSerializeWithCachedSizes().
//
// cached_has_bit_index maintains that:
// cached_has_bits = _has_bits_[cached_has_bit_index]
// for cached_has_bit_index >= 0
void GenerateSerializeOneField(io::Printer* printer,
const FieldDescriptor* field,
bool unbounded,
int cached_has_bits_index);
// Generate a switch statement to serialize 2+ fields from the same oneof.
// Or, if fields.size() == 1, just call GenerateSerializeOneField().
void GenerateSerializeOneofFields(
io::Printer* printer, const std::vector<const FieldDescriptor*>& fields,
bool to_array);
void GenerateSerializeOneExtensionRange(
io::Printer* printer, const Descriptor::ExtensionRange* range,
bool unbounded);
// Generates has_foo() functions and variables for singular field has-bits.
void GenerateSingularFieldHasBits(const FieldDescriptor* field,
std::map<string, string> vars,
io::Printer* printer);
// Generates has_foo() functions and variables for oneof field has-bits.
void GenerateOneofHasBits(io::Printer* printer);
// Generates has_foo_bar() functions for oneof members.
void GenerateOneofMemberHasBits(const FieldDescriptor* field,
const std::map<string, string>& vars,
io::Printer* printer);
// Generates the clear_foo() method for a field.
void GenerateFieldClear(const FieldDescriptor* field,
const std::map<string, string>& vars,
bool is_inline,
io::Printer* printer);
void GenerateConstructorBody(io::Printer* printer,
std::vector<bool> already_processed,
bool copy_constructor) const;
size_t HasBitsSize() const;
std::vector<uint32> RequiredFieldsBitMask() const;
const Descriptor* descriptor_;
int index_in_file_messages_;
string classname_;
Options options_;
FieldGeneratorMap field_generators_;
// optimized_order_ is the order we layout the message's fields in the class.
// This is reused to initialize the fields in-order for cache efficiency.
//
// optimized_order_ excludes oneof fields and weak fields.
std::vector<const FieldDescriptor *> optimized_order_;
std::vector<int> has_bit_indices_;
int max_has_bit_index_;
std::unique_ptr<std::unique_ptr<EnumGenerator> []> enum_generators_;
std::unique_ptr<std::unique_ptr<ExtensionGenerator> []> extension_generators_;
int num_required_fields_;
int num_weak_fields_;
// table_driven_ indicates the generated message uses table-driven parsing.
bool table_driven_;
std::unique_ptr<MessageLayoutHelper> message_layout_helper_;
SCCAnalyzer* scc_analyzer_;
string scc_name_;
friend class FileGenerator;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator);
};
} // namespace cpp
} // namespace compiler
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_H__

View File

@ -0,0 +1,836 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
#include <google/protobuf/compiler/cpp/cpp_message_field.h>
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/stubs/strutil.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {
namespace {
// When we are generating code for implicit weak fields, we need to insert some
// additional casts. These functions return the casted expression if
// implicit_weak_field is true but otherwise return the original expression.
// Ordinarily a static_cast is enough to cast google::protobuf::MessageLite* to a class
// deriving from it, but we need a reinterpret_cast in cases where the generated
// message is forward-declared but its full definition is not visible.
string StaticCast(const string& type, const string& expression,
bool implicit_weak_field) {
if (implicit_weak_field) {
return "static_cast< " + type + " >(" + expression + ")";
} else {
return expression;
}
}
string ReinterpretCast(const string& type, const string& expression,
bool implicit_weak_field) {
if (implicit_weak_field) {
return "reinterpret_cast< " + type + " >(" + expression + ")";
} else {
return expression;
}
}
void SetMessageVariables(const FieldDescriptor* descriptor,
const Options& options, bool implicit_weak,
std::map<string, string>* variables) {
SetCommonFieldVariables(descriptor, variables, options);
(*variables)["type"] = FieldMessageTypeName(descriptor);
(*variables)["casted_member"] = ReinterpretCast(
(*variables)["type"] + "*", (*variables)["name"] + "_", implicit_weak);
(*variables)["type_default_instance"] =
DefaultInstanceName(descriptor->message_type());
(*variables)["type_reference_function"] =
implicit_weak
? (" " + ReferenceFunctionName(descriptor->message_type()) + "();\n")
: "";
(*variables)["stream_writer"] =
(*variables)["declared_type"] +
(HasFastArraySerialization(descriptor->message_type()->file(), options)
? "MaybeToArray"
: "");
// NOTE: Escaped here to unblock proto1->proto2 migration.
// TODO(liujisi): Extend this to apply for other conflicting methods.
(*variables)["release_name"] =
SafeFunctionName(descriptor->containing_type(),
descriptor, "release_");
(*variables)["full_name"] = descriptor->full_name();
}
} // namespace
// ===================================================================
MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor,
const Options& options,
SCCAnalyzer* scc_analyzer)
: FieldGenerator(options),
descriptor_(descriptor),
implicit_weak_field_(
IsImplicitWeakField(descriptor, options, scc_analyzer)) {
SetMessageVariables(descriptor, options, implicit_weak_field_, &variables_);
}
MessageFieldGenerator::~MessageFieldGenerator() {}
void MessageFieldGenerator::
GeneratePrivateMembers(io::Printer* printer) const {
if (implicit_weak_field_) {
printer->Print(variables_, "::google::protobuf::MessageLite* $name$_;\n");
} else {
printer->Print(variables_, "$type$* $name$_;\n");
}
}
void MessageFieldGenerator::
GenerateAccessorDeclarations(io::Printer* printer) const {
if (implicit_weak_field_) {
// These private accessors are used by MergeFrom and
// MergePartialFromCodedStream, and their purpose is to provide access to
// the field without creating a strong dependency on the message type.
printer->Print(variables_,
"private:\n"
"const ::google::protobuf::MessageLite& _internal_$name$() const;\n"
"::google::protobuf::MessageLite* _internal_mutable_$name$();\n"
"public:\n");
} else {
// This inline accessor directly returns member field and is used in
// Serialize such that AFDO profile correctly captures access information to
// message fields under serialize.
printer->Print(variables_,
"private:\n"
"const $type$& _internal_$name$() const;\n"
"public:\n");
}
printer->Print(variables_,
"$deprecated_attr$const $type$& $name$() const;\n");
printer->Annotate("name", descriptor_);
printer->Print(variables_, "$deprecated_attr$$type$* $release_name$();\n");
printer->Annotate("release_name", descriptor_);
printer->Print(variables_,
"$deprecated_attr$$type$* ${$mutable_$name$$}$();\n");
printer->Annotate("{", "}", descriptor_);
printer->Print(variables_,
"$deprecated_attr$void ${$set_allocated_$name$$}$"
"($type$* $name$);\n");
printer->Annotate("{", "}", descriptor_);
if (SupportsArenas(descriptor_)) {
printer->Print(variables_,
"$deprecated_attr$void "
"${$unsafe_arena_set_allocated_$name$$}$(\n"
" $type$* $name$);\n");
printer->Annotate("{", "}", descriptor_);
printer->Print(
variables_,
"$deprecated_attr$$type$* ${$unsafe_arena_release_$name$$}$();\n");
printer->Annotate("{", "}", descriptor_);
}
}
void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions(
io::Printer* printer) const {
if (implicit_weak_field_) {
printer->Print(variables_,
"const ::google::protobuf::MessageLite& $classname$::_internal_$name$() const {\n"
" if ($name$_ != NULL) {\n"
" return *$name$_;\n"
" } else if (&$type_default_instance$ != NULL) {\n"
" return *reinterpret_cast<const ::google::protobuf::MessageLite*>(\n"
" &$type_default_instance$);\n"
" } else {\n"
" return "
"*::google::protobuf::internal::ImplicitWeakMessage::default_instance();\n"
" }\n"
"}\n");
}
if (SupportsArenas(descriptor_)) {
if (implicit_weak_field_) {
printer->Print(variables_,
"::google::protobuf::MessageLite* $classname$::_internal_mutable_$name$() {\n"
" $set_hasbit$\n"
" if ($name$_ == NULL) {\n"
" if (&$type_default_instance$ == NULL) {\n"
" $name$_ = ::google::protobuf::Arena::CreateMessage<\n"
" ::google::protobuf::internal::ImplicitWeakMessage>(\n"
" GetArenaNoVirtual());\n"
" } else {\n"
" $name$_ = reinterpret_cast<const ::google::protobuf::MessageLite*>(\n"
" &$type_default_instance$)->New(GetArenaNoVirtual());\n"
" }\n"
" }\n"
" return $name$_;\n"
"}\n");
}
printer->Print(variables_,
"void $classname$::unsafe_arena_set_allocated_$name$(\n"
" $type$* $name$) {\n"
// If we're not on an arena, free whatever we were holding before.
// (If we are on arena, we can just forget the earlier pointer.)
" if (GetArenaNoVirtual() == NULL) {\n"
" delete $name$_;\n"
" }\n"
" $name$_ = $name$;\n"
" if ($name$) {\n"
" $set_hasbit$\n"
" } else {\n"
" $clear_hasbit$\n"
" }\n"
" // @@protoc_insertion_point(field_unsafe_arena_set_allocated"
":$full_name$)\n"
"}\n");
} else if (implicit_weak_field_) {
printer->Print(variables_,
"::google::protobuf::MessageLite* $classname$::_internal_mutable_$name$() {\n"
" $set_hasbit$\n"
" if ($name$_ == NULL) {\n"
" if (&$type_default_instance$ == NULL) {\n"
" $name$_ = new ::google::protobuf::internal::ImplicitWeakMessage;\n"
" } else {\n"
" $name$_ = reinterpret_cast<const ::google::protobuf::MessageLite*>(\n"
" &$type_default_instance$)->New();\n"
" }\n"
" }\n"
" return $name$_;\n"
"}\n");
}
}
void MessageFieldGenerator::
GenerateInlineAccessorDefinitions(io::Printer* printer) const {
if (!implicit_weak_field_) {
printer->Print(variables_,
"inline const $type$& $classname$::_internal_$name$() const {\n"
" return *$field_member$;\n"
"}\n");
}
printer->Print(variables_,
"inline const $type$& $classname$::$name$() const {\n"
" const $type$* p = $casted_member$;\n"
" // @@protoc_insertion_point(field_get:$full_name$)\n"
" return p != NULL ? *p : *reinterpret_cast<const $type$*>(\n"
" &$type_default_instance$);\n"
"}\n");
printer->Print(variables_,
"inline $type$* $classname$::$release_name$() {\n"
" // @@protoc_insertion_point(field_release:$full_name$)\n"
"$type_reference_function$"
" $clear_hasbit$\n"
" $type$* temp = $casted_member$;\n");
if (SupportsArenas(descriptor_)) {
printer->Print(variables_,
" if (GetArenaNoVirtual() != NULL) {\n"
" temp = ::google::protobuf::internal::DuplicateIfNonNull(temp);\n"
" }\n");
}
printer->Print(variables_,
" $name$_ = NULL;\n"
" return temp;\n"
"}\n");
if (SupportsArenas(descriptor_)) {
printer->Print(variables_,
"inline $type$* $classname$::unsafe_arena_release_$name$() {\n"
" // @@protoc_insertion_point(field_unsafe_arena_release:$full_name$)\n"
"$type_reference_function$"
" $clear_hasbit$\n"
" $type$* temp = $casted_member$;\n"
" $name$_ = NULL;\n"
" return temp;\n"
"}\n");
}
printer->Print(variables_,
"inline $type$* $classname$::mutable_$name$() {\n"
" $set_hasbit$\n"
" if ($name$_ == NULL) {\n"
" auto* p = CreateMaybeMessage<$type$>(GetArenaNoVirtual());\n");
if (implicit_weak_field_) {
printer->Print(variables_,
" $name$_ = reinterpret_cast<::google::protobuf::MessageLite*>(p);\n");
} else {
printer->Print(variables_,
" $name$_ = p;\n");
}
printer->Print(variables_,
" }\n"
" // @@protoc_insertion_point(field_mutable:$full_name$)\n"
" return $casted_member$;\n"
"}\n");
// We handle the most common case inline, and delegate less common cases to
// the slow fallback function.
printer->Print(variables_,
"inline void $classname$::set_allocated_$name$($type$* $name$) {\n"
" ::google::protobuf::Arena* message_arena = GetArenaNoVirtual();\n");
printer->Print(variables_,
" if (message_arena == NULL) {\n");
if (IsCrossFileMessage(descriptor_)) {
printer->Print(variables_,
" delete reinterpret_cast< ::google::protobuf::MessageLite*>($name$_);\n");
} else {
printer->Print(variables_,
" delete $name$_;\n");
}
printer->Print(variables_,
" }\n"
" if ($name$) {\n");
if (SupportsArenas(descriptor_->message_type()) &&
IsCrossFileMessage(descriptor_)) {
// We have to read the arena through the virtual method, because the type
// isn't defined in this file.
printer->Print(variables_,
" ::google::protobuf::Arena* submessage_arena =\n"
" reinterpret_cast<::google::protobuf::MessageLite*>($name$)->GetArena();\n");
} else if (!SupportsArenas(descriptor_->message_type())) {
printer->Print(variables_,
" ::google::protobuf::Arena* submessage_arena = NULL;\n");
} else {
printer->Print(variables_,
" ::google::protobuf::Arena* submessage_arena =\n"
" ::google::protobuf::Arena::GetArena($name$);\n");
}
printer->Print(variables_,
" if (message_arena != submessage_arena) {\n"
" $name$ = ::google::protobuf::internal::GetOwnedMessage(\n"
" message_arena, $name$, submessage_arena);\n"
" }\n"
" $set_hasbit$\n"
" } else {\n"
" $clear_hasbit$\n"
" }\n");
if (implicit_weak_field_) {
printer->Print(variables_,
" $name$_ = reinterpret_cast<MessageLite*>($name$);\n");
} else {
printer->Print(variables_,
" $name$_ = $name$;\n");
}
printer->Print(variables_,
" // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
"}\n");
}
void MessageFieldGenerator::
GenerateClearingCode(io::Printer* printer) const {
if (!HasFieldPresence(descriptor_->file())) {
// If we don't have has-bits, message presence is indicated only by ptr !=
// NULL. Thus on clear, we need to delete the object.
printer->Print(variables_,
"if (GetArenaNoVirtual() == NULL && $name$_ != NULL) {\n"
" delete $name$_;\n"
"}\n"
"$name$_ = NULL;\n");
} else {
printer->Print(variables_,
"if ($name$_ != NULL) $name$_->Clear();\n");
}
}
void MessageFieldGenerator::
GenerateMessageClearingCode(io::Printer* printer) const {
if (!HasFieldPresence(descriptor_->file())) {
// If we don't have has-bits, message presence is indicated only by ptr !=
// NULL. Thus on clear, we need to delete the object.
printer->Print(variables_,
"if (GetArenaNoVirtual() == NULL && $name$_ != NULL) {\n"
" delete $name$_;\n"
"}\n"
"$name$_ = NULL;\n");
} else {
printer->Print(variables_,
"GOOGLE_DCHECK($name$_ != NULL);\n"
"$name$_->Clear();\n");
}
}
void MessageFieldGenerator::
GenerateMergingCode(io::Printer* printer) const {
if (implicit_weak_field_) {
printer->Print(variables_,
"_internal_mutable_$name$()->CheckTypeAndMergeFrom(\n"
" from._internal_$name$());\n");
} else {
printer->Print(variables_,
"mutable_$name$()->$type$::MergeFrom(from.$name$());\n");
}
}
void MessageFieldGenerator::
GenerateSwappingCode(io::Printer* printer) const {
printer->Print(variables_, "swap($name$_, other->$name$_);\n");
}
void MessageFieldGenerator::
GenerateDestructorCode(io::Printer* printer) const {
// TODO(gerbens) Remove this when we don't need to destruct default instances.
// In google3 a default instance will never get deleted so we don't need to
// worry about that but in opensource protobuf default instances are deleted
// in shutdown process and we need to take special care when handling them.
printer->Print(variables_,
"if (this != internal_default_instance()) ");
printer->Print(variables_, "delete $name$_;\n");
}
void MessageFieldGenerator::
GenerateConstructorCode(io::Printer* printer) const {
printer->Print(variables_, "$name$_ = NULL;\n");
}
void MessageFieldGenerator::
GenerateCopyConstructorCode(io::Printer* printer) const {
printer->Print(variables_,
"if (from.has_$name$()) {\n"
" $name$_ = new $type$(*from.$name$_);\n"
"} else {\n"
" $name$_ = NULL;\n"
"}\n");
}
void MessageFieldGenerator::
GenerateMergeFromCodedStream(io::Printer* printer) const {
if (implicit_weak_field_) {
printer->Print(variables_,
"DO_(::google::protobuf::internal::WireFormatLite::ReadMessage(\n"
" input, _internal_mutable_$name$()));\n");
} else if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) {
printer->Print(variables_,
"DO_(::google::protobuf::internal::WireFormatLite::ReadMessage(\n"
" input, mutable_$name$()));\n");
} else {
printer->Print(variables_,
"DO_(::google::protobuf::internal::WireFormatLite::ReadGroup(\n"
" $number$, input, mutable_$name$()));\n");
}
}
void MessageFieldGenerator::
GenerateSerializeWithCachedSizes(io::Printer* printer) const {
printer->Print(variables_,
"::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n"
" $number$, this->_internal_$name$(), output);\n");
}
void MessageFieldGenerator::
GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
printer->Print(variables_,
"target = ::google::protobuf::internal::WireFormatLite::\n"
" InternalWrite$declared_type$ToArray(\n"
" $number$, this->_internal_$name$(), deterministic, target);\n");
}
void MessageFieldGenerator::
GenerateByteSize(io::Printer* printer) const {
printer->Print(variables_,
"total_size += $tag_size$ +\n"
" ::google::protobuf::internal::WireFormatLite::$declared_type$Size(\n"
" *$field_member$);\n");
}
// ===================================================================
MessageOneofFieldGenerator::MessageOneofFieldGenerator(
const FieldDescriptor* descriptor, const Options& options,
SCCAnalyzer* scc_analyzer)
: MessageFieldGenerator(descriptor, options, scc_analyzer) {
SetCommonOneofFieldVariables(descriptor, &variables_);
}
MessageOneofFieldGenerator::~MessageOneofFieldGenerator() {}
void MessageOneofFieldGenerator::GenerateNonInlineAccessorDefinitions(
io::Printer* printer) const {
printer->Print(variables_,
"void $classname$::set_allocated_$name$($type$* $name$) {\n"
" ::google::protobuf::Arena* message_arena = GetArenaNoVirtual();\n"
" clear_$oneof_name$();\n"
" if ($name$) {\n");
if (SupportsArenas(descriptor_->message_type()) &&
descriptor_->file() != descriptor_->message_type()->file()) {
// We have to read the arena through the virtual method, because the type
// isn't defined in this file.
printer->Print(variables_,
" ::google::protobuf::Arena* submessage_arena =\n"
" reinterpret_cast<::google::protobuf::MessageLite*>($name$)->GetArena();\n");
} else if (!SupportsArenas(descriptor_->message_type())) {
printer->Print(variables_,
" ::google::protobuf::Arena* submessage_arena = NULL;\n");
} else {
printer->Print(variables_,
" ::google::protobuf::Arena* submessage_arena =\n"
" ::google::protobuf::Arena::GetArena($name$);\n");
}
printer->Print(variables_,
" if (message_arena != submessage_arena) {\n"
" $name$ = ::google::protobuf::internal::GetOwnedMessage(\n"
" message_arena, $name$, submessage_arena);\n"
" }\n"
" set_has_$name$();\n"
" $field_member$ = $name$;\n"
" }\n"
" // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
"}\n");
}
void MessageOneofFieldGenerator::
GenerateInlineAccessorDefinitions(io::Printer* printer) const {
if (!implicit_weak_field_) {
printer->Print(variables_,
"inline const $type$& $classname$::_internal_$name$() const {\n"
" return *$field_member$;\n"
"}\n");
}
printer->Print(variables_,
"inline $type$* $classname$::$release_name$() {\n"
" // @@protoc_insertion_point(field_release:$full_name$)\n"
" if (has_$name$()) {\n"
" clear_has_$oneof_name$();\n"
" $type$* temp = $field_member$;\n");
if (SupportsArenas(descriptor_)) {
printer->Print(variables_,
" if (GetArenaNoVirtual() != NULL) {\n"
" temp = ::google::protobuf::internal::DuplicateIfNonNull(temp);\n"
" }\n");
}
printer->Print(variables_,
" $field_member$ = NULL;\n"
" return temp;\n"
" } else {\n"
" return NULL;\n"
" }\n"
"}\n");
printer->Print(variables_,
"inline const $type$& $classname$::$name$() const {\n"
" // @@protoc_insertion_point(field_get:$full_name$)\n"
" return has_$name$()\n"
" ? *$field_member$\n"
" : *reinterpret_cast< $type$*>(&$type_default_instance$);\n"
"}\n");
if (SupportsArenas(descriptor_)) {
printer->Print(variables_,
"inline $type$* $classname$::unsafe_arena_release_$name$() {\n"
" // @@protoc_insertion_point(field_unsafe_arena_release"
":$full_name$)\n"
" if (has_$name$()) {\n"
" clear_has_$oneof_name$();\n"
" $type$* temp = $field_member$;\n"
" $field_member$ = NULL;\n"
" return temp;\n"
" } else {\n"
" return NULL;\n"
" }\n"
"}\n"
"inline void $classname$::unsafe_arena_set_allocated_$name$"
"($type$* $name$) {\n"
// We rely on the oneof clear method to free the earlier contents of this
// oneof. We can directly use the pointer we're given to set the new
// value.
" clear_$oneof_name$();\n"
" if ($name$) {\n"
" set_has_$name$();\n"
" $field_member$ = $name$;\n"
" }\n"
" // @@protoc_insertion_point(field_unsafe_arena_set_allocated:"
"$full_name$)\n"
"}\n");
}
printer->Print(variables_,
"inline $type$* $classname$::mutable_$name$() {\n"
" if (!has_$name$()) {\n"
" clear_$oneof_name$();\n"
" set_has_$name$();\n"
" $field_member$ = CreateMaybeMessage< $type$ >(\n"
" GetArenaNoVirtual());\n"
" }\n"
" // @@protoc_insertion_point(field_mutable:$full_name$)\n"
" return $field_member$;\n"
"}\n");
}
void MessageOneofFieldGenerator::
GenerateClearingCode(io::Printer* printer) const {
if (SupportsArenas(descriptor_)) {
printer->Print(variables_,
"if (GetArenaNoVirtual() == NULL) {\n"
" delete $field_member$;\n"
"}\n");
} else {
printer->Print(variables_,
"delete $field_member$;\n");
}
}
void MessageOneofFieldGenerator::
GenerateMessageClearingCode(io::Printer* printer) const {
GenerateClearingCode(printer);
}
void MessageOneofFieldGenerator::
GenerateSwappingCode(io::Printer* printer) const {
// Don't print any swapping code. Swapping the union will swap this field.
}
void MessageOneofFieldGenerator::
GenerateDestructorCode(io::Printer* printer) const {
// We inherit from MessageFieldGenerator, so we need to override the default
// behavior.
}
void MessageOneofFieldGenerator::
GenerateConstructorCode(io::Printer* printer) const {
// Don't print any constructor code. The field is in a union. We allocate
// space only when this field is used.
}
// ===================================================================
RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator(
const FieldDescriptor* descriptor, const Options& options,
SCCAnalyzer* scc_analyzer)
: FieldGenerator(options),
descriptor_(descriptor),
implicit_weak_field_(
IsImplicitWeakField(descriptor, options, scc_analyzer)) {
SetMessageVariables(descriptor, options, implicit_weak_field_, &variables_);
}
RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {}
void RepeatedMessageFieldGenerator::
GeneratePrivateMembers(io::Printer* printer) const {
printer->Print(variables_,
"::google::protobuf::RepeatedPtrField< $type$ > $name$_;\n");
}
void RepeatedMessageFieldGenerator::
GenerateAccessorDeclarations(io::Printer* printer) const {
printer->Print(variables_,
"$deprecated_attr$$type$* ${$mutable_$name$$}$(int index);\n");
printer->Annotate("{", "}", descriptor_);
printer->Print(variables_,
"$deprecated_attr$::google::protobuf::RepeatedPtrField< $type$ >*\n"
" ${$mutable_$name$$}$();\n");
printer->Annotate("{", "}", descriptor_);
printer->Print(variables_,
"$deprecated_attr$const $type$& $name$(int index) const;\n");
printer->Annotate("name", descriptor_);
printer->Print(variables_, "$deprecated_attr$$type$* ${$add_$name$$}$();\n");
printer->Annotate("{", "}", descriptor_);
printer->Print(variables_,
"$deprecated_attr$const ::google::protobuf::RepeatedPtrField< $type$ >&\n"
" $name$() const;\n");
printer->Annotate("name", descriptor_);
}
void RepeatedMessageFieldGenerator::
GenerateInlineAccessorDefinitions(io::Printer* printer) const {
printer->Print(variables_,
"inline $type$* $classname$::mutable_$name$(int index) {\n"
// TODO(dlj): move insertion points
" // @@protoc_insertion_point(field_mutable:$full_name$)\n"
"$type_reference_function$"
" return $name$_.Mutable(index);\n"
"}\n"
"inline ::google::protobuf::RepeatedPtrField< $type$ >*\n"
"$classname$::mutable_$name$() {\n"
" // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
"$type_reference_function$"
" return &$name$_;\n"
"}\n");
if (options_.safe_boundary_check) {
printer->Print(variables_,
"inline const $type$& $classname$::$name$(int index) const {\n"
" // @@protoc_insertion_point(field_get:$full_name$)\n"
" return $name$_.InternalCheckedGet(index,\n"
" *reinterpret_cast<const $type$*>(&$type_default_instance$));\n"
"}\n");
} else {
printer->Print(variables_,
"inline const $type$& $classname$::$name$(int index) const {\n"
" // @@protoc_insertion_point(field_get:$full_name$)\n"
"$type_reference_function$"
" return $name$_.Get(index);\n"
"}\n");
}
printer->Print(variables_,
"inline $type$* $classname$::add_$name$() {\n"
" // @@protoc_insertion_point(field_add:$full_name$)\n"
" return $name$_.Add();\n"
"}\n");
printer->Print(variables_,
"inline const ::google::protobuf::RepeatedPtrField< $type$ >&\n"
"$classname$::$name$() const {\n"
" // @@protoc_insertion_point(field_list:$full_name$)\n"
"$type_reference_function$"
" return $name$_;\n"
"}\n");
}
void RepeatedMessageFieldGenerator::
GenerateClearingCode(io::Printer* printer) const {
if (implicit_weak_field_) {
printer->Print(
variables_,
"CastToBase(&$name$_)->Clear<"
"::google::protobuf::internal::ImplicitWeakTypeHandler<$type$>>();\n");
} else {
printer->Print(variables_, "$name$_.Clear();\n");
}
}
void RepeatedMessageFieldGenerator::
GenerateMergingCode(io::Printer* printer) const {
if (implicit_weak_field_) {
printer->Print(
variables_,
"CastToBase(&$name$_)->MergeFrom<"
"::google::protobuf::internal::ImplicitWeakTypeHandler<$type$>>(CastToBase("
"from.$name$_));\n");
} else {
printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n");
}
}
void RepeatedMessageFieldGenerator::
GenerateSwappingCode(io::Printer* printer) const {
printer->Print(
variables_,
"CastToBase(&$name$_)->InternalSwap(CastToBase(&other->$name$_));\n");
}
void RepeatedMessageFieldGenerator::
GenerateConstructorCode(io::Printer* printer) const {
// Not needed for repeated fields.
}
void RepeatedMessageFieldGenerator::
GenerateMergeFromCodedStream(io::Printer* printer) const {
if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) {
if (implicit_weak_field_) {
printer->Print(variables_,
"DO_(::google::protobuf::internal::WireFormatLite::"
"ReadMessage(input, CastToBase(&$name$_)->AddWeak(\n"
" reinterpret_cast<const ::google::protobuf::MessageLite*>(\n"
" &$type_default_instance$))));\n");
} else {
printer->Print(variables_,
"DO_(::google::protobuf::internal::WireFormatLite::"
"ReadMessage(\n"
" input, add_$name$()));\n");
}
} else {
printer->Print(variables_,
"DO_(::google::protobuf::internal::WireFormatLite::"
"ReadGroup($number$, input, add_$name$()));\n");
}
}
void RepeatedMessageFieldGenerator::
GenerateSerializeWithCachedSizes(io::Printer* printer) const {
printer->Print(variables_,
"for (unsigned int i = 0,\n"
" n = static_cast<unsigned int>(this->$name$_size()); i < n; i++) {\n"
" ::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n"
" $number$,\n");
if (implicit_weak_field_) {
printer->Print(
variables_,
" CastToBase($name$_).Get<"
"::google::protobuf::internal::ImplicitWeakTypeHandler<$type$>>("
"static_cast<int>(i)),\n");
} else {
printer->Print(variables_,
" this->$name$(static_cast<int>(i)),\n");
}
printer->Print(variables_,
" output);\n"
"}\n");
}
void RepeatedMessageFieldGenerator::
GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
printer->Print(variables_,
"for (unsigned int i = 0,\n"
" n = static_cast<unsigned int>(this->$name$_size()); i < n; i++) {\n"
" target = ::google::protobuf::internal::WireFormatLite::\n"
" InternalWrite$declared_type$ToArray(\n"
" $number$, this->$name$(static_cast<int>(i)), deterministic, target);\n"
"}\n");
}
void RepeatedMessageFieldGenerator::
GenerateByteSize(io::Printer* printer) const {
printer->Print(variables_,
"{\n"
" unsigned int count = static_cast<unsigned int>(this->$name$_size());\n");
printer->Indent();
printer->Print(variables_,
"total_size += $tag_size$UL * count;\n"
"for (unsigned int i = 0; i < count; i++) {\n"
" total_size +=\n"
" ::google::protobuf::internal::WireFormatLite::$declared_type$Size(\n");
if (implicit_weak_field_) {
printer->Print(
variables_,
" CastToBase($name$_).Get<"
"::google::protobuf::internal::ImplicitWeakTypeHandler<$type$>>("
"static_cast<int>(i)));\n");
} else {
printer->Print(variables_,
" this->$name$(static_cast<int>(i)));\n");
}
printer->Print(variables_, "}\n");
printer->Outdent();
printer->Print("}\n");
}
} // namespace cpp
} // namespace compiler
} // namespace protobuf
} // namespace google

View File

@ -0,0 +1,136 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_FIELD_H__
#define GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_FIELD_H__
#include <map>
#include <string>
#include <google/protobuf/compiler/cpp/cpp_field.h>
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {
class MessageFieldGenerator : public FieldGenerator {
public:
MessageFieldGenerator(const FieldDescriptor* descriptor,
const Options& options, SCCAnalyzer* scc_analyzer);
~MessageFieldGenerator();
// implements FieldGenerator ---------------------------------------
void GeneratePrivateMembers(io::Printer* printer) const;
void GenerateAccessorDeclarations(io::Printer* printer) const;
void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const;
void GenerateClearingCode(io::Printer* printer) const;
void GenerateMessageClearingCode(io::Printer* printer) const;
void GenerateMergingCode(io::Printer* printer) const;
void GenerateSwappingCode(io::Printer* printer) const;
void GenerateDestructorCode(io::Printer* printer) const;
void GenerateConstructorCode(io::Printer* printer) const;
void GenerateCopyConstructorCode(io::Printer* printer) const;
void GenerateMergeFromCodedStream(io::Printer* printer) const;
void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
void GenerateByteSize(io::Printer* printer) const;
protected:
const FieldDescriptor* descriptor_;
const bool implicit_weak_field_;
std::map<string, string> variables_;
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFieldGenerator);
};
class MessageOneofFieldGenerator : public MessageFieldGenerator {
public:
MessageOneofFieldGenerator(const FieldDescriptor* descriptor,
const Options& options, SCCAnalyzer* scc_analyzer);
~MessageOneofFieldGenerator();
// implements FieldGenerator ---------------------------------------
void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const;
void GenerateClearingCode(io::Printer* printer) const;
// MessageFieldGenerator, from which we inherit, overrides this so we need to
// override it as well.
void GenerateMessageClearingCode(io::Printer* printer) const;
void GenerateSwappingCode(io::Printer* printer) const;
void GenerateDestructorCode(io::Printer* printer) const;
void GenerateConstructorCode(io::Printer* printer) const;
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageOneofFieldGenerator);
};
class RepeatedMessageFieldGenerator : public FieldGenerator {
public:
RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor,
const Options& options,
SCCAnalyzer* scc_analyzer);
~RepeatedMessageFieldGenerator();
// implements FieldGenerator ---------------------------------------
void GeneratePrivateMembers(io::Printer* printer) const;
void GenerateAccessorDeclarations(io::Printer* printer) const;
void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
void GenerateClearingCode(io::Printer* printer) const;
void GenerateMergingCode(io::Printer* printer) const;
void GenerateSwappingCode(io::Printer* printer) const;
void GenerateConstructorCode(io::Printer* printer) const;
void GenerateCopyConstructorCode(io::Printer* printer) const {}
void GenerateMergeFromCodedStream(io::Printer* printer) const;
void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
void GenerateByteSize(io::Printer* printer) const;
private:
const FieldDescriptor* descriptor_;
const bool implicit_weak_field_;
std::map<string, string> variables_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator);
};
} // namespace cpp
} // namespace compiler
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_FIELD_H__

View File

@ -0,0 +1,61 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: seongkim@google.com (Seong Beom Kim)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_LAYOUT_HELPER_H__
#define GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_LAYOUT_HELPER_H__
#include <google/protobuf/compiler/cpp/cpp_options.h>
#include <google/protobuf/descriptor.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {
// Provides an abstract interface to optimize message layout
// by rearranging the fields of a message.
class MessageLayoutHelper {
public:
virtual ~MessageLayoutHelper() {}
virtual void OptimizeLayout(std::vector<const FieldDescriptor*>* fields,
const Options& options) = 0;
};
} // namespace cpp
} // namespace compiler
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_LAYOUT_HELPER_H__

View File

@ -0,0 +1,169 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/test_util.h>
#include <google/protobuf/unittest.pb.h>
#include <gtest/gtest.h>
#if LANG_CXX11
#include <type_traits>
#endif
namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {
// Can't use an anonymous namespace here due to brokenness of Tru64 compiler.
namespace cpp_unittest {
// Moves are enabled only when compiling with a C++11 compiler or newer.
#if LANG_CXX11
TEST(MovableMessageTest, MoveConstructor) {
protobuf_unittest::TestAllTypes message1;
TestUtil::SetAllFields(&message1);
const auto* nested = &message1.optional_nested_message();
protobuf_unittest::TestAllTypes message2(std::move(message1));
TestUtil::ExpectAllFieldsSet(message2);
// Check if the optional_nested_message was actually moved (and not just
// copied).
EXPECT_EQ(nested, &message2.optional_nested_message());
EXPECT_NE(nested, &message1.optional_nested_message());
}
TEST(MovableMessageTest, MoveAssignmentOperator) {
protobuf_unittest::TestAllTypes message1;
TestUtil::SetAllFields(&message1);
const auto* nested = &message1.optional_nested_message();
protobuf_unittest::TestAllTypes message2;
message2 = std::move(message1);
TestUtil::ExpectAllFieldsSet(message2);
// Check if the optional_nested_message was actually moved (and not just
// copied).
EXPECT_EQ(nested, &message2.optional_nested_message());
EXPECT_NE(nested, &message1.optional_nested_message());
}
TEST(MovableMessageTest, SelfMoveAssignment) {
// The `self` reference is necessary to defeat -Wself-move.
protobuf_unittest::TestAllTypes message, &self = message;
TestUtil::SetAllFields(&message);
message = std::move(self);
TestUtil::ExpectAllFieldsSet(message);
}
TEST(MovableMessageTest, MoveSameArena) {
Arena arena;
auto* message1_on_arena =
Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena);
TestUtil::SetAllFields(message1_on_arena);
const auto* nested = &message1_on_arena->optional_nested_message();
auto* message2_on_arena =
Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena);
// Moving messages on the same arena should lead to swapped pointers.
*message2_on_arena = std::move(*message1_on_arena);
EXPECT_EQ(nested, &message2_on_arena->optional_nested_message());
}
TEST(MovableMessageTest, MoveDifferentArenas) {
Arena arena1, arena2;
auto* message1_on_arena =
Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena1);
TestUtil::SetAllFields(message1_on_arena);
const auto* nested = &message1_on_arena->optional_nested_message();
auto* message2_on_arena =
Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena2);
// Moving messages on two different arenas should lead to a copy.
*message2_on_arena = std::move(*message1_on_arena);
EXPECT_NE(nested, &message2_on_arena->optional_nested_message());
TestUtil::ExpectAllFieldsSet(*message1_on_arena);
TestUtil::ExpectAllFieldsSet(*message2_on_arena);
}
TEST(MovableMessageTest, MoveFromArena) {
Arena arena;
auto* message1_on_arena =
Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena);
TestUtil::SetAllFields(message1_on_arena);
const auto* nested = &message1_on_arena->optional_nested_message();
protobuf_unittest::TestAllTypes message2;
// Moving from a message on the arena should lead to a copy.
message2 = std::move(*message1_on_arena);
EXPECT_NE(nested, &message2.optional_nested_message());
TestUtil::ExpectAllFieldsSet(*message1_on_arena);
TestUtil::ExpectAllFieldsSet(message2);
}
TEST(MovableMessageTest, MoveToArena) {
Arena arena;
protobuf_unittest::TestAllTypes message1;
TestUtil::SetAllFields(&message1);
const auto* nested = &message1.optional_nested_message();
auto* message2_on_arena =
Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena);
// Moving to a message on the arena should lead to a copy.
*message2_on_arena = std::move(message1);
EXPECT_NE(nested, &message2_on_arena->optional_nested_message());
TestUtil::ExpectAllFieldsSet(message1);
TestUtil::ExpectAllFieldsSet(*message2_on_arena);
}
TEST(MovableMessageTest, Noexcept) {
EXPECT_TRUE(
std::is_nothrow_move_constructible<protobuf_unittest::TestAllTypes>());
EXPECT_TRUE(std::is_nothrow_move_assignable<protobuf_unittest::TestAllTypes>());
}
#endif // LANG_CXX11
} // namespace cpp_unittest
} // namespace cpp
} // namespace compiler
} // namespace protobuf
} // namespace google

View File

@ -0,0 +1,83 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: rennie@google.com (Jeffrey Rennie)
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_OPTIONS_H__
#define GOOGLE_PROTOBUF_COMPILER_CPP_OPTIONS_H__
#include <string>
#include <google/protobuf/stubs/common.h>
namespace google {
namespace protobuf {
namespace compiler {
class AccessInfoMap;
namespace cpp {
// Generator options (see generator.cc for a description of each):
struct Options {
Options()
: safe_boundary_check(false),
proto_h(false),
transitive_pb_h(true),
annotate_headers(false),
enforce_lite(false),
table_driven_parsing(false),
table_driven_serialization(false),
lite_implicit_weak_fields(false),
bootstrap(false),
num_cc_files(0),
access_info_map(NULL) {}
string dllexport_decl;
bool safe_boundary_check;
bool proto_h;
bool transitive_pb_h;
bool annotate_headers;
bool enforce_lite;
bool table_driven_parsing;
bool table_driven_serialization;
bool lite_implicit_weak_fields;
bool bootstrap;
int num_cc_files;
string annotation_pragma_name;
string annotation_guard_name;
const AccessInfoMap* access_info_map;
};
} // namespace cpp
} // namespace compiler
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_OPTIONS_H__

View File

@ -0,0 +1,220 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <google/protobuf/compiler/cpp/cpp_padding_optimizer.h>
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {
namespace {
// FieldGroup is just a helper for PaddingOptimizer below. It holds a vector of
// fields that are grouped together because they have compatible alignment, and
// a preferred location in the final field ordering.
class FieldGroup {
public:
FieldGroup() : preferred_location_(0) {}
// A group with a single field.
FieldGroup(float preferred_location, const FieldDescriptor* field)
: preferred_location_(preferred_location), fields_(1, field) {}
// Append the fields in 'other' to this group.
void Append(const FieldGroup& other) {
if (other.fields_.empty()) {
return;
}
// Preferred location is the average among all the fields, so we weight by
// the number of fields on each FieldGroup object.
preferred_location_ = (preferred_location_ * fields_.size() +
(other.preferred_location_ * other.fields_.size())) /
(fields_.size() + other.fields_.size());
fields_.insert(fields_.end(), other.fields_.begin(), other.fields_.end());
}
void SetPreferredLocation(float location) { preferred_location_ = location; }
const std::vector<const FieldDescriptor*>& fields() const { return fields_; }
// FieldGroup objects sort by their preferred location.
bool operator<(const FieldGroup& other) const {
return preferred_location_ < other.preferred_location_;
}
private:
// "preferred_location_" is an estimate of where this group should go in the
// final list of fields. We compute this by taking the average index of each
// field in this group in the original ordering of fields. This is very
// approximate, but should put this group close to where its member fields
// originally went.
float preferred_location_;
std::vector<const FieldDescriptor*> fields_;
// We rely on the default copy constructor and operator= so this type can be
// used in a vector.
};
} // namespace
// Reorder 'fields' so that if the fields are output into a c++ class in the new
// order, fields of similar family (see below) are together and within each
// family, alignment padding is minimized.
//
// We try to do this while keeping each field as close as possible to its field
// number order so that we don't reduce cache locality much for function that
// access each field in order. Originally, OptimizePadding used declaration
// order for its decisions, but generated code minus the serializer/parsers uses
// the output of OptimizePadding as well (stored in
// MessageGenerator::optimized_order_). Since the serializers use field number
// order, we use that as a tie-breaker.
//
// We classify each field into a particular "family" of fields, that we perform
// the same operation on in our generated functions.
//
// REPEATED is placed first, as the C++ compiler automatically initializes
// these fields in layout order.
//
// STRING is grouped next, as our Clear/SharedCtor/SharedDtor walks it and
// calls ArenaStringPtr::Destroy on each.
//
//
// MESSAGE is grouped next, as our Clear/SharedDtor code walks it and calls
// delete on each. We initialize these fields with a NULL pointer (see
// MessageFieldGenerator::GenerateConstructorCode), which allows them to be
// memset.
//
// ZERO_INITIALIZABLE is memset in Clear/SharedCtor
//
// OTHER these fields are initialized one-by-one.
void PaddingOptimizer::OptimizeLayout(
std::vector<const FieldDescriptor*>* fields, const Options& options) {
// The sorted numeric order of Family determines the declaration order in the
// memory layout.
enum Family {
REPEATED = 0,
STRING = 1,
MESSAGE = 3,
ZERO_INITIALIZABLE = 4,
OTHER = 5,
kMaxFamily
};
// First divide fields into those that align to 1 byte, 4 bytes or 8 bytes.
std::vector<FieldGroup> aligned_to_1[kMaxFamily];
std::vector<FieldGroup> aligned_to_4[kMaxFamily];
std::vector<FieldGroup> aligned_to_8[kMaxFamily];
for (int i = 0; i < fields->size(); ++i) {
const FieldDescriptor* field = (*fields)[i];
Family f = OTHER;
if (field->is_repeated()) {
f = REPEATED;
} else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
f = STRING;
} else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
f = MESSAGE;
} else if (CanInitializeByZeroing(field)) {
f = ZERO_INITIALIZABLE;
}
const int j = field->number();
switch (EstimateAlignmentSize(field)) {
case 1:
aligned_to_1[f].push_back(FieldGroup(j, field));
break;
case 4:
aligned_to_4[f].push_back(FieldGroup(j, field));
break;
case 8:
aligned_to_8[f].push_back(FieldGroup(j, field));
break;
default:
GOOGLE_LOG(FATAL) << "Unknown alignment size " << EstimateAlignmentSize(field)
<< "for a field " << field->full_name() << ".";
}
}
// For each family, group fields to optimize padding.
for (int f = 0; f < kMaxFamily; f++) {
// Now group fields aligned to 1 byte into sets of 4, and treat those like a
// single field aligned to 4 bytes.
for (int i = 0; i < aligned_to_1[f].size(); i += 4) {
FieldGroup field_group;
for (int j = i; j < aligned_to_1[f].size() && j < i + 4; ++j) {
field_group.Append(aligned_to_1[f][j]);
}
aligned_to_4[f].push_back(field_group);
}
// Sort by preferred location to keep fields as close to their field number
// order as possible. Using stable_sort ensures that the output is
// consistent across runs.
std::stable_sort(aligned_to_4[f].begin(), aligned_to_4[f].end());
// Now group fields aligned to 4 bytes (or the 4-field groups created above)
// into pairs, and treat those like a single field aligned to 8 bytes.
for (int i = 0; i < aligned_to_4[f].size(); i += 2) {
FieldGroup field_group;
for (int j = i; j < aligned_to_4[f].size() && j < i + 2; ++j) {
field_group.Append(aligned_to_4[f][j]);
}
if (i == aligned_to_4[f].size() - 1) {
if (f == OTHER) {
// Move incomplete 4-byte block to the beginning. This is done to
// pair with the (possible) leftover blocks from the
// ZERO_INITIALIZABLE family.
field_group.SetPreferredLocation(-1);
} else {
// Move incomplete 4-byte block to the end.
field_group.SetPreferredLocation(fields->size() + 1);
}
}
aligned_to_8[f].push_back(field_group);
}
// Sort by preferred location.
std::stable_sort(aligned_to_8[f].begin(), aligned_to_8[f].end());
}
// Now pull out all the FieldDescriptors in order.
fields->clear();
for (int f = 0; f < kMaxFamily; ++f) {
for (int i = 0; i < aligned_to_8[f].size(); ++i) {
fields->insert(fields->end(), aligned_to_8[f][i].fields().begin(),
aligned_to_8[f][i].fields().end());
}
}
}
} // namespace cpp
} // namespace compiler
} // namespace protobuf
} // namespace google

View File

@ -0,0 +1,64 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: seongkim@google.com (Seong Beom Kim)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_PADDING_OPTIMIZER_H__
#define GOOGLE_PROTOBUF_COMPILER_CPP_PADDING_OPTIMIZER_H__
#include <google/protobuf/compiler/cpp/cpp_message_layout_helper.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {
// Rearranges the fields of a message to minimize padding.
// Fields are grouped by the type and the size.
// For example, grouping four boolean fields and one int32
// field results in zero padding overhead. See OptimizeLayout's
// comment for details.
class PaddingOptimizer : public MessageLayoutHelper {
public:
PaddingOptimizer() {}
~PaddingOptimizer() override {}
void OptimizeLayout(std::vector<const FieldDescriptor*>* fields,
const Options& options) override;
};
} // namespace cpp
} // namespace compiler
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_PADDING_OPTIMIZER_H__

View File

@ -0,0 +1,249 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda)
//
// TODO(kenton): Share code with the versions of this test in other languages?
// It seemed like parameterizing it would add more complexity than it is
// worth.
#include <memory>
#include <google/protobuf/compiler/cpp/cpp_generator.h>
#include <google/protobuf/compiler/command_line_interface.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/testing/file.h>
#include <google/protobuf/testing/file.h>
#include <google/protobuf/testing/googletest.h>
#include <gtest/gtest.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {
namespace {
class TestGenerator : public CodeGenerator {
public:
TestGenerator() {}
~TestGenerator() {}
virtual bool Generate(const FileDescriptor* file,
const string& parameter,
GeneratorContext* context,
string* error) const {
TryInsert("test.pb.h", "includes", context);
TryInsert("test.pb.h", "namespace_scope", context);
TryInsert("test.pb.h", "global_scope", context);
TryInsert("test.pb.h", "class_scope:foo.Bar", context);
TryInsert("test.pb.h", "class_scope:foo.Bar.Baz", context);
TryInsert("test.pb.cc", "includes", context);
TryInsert("test.pb.cc", "namespace_scope", context);
TryInsert("test.pb.cc", "global_scope", context);
// Check field accessors for an optional int32:
TryInsert("test.pb.h", "field_get:foo.Bar.optInt", context);
TryInsert("test.pb.h", "field_set:foo.Bar.optInt", context);
// Check field accessors for a repeated int32:
TryInsert("test.pb.h", "field_get:foo.Bar.repeatedInt", context);
TryInsert("test.pb.h", "field_set:foo.Bar.repeatedInt", context);
// Check field accessors for a required string:
TryInsert("test.pb.h", "field_get:foo.Bar.requiredString", context);
TryInsert("test.pb.h", "field_set:foo.Bar.requiredString", context);
TryInsert("test.pb.h", "field_set_char:foo.Bar.requiredString", context);
TryInsert("test.pb.h", "field_set_pointer:foo.Bar.requiredString", context);
TryInsert("test.pb.h", "field_mutable:foo.Bar.requiredString", context);
TryInsert("test.pb.h", "field_set_allocated:foo.Bar.requiredString",
context);
TryInsert("test.pb.h", "field_set_char:foo.Bar.requiredString", context);
TryInsert("test.pb.h", "field_set_pointer:foo.Bar.requiredString", context);
// Check field accessors for a repeated string:
TryInsert("test.pb.h", "field_get:foo.Bar.repeatedString", context);
TryInsert("test.pb.h", "field_set:foo.Bar.repeatedString", context);
TryInsert("test.pb.h", "field_set_char:foo.Bar.repeatedString", context);
TryInsert("test.pb.h", "field_set_pointer:foo.Bar.repeatedString", context);
TryInsert("test.pb.h", "field_mutable:foo.Bar.repeatedString", context);
TryInsert("test.pb.h", "field_set_char:foo.Bar.repeatedString", context);
TryInsert("test.pb.h", "field_set_pointer:foo.Bar.repeatedString", context);
// Check field accessors for an int inside oneof{}:
TryInsert("test.pb.h", "field_get:foo.Bar.oneOfInt", context);
TryInsert("test.pb.h", "field_set:foo.Bar.oneOfInt", context);
// Check field accessors for a string inside oneof{}:
TryInsert("test.pb.h", "field_get:foo.Bar.oneOfString", context);
TryInsert("test.pb.h", "field_set:foo.Bar.oneOfString", context);
TryInsert("test.pb.h", "field_set_char:foo.Bar.oneOfString", context);
TryInsert("test.pb.h", "field_set_pointer:foo.Bar.oneOfString", context);
TryInsert("test.pb.h", "field_mutable:foo.Bar.oneOfString", context);
TryInsert("test.pb.h", "field_set_allocated:foo.Bar.oneOfString", context);
TryInsert("test.pb.h", "field_set_char:foo.Bar.oneOfString", context);
TryInsert("test.pb.h", "field_set_pointer:foo.Bar.oneOfString", context);
// Check field accessors for an optional message:
TryInsert("test.pb.h", "field_get:foo.Bar.optMessage", context);
TryInsert("test.pb.h", "field_mutable:foo.Bar.optMessage", context);
TryInsert("test.pb.h", "field_set_allocated:foo.Bar.optMessage", context);
// Check field accessors for a repeated message:
TryInsert("test.pb.h", "field_add:foo.Bar.repeatedMessage", context);
TryInsert("test.pb.h", "field_get:foo.Bar.repeatedMessage", context);
TryInsert("test.pb.h", "field_list:foo.Bar.repeatedMessage", context);
TryInsert("test.pb.h", "field_mutable:foo.Bar.repeatedMessage", context);
TryInsert("test.pb.h", "field_mutable_list:foo.Bar.repeatedMessage",
context);
// Check field accessors for a message inside oneof{}:
TryInsert("test.pb.h", "field_get:foo.Bar.oneOfMessage", context);
TryInsert("test.pb.h", "field_mutable:foo.Bar.oneOfMessage", context);
TryInsert("test.pb.cc", "field_set_allocated:foo.Bar.oneOfMessage", context);
// Check field accessors for an optional enum:
TryInsert("test.pb.h", "field_get:foo.Bar.optEnum", context);
TryInsert("test.pb.h", "field_set:foo.Bar.optEnum", context);
// Check field accessors for a repeated enum:
TryInsert("test.pb.h", "field_get:foo.Bar.repeatedEnum", context);
TryInsert("test.pb.h", "field_set:foo.Bar.repeatedEnum", context);
TryInsert("test.pb.h", "field_add:foo.Bar.repeatedEnum", context);
TryInsert("test.pb.h", "field_list:foo.Bar.repeatedEnum", context);
TryInsert("test.pb.h", "field_mutable_list:foo.Bar.repeatedEnum", context);
// Check field accessors for an enum inside oneof{}:
TryInsert("test.pb.h", "field_get:foo.Bar.oneOfEnum", context);
TryInsert("test.pb.h", "field_set:foo.Bar.oneOfEnum", context);
// Check field accessors for a required cord:
TryInsert("test.pb.h", "field_get:foo.Bar.requiredCord", context);
TryInsert("test.pb.h", "field_set:foo.Bar.requiredCord", context);
TryInsert("test.pb.h", "field_mutable:foo.Bar.requiredCord", context);
// Check field accessors for a repeated cord:
TryInsert("test.pb.h", "field_get:foo.Bar.repeatedCord", context);
TryInsert("test.pb.h", "field_set:foo.Bar.repeatedCord", context);
TryInsert("test.pb.h", "field_add:foo.Bar.repeatedCord", context);
TryInsert("test.pb.h", "field_list:foo.Bar.repeatedCord", context);
TryInsert("test.pb.h", "field_mutable:foo.Bar.repeatedCord", context);
TryInsert("test.pb.h", "field_mutable_list:foo.Bar.repeatedCord", context);
// Check field accessors for a cord inside oneof{}:
TryInsert("test.pb.h", "field_get:foo.Bar.oneOfCord", context);
TryInsert("test.pb.h", "field_set:foo.Bar.oneOfCord", context);
TryInsert("test.pb.h", "field_mutable:foo.Bar.oneOfCord", context);
return true;
}
void TryInsert(const string& filename, const string& insertion_point,
GeneratorContext* context) const {
std::unique_ptr<io::ZeroCopyOutputStream> output(
context->OpenForInsert(filename, insertion_point));
io::Printer printer(output.get(), '$');
printer.Print("// inserted $name$\n", "name", insertion_point);
}
};
// This test verifies that all the expected insertion points exist. It does
// not verify that they are correctly-placed; that would require actually
// compiling the output which is a bit more than I care to do for this test.
TEST(CppPluginTest, PluginTest) {
GOOGLE_CHECK_OK(File::SetContents(TestTempDir() + "/test.proto",
"syntax = \"proto2\";\n"
"package foo;\n"
"\n"
"enum Thud { VALUE = 0; }\n"
"\n"
"message Bar {\n"
" message Baz {}\n"
" optional int32 optInt = 1;\n"
" repeated int32 repeatedInt = 2;\n"
"\n"
" required string requiredString = 3;\n"
" repeated string repeatedString = 4;\n"
"\n"
" optional Baz optMessage = 6;\n"
" repeated Baz repeatedMessage = 7;\n"
"\n"
" optional Thud optEnum = 8;\n"
" repeated Thud repeatedEnum = 9;\n"
"\n"
" required string requiredCord = 10 [\n"
" ctype = CORD\n"
" ];\n"
" repeated string repeatedCord = 11 [\n"
" ctype = CORD\n"
" ];\n"
"\n"
" oneof Qux {\n"
" int64 oneOfInt = 20;\n"
" string oneOfString = 21;\n"
" Baz oneOfMessage = 22;\n"
" Thud oneOfEnum = 23;"
" string oneOfCord = 24 [\n"
" ctype = CORD\n"
" ];\n"
" }\n"
"}\n",
true));
google::protobuf::compiler::CommandLineInterface cli;
cli.SetInputsAreProtoPathRelative(true);
CppGenerator cpp_generator;
TestGenerator test_generator;
cli.RegisterGenerator("--cpp_out", &cpp_generator, "");
cli.RegisterGenerator("--test_out", &test_generator, "");
string proto_path = "-I" + TestTempDir();
string cpp_out = "--cpp_out=" + TestTempDir();
string test_out = "--test_out=" + TestTempDir();
const char* argv[] = {
"protoc",
proto_path.c_str(),
cpp_out.c_str(),
test_out.c_str(),
"test.proto"
};
EXPECT_EQ(0, cli.Run(5, argv));
}
} // namespace
} // namespace cpp
} // namespace compiler
} // namespace protobuf
} // namespace google

View File

@ -0,0 +1,481 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
#include <google/protobuf/compiler/cpp/cpp_primitive_field.h>
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/wire_format.h>
#include <google/protobuf/stubs/strutil.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {
using internal::WireFormatLite;
namespace {
// For encodings with fixed sizes, returns that size in bytes. Otherwise
// returns -1.
int FixedSize(FieldDescriptor::Type type) {
switch (type) {
case FieldDescriptor::TYPE_INT32 : return -1;
case FieldDescriptor::TYPE_INT64 : return -1;
case FieldDescriptor::TYPE_UINT32 : return -1;
case FieldDescriptor::TYPE_UINT64 : return -1;
case FieldDescriptor::TYPE_SINT32 : return -1;
case FieldDescriptor::TYPE_SINT64 : return -1;
case FieldDescriptor::TYPE_FIXED32 : return WireFormatLite::kFixed32Size;
case FieldDescriptor::TYPE_FIXED64 : return WireFormatLite::kFixed64Size;
case FieldDescriptor::TYPE_SFIXED32: return WireFormatLite::kSFixed32Size;
case FieldDescriptor::TYPE_SFIXED64: return WireFormatLite::kSFixed64Size;
case FieldDescriptor::TYPE_FLOAT : return WireFormatLite::kFloatSize;
case FieldDescriptor::TYPE_DOUBLE : return WireFormatLite::kDoubleSize;
case FieldDescriptor::TYPE_BOOL : return WireFormatLite::kBoolSize;
case FieldDescriptor::TYPE_ENUM : return -1;
case FieldDescriptor::TYPE_STRING : return -1;
case FieldDescriptor::TYPE_BYTES : return -1;
case FieldDescriptor::TYPE_GROUP : return -1;
case FieldDescriptor::TYPE_MESSAGE : return -1;
// No default because we want the compiler to complain if any new
// types are added.
}
GOOGLE_LOG(FATAL) << "Can't get here.";
return -1;
}
void SetPrimitiveVariables(const FieldDescriptor* descriptor,
std::map<string, string>* variables,
const Options& options) {
SetCommonFieldVariables(descriptor, variables, options);
(*variables)["type"] = PrimitiveTypeName(descriptor->cpp_type());
(*variables)["default"] = DefaultValue(descriptor);
(*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
int fixed_size = FixedSize(descriptor->type());
if (fixed_size != -1) {
(*variables)["fixed_size"] = SimpleItoa(fixed_size);
}
(*variables)["wire_format_field_type"] =
"::google::protobuf::internal::WireFormatLite::" + FieldDescriptorProto_Type_Name(
static_cast<FieldDescriptorProto_Type>(descriptor->type()));
(*variables)["full_name"] = descriptor->full_name();
}
} // namespace
// ===================================================================
PrimitiveFieldGenerator::PrimitiveFieldGenerator(
const FieldDescriptor* descriptor, const Options& options)
: FieldGenerator(options), descriptor_(descriptor) {
SetPrimitiveVariables(descriptor, &variables_, options);
}
PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {}
void PrimitiveFieldGenerator::
GeneratePrivateMembers(io::Printer* printer) const {
printer->Print(variables_, "$type$ $name$_;\n");
}
void PrimitiveFieldGenerator::
GenerateAccessorDeclarations(io::Printer* printer) const {
printer->Print(variables_, "$deprecated_attr$$type$ $name$() const;\n");
printer->Annotate("name", descriptor_);
printer->Print(variables_,
"$deprecated_attr$void ${$set_$name$$}$($type$ value);\n");
printer->Annotate("{", "}", descriptor_);
}
void PrimitiveFieldGenerator::
GenerateInlineAccessorDefinitions(io::Printer* printer) const {
printer->Print(variables_,
"inline $type$ $classname$::$name$() const {\n"
" // @@protoc_insertion_point(field_get:$full_name$)\n"
" return $name$_;\n"
"}\n"
"inline void $classname$::set_$name$($type$ value) {\n"
" $set_hasbit$\n"
" $name$_ = value;\n"
" // @@protoc_insertion_point(field_set:$full_name$)\n"
"}\n");
}
void PrimitiveFieldGenerator::
GenerateClearingCode(io::Printer* printer) const {
printer->Print(variables_, "$name$_ = $default$;\n");
}
void PrimitiveFieldGenerator::
GenerateMergingCode(io::Printer* printer) const {
printer->Print(variables_, "set_$name$(from.$name$());\n");
}
void PrimitiveFieldGenerator::
GenerateSwappingCode(io::Printer* printer) const {
printer->Print(variables_, "swap($name$_, other->$name$_);\n");
}
void PrimitiveFieldGenerator::
GenerateConstructorCode(io::Printer* printer) const {
printer->Print(variables_, "$name$_ = $default$;\n");
}
void PrimitiveFieldGenerator::
GenerateCopyConstructorCode(io::Printer* printer) const {
printer->Print(variables_, "$name$_ = from.$name$_;\n");
}
void PrimitiveFieldGenerator::
GenerateMergeFromCodedStream(io::Printer* printer) const {
printer->Print(variables_,
"$set_hasbit$\n"
"DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n"
" $type$, $wire_format_field_type$>(\n"
" input, &$name$_)));\n");
}
void PrimitiveFieldGenerator::
GenerateSerializeWithCachedSizes(io::Printer* printer) const {
printer->Print(variables_,
"::google::protobuf::internal::WireFormatLite::Write$declared_type$("
"$number$, this->$name$(), output);\n");
}
void PrimitiveFieldGenerator::
GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
printer->Print(variables_,
"target = ::google::protobuf::internal::WireFormatLite::Write$declared_type$ToArray("
"$number$, this->$name$(), target);\n");
}
void PrimitiveFieldGenerator::
GenerateByteSize(io::Printer* printer) const {
int fixed_size = FixedSize(descriptor_->type());
if (fixed_size == -1) {
printer->Print(variables_,
"total_size += $tag_size$ +\n"
" ::google::protobuf::internal::WireFormatLite::$declared_type$Size(\n"
" this->$name$());\n");
} else {
printer->Print(variables_,
"total_size += $tag_size$ + $fixed_size$;\n");
}
}
// ===================================================================
PrimitiveOneofFieldGenerator::
PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor,
const Options& options)
: PrimitiveFieldGenerator(descriptor, options) {
SetCommonOneofFieldVariables(descriptor, &variables_);
}
PrimitiveOneofFieldGenerator::~PrimitiveOneofFieldGenerator() {}
void PrimitiveOneofFieldGenerator::
GenerateInlineAccessorDefinitions(io::Printer* printer) const {
printer->Print(variables_,
"inline $type$ $classname$::$name$() const {\n"
" // @@protoc_insertion_point(field_get:$full_name$)\n"
" if (has_$name$()) {\n"
" return $field_member$;\n"
" }\n"
" return $default$;\n"
"}\n"
"inline void $classname$::set_$name$($type$ value) {\n"
" if (!has_$name$()) {\n"
" clear_$oneof_name$();\n"
" set_has_$name$();\n"
" }\n"
" $field_member$ = value;\n"
" // @@protoc_insertion_point(field_set:$full_name$)\n"
"}\n");
}
void PrimitiveOneofFieldGenerator::
GenerateClearingCode(io::Printer* printer) const {
printer->Print(variables_, "$field_member$ = $default$;\n");
}
void PrimitiveOneofFieldGenerator::
GenerateSwappingCode(io::Printer* printer) const {
// Don't print any swapping code. Swapping the union will swap this field.
}
void PrimitiveOneofFieldGenerator::
GenerateConstructorCode(io::Printer* printer) const {
printer->Print(variables_,
"$ns$::_$classname$_default_instance_.$name$_ = $default$;\n");
}
void PrimitiveOneofFieldGenerator::
GenerateMergeFromCodedStream(io::Printer* printer) const {
printer->Print(variables_,
"clear_$oneof_name$();\n"
"DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n"
" $type$, $wire_format_field_type$>(\n"
" input, &$field_member$)));\n"
"set_has_$name$();\n");
}
// ===================================================================
RepeatedPrimitiveFieldGenerator::RepeatedPrimitiveFieldGenerator(
const FieldDescriptor* descriptor, const Options& options)
: FieldGenerator(options), descriptor_(descriptor) {
SetPrimitiveVariables(descriptor, &variables_, options);
if (descriptor->is_packed()) {
variables_["packed_reader"] = "ReadPackedPrimitive";
variables_["repeated_reader"] = "ReadRepeatedPrimitiveNoInline";
} else {
variables_["packed_reader"] = "ReadPackedPrimitiveNoInline";
variables_["repeated_reader"] = "ReadRepeatedPrimitive";
}
}
RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {}
void RepeatedPrimitiveFieldGenerator::
GeneratePrivateMembers(io::Printer* printer) const {
printer->Print(variables_,
"::google::protobuf::RepeatedField< $type$ > $name$_;\n");
if (descriptor_->is_packed() &&
HasGeneratedMethods(descriptor_->file(), options_)) {
printer->Print(variables_,
"mutable int _$name$_cached_byte_size_;\n");
}
}
void RepeatedPrimitiveFieldGenerator::
GenerateAccessorDeclarations(io::Printer* printer) const {
printer->Print(variables_,
"$deprecated_attr$$type$ $name$(int index) const;\n");
printer->Annotate("name", descriptor_);
printer->Print(
variables_,
"$deprecated_attr$void ${$set_$name$$}$(int index, $type$ value);\n");
printer->Annotate("{", "}", descriptor_);
printer->Print(variables_,
"$deprecated_attr$void ${$add_$name$$}$($type$ value);\n");
printer->Annotate("{", "}", descriptor_);
printer->Print(variables_,
"$deprecated_attr$const ::google::protobuf::RepeatedField< $type$ >&\n"
" $name$() const;\n");
printer->Annotate("name", descriptor_);
printer->Print(variables_,
"$deprecated_attr$::google::protobuf::RepeatedField< $type$ >*\n"
" ${$mutable_$name$$}$();\n");
printer->Annotate("{", "}", descriptor_);
}
void RepeatedPrimitiveFieldGenerator::
GenerateInlineAccessorDefinitions(io::Printer* printer) const {
printer->Print(variables_,
"inline $type$ $classname$::$name$(int index) const {\n"
" // @@protoc_insertion_point(field_get:$full_name$)\n"
" return $name$_.Get(index);\n"
"}\n"
"inline void $classname$::set_$name$(int index, $type$ value) {\n"
" $name$_.Set(index, value);\n"
" // @@protoc_insertion_point(field_set:$full_name$)\n"
"}\n"
"inline void $classname$::add_$name$($type$ value) {\n"
" $name$_.Add(value);\n"
" // @@protoc_insertion_point(field_add:$full_name$)\n"
"}\n"
"inline const ::google::protobuf::RepeatedField< $type$ >&\n"
"$classname$::$name$() const {\n"
" // @@protoc_insertion_point(field_list:$full_name$)\n"
" return $name$_;\n"
"}\n"
"inline ::google::protobuf::RepeatedField< $type$ >*\n"
"$classname$::mutable_$name$() {\n"
" // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
" return &$name$_;\n"
"}\n");
}
void RepeatedPrimitiveFieldGenerator::
GenerateClearingCode(io::Printer* printer) const {
printer->Print(variables_, "$name$_.Clear();\n");
}
void RepeatedPrimitiveFieldGenerator::
GenerateMergingCode(io::Printer* printer) const {
printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n");
}
void RepeatedPrimitiveFieldGenerator::
GenerateSwappingCode(io::Printer* printer) const {
printer->Print(variables_, "$name$_.InternalSwap(&other->$name$_);\n");
}
void RepeatedPrimitiveFieldGenerator::
GenerateConstructorCode(io::Printer* printer) const {
// Not needed for repeated fields.
}
void RepeatedPrimitiveFieldGenerator::
GenerateCopyConstructorCode(io::Printer* printer) const {
printer->Print(variables_, "$name$_.CopyFrom(from.$name$_);\n");
}
void RepeatedPrimitiveFieldGenerator::
GenerateMergeFromCodedStream(io::Printer* printer) const {
printer->Print(variables_,
"DO_((::google::protobuf::internal::WireFormatLite::$repeated_reader$<\n"
" $type$, $wire_format_field_type$>(\n"
" $tag_size$, $tag$u, input, this->mutable_$name$())));\n");
}
void RepeatedPrimitiveFieldGenerator::
GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const {
printer->Print(variables_,
"DO_((::google::protobuf::internal::WireFormatLite::$packed_reader$<\n"
" $type$, $wire_format_field_type$>(\n"
" input, this->mutable_$name$())));\n");
}
void RepeatedPrimitiveFieldGenerator::
GenerateSerializeWithCachedSizes(io::Printer* printer) const {
bool array_written = false;
if (descriptor_->is_packed()) {
// Write the tag and the size.
printer->Print(variables_,
"if (this->$name$_size() > 0) {\n"
" ::google::protobuf::internal::WireFormatLite::WriteTag("
"$number$, "
"::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, "
"output);\n"
" output->WriteVarint32(static_cast< ::google::protobuf::uint32>(\n"
" _$name$_cached_byte_size_));\n");
if (FixedSize(descriptor_->type()) > 0) {
// TODO(ckennelly): Use RepeatedField<T>::unsafe_data() via
// WireFormatLite to access the contents of this->$name$_ to save a branch
// here.
printer->Print(variables_,
" ::google::protobuf::internal::WireFormatLite::Write$declared_type$Array(\n"
" this->$name$().data(), this->$name$_size(), output);\n");
array_written = true; // Wrote array all at once
}
printer->Print(variables_, "}\n");
}
if (!array_written) {
printer->Print(variables_,
"for (int i = 0, n = this->$name$_size(); i < n; i++) {\n");
if (descriptor_->is_packed()) {
printer->Print(variables_,
" ::google::protobuf::internal::WireFormatLite::Write$declared_type$NoTag(\n"
" this->$name$(i), output);\n");
} else {
printer->Print(variables_,
" ::google::protobuf::internal::WireFormatLite::Write$declared_type$(\n"
" $number$, this->$name$(i), output);\n");
}
printer->Print("}\n");
}
}
void RepeatedPrimitiveFieldGenerator::
GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
if (descriptor_->is_packed()) {
// Write the tag and the size.
printer->Print(variables_,
"if (this->$name$_size() > 0) {\n"
" target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(\n"
" $number$,\n"
" ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n"
" target);\n"
" target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(\n"
" static_cast< ::google::protobuf::int32>(\n"
" _$name$_cached_byte_size_), target);\n"
" target = ::google::protobuf::internal::WireFormatLite::\n"
" Write$declared_type$NoTagToArray(this->$name$_, target);\n"
"}\n");
} else {
printer->Print(variables_,
"target = ::google::protobuf::internal::WireFormatLite::\n"
" Write$declared_type$ToArray($number$, this->$name$_, target);\n");
}
}
void RepeatedPrimitiveFieldGenerator::
GenerateByteSize(io::Printer* printer) const {
printer->Print(variables_, "{\n");
printer->Indent();
int fixed_size = FixedSize(descriptor_->type());
if (fixed_size == -1) {
printer->Print(variables_,
"size_t data_size = ::google::protobuf::internal::WireFormatLite::\n"
" $declared_type$Size(this->$name$_);\n");
} else {
printer->Print(variables_,
"unsigned int count = static_cast<unsigned int>(this->$name$_size());\n"
"size_t data_size = $fixed_size$UL * count;\n");
}
if (descriptor_->is_packed()) {
printer->Print(variables_,
"if (data_size > 0) {\n"
" total_size += $tag_size$ +\n"
" ::google::protobuf::internal::WireFormatLite::Int32Size(\n"
" static_cast< ::google::protobuf::int32>(data_size));\n"
"}\n"
"int cached_size = ::google::protobuf::internal::ToCachedSize(data_size);\n"
"GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n"
"_$name$_cached_byte_size_ = cached_size;\n"
"GOOGLE_SAFE_CONCURRENT_WRITES_END();\n"
"total_size += data_size;\n");
} else {
printer->Print(variables_,
"total_size += $tag_size$ *\n"
" ::google::protobuf::internal::FromIntSize(this->$name$_size());\n"
"total_size += data_size;\n");
}
printer->Outdent();
printer->Print("}\n");
}
} // namespace cpp
} // namespace compiler
} // namespace protobuf
} // namespace google

View File

@ -0,0 +1,125 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_PRIMITIVE_FIELD_H__
#define GOOGLE_PROTOBUF_COMPILER_CPP_PRIMITIVE_FIELD_H__
#include <map>
#include <string>
#include <google/protobuf/compiler/cpp/cpp_field.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {
class PrimitiveFieldGenerator : public FieldGenerator {
public:
PrimitiveFieldGenerator(const FieldDescriptor* descriptor,
const Options& options);
~PrimitiveFieldGenerator();
// implements FieldGenerator ---------------------------------------
void GeneratePrivateMembers(io::Printer* printer) const;
void GenerateAccessorDeclarations(io::Printer* printer) const;
void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
void GenerateClearingCode(io::Printer* printer) const;
void GenerateMergingCode(io::Printer* printer) const;
void GenerateSwappingCode(io::Printer* printer) const;
void GenerateConstructorCode(io::Printer* printer) const;
void GenerateCopyConstructorCode(io::Printer* printer) const;
void GenerateMergeFromCodedStream(io::Printer* printer) const;
void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
void GenerateByteSize(io::Printer* printer) const;
protected:
const FieldDescriptor* descriptor_;
std::map<string, string> variables_;
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveFieldGenerator);
};
class PrimitiveOneofFieldGenerator : public PrimitiveFieldGenerator {
public:
PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor,
const Options& options);
~PrimitiveOneofFieldGenerator();
// implements FieldGenerator ---------------------------------------
void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
void GenerateClearingCode(io::Printer* printer) const;
void GenerateSwappingCode(io::Printer* printer) const;
void GenerateConstructorCode(io::Printer* printer) const;
void GenerateMergeFromCodedStream(io::Printer* printer) const;
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveOneofFieldGenerator);
};
class RepeatedPrimitiveFieldGenerator : public FieldGenerator {
public:
RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor,
const Options& options);
~RepeatedPrimitiveFieldGenerator();
// implements FieldGenerator ---------------------------------------
void GeneratePrivateMembers(io::Printer* printer) const;
void GenerateAccessorDeclarations(io::Printer* printer) const;
void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
void GenerateClearingCode(io::Printer* printer) const;
void GenerateMergingCode(io::Printer* printer) const;
void GenerateSwappingCode(io::Printer* printer) const;
void GenerateConstructorCode(io::Printer* printer) const;
void GenerateCopyConstructorCode(io::Printer* printer) const;
void GenerateMergeFromCodedStream(io::Printer* printer) const;
void GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const;
void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
void GenerateByteSize(io::Printer* printer) const;
private:
const FieldDescriptor* descriptor_;
std::map<string, string> variables_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPrimitiveFieldGenerator);
};
} // namespace cpp
} // namespace compiler
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_PRIMITIVE_FIELD_H__

View File

@ -0,0 +1,340 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
#include <google/protobuf/compiler/cpp/cpp_service.h>
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/stubs/strutil.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {
ServiceGenerator::ServiceGenerator(const ServiceDescriptor* descriptor,
const Options& options)
: descriptor_(descriptor) {
vars_["classname"] = descriptor_->name();
vars_["file_namespace"] = FileLevelNamespace(descriptor_->file()->name());
vars_["full_name"] = descriptor_->full_name();
if (options.dllexport_decl.empty()) {
vars_["dllexport"] = "";
} else {
vars_["dllexport"] = options.dllexport_decl + " ";
}
}
ServiceGenerator::~ServiceGenerator() {}
void ServiceGenerator::GenerateDeclarations(io::Printer* printer) {
// Forward-declare the stub type.
printer->Print(vars_,
"class $classname$_Stub;\n"
"\n");
GenerateInterface(printer);
GenerateStubDefinition(printer);
}
void ServiceGenerator::GenerateInterface(io::Printer* printer) {
printer->Print(vars_,
"class $dllexport$$classname$ : public ::google::protobuf::Service {\n"
" protected:\n"
" // This class should be treated as an abstract interface.\n"
" inline $classname$() {};\n"
" public:\n"
" virtual ~$classname$();\n");
printer->Indent();
printer->Print(vars_,
"\n"
"typedef $classname$_Stub Stub;\n"
"\n"
"static const ::google::protobuf::ServiceDescriptor* descriptor();\n"
"\n");
GenerateMethodSignatures(VIRTUAL, printer);
printer->Print(
"\n"
"// implements Service ----------------------------------------------\n"
"\n"
"const ::google::protobuf::ServiceDescriptor* GetDescriptor();\n"
"void CallMethod(const ::google::protobuf::MethodDescriptor* method,\n"
" ::google::protobuf::RpcController* controller,\n"
" const ::google::protobuf::Message* request,\n"
" ::google::protobuf::Message* response,\n"
" ::google::protobuf::Closure* done);\n"
"const ::google::protobuf::Message& GetRequestPrototype(\n"
" const ::google::protobuf::MethodDescriptor* method) const;\n"
"const ::google::protobuf::Message& GetResponsePrototype(\n"
" const ::google::protobuf::MethodDescriptor* method) const;\n");
printer->Outdent();
printer->Print(vars_,
"\n"
" private:\n"
" GOOGLE_DISALLOW_EVIL_CONSTRUCTORS($classname$);\n"
"};\n"
"\n");
}
void ServiceGenerator::GenerateStubDefinition(io::Printer* printer) {
printer->Print(vars_,
"class $dllexport$$classname$_Stub : public $classname$ {\n"
" public:\n");
printer->Indent();
printer->Print(vars_,
"$classname$_Stub(::google::protobuf::RpcChannel* channel);\n"
"$classname$_Stub(::google::protobuf::RpcChannel* channel,\n"
" ::google::protobuf::Service::ChannelOwnership ownership);\n"
"~$classname$_Stub();\n"
"\n"
"inline ::google::protobuf::RpcChannel* channel() { return channel_; }\n"
"\n"
"// implements $classname$ ------------------------------------------\n"
"\n");
GenerateMethodSignatures(NON_VIRTUAL, printer);
printer->Outdent();
printer->Print(vars_,
" private:\n"
" ::google::protobuf::RpcChannel* channel_;\n"
" bool owns_channel_;\n"
" GOOGLE_DISALLOW_EVIL_CONSTRUCTORS($classname$_Stub);\n"
"};\n"
"\n");
}
void ServiceGenerator::GenerateMethodSignatures(
VirtualOrNon virtual_or_non, io::Printer* printer) {
for (int i = 0; i < descriptor_->method_count(); i++) {
const MethodDescriptor* method = descriptor_->method(i);
std::map<string, string> sub_vars;
sub_vars["name"] = method->name();
sub_vars["input_type"] = ClassName(method->input_type(), true);
sub_vars["output_type"] = ClassName(method->output_type(), true);
sub_vars["virtual"] = virtual_or_non == VIRTUAL ? "virtual " : "";
printer->Print(sub_vars,
"$virtual$void $name$(::google::protobuf::RpcController* controller,\n"
" const $input_type$* request,\n"
" $output_type$* response,\n"
" ::google::protobuf::Closure* done);\n");
}
}
// ===================================================================
void ServiceGenerator::GenerateDescriptorInitializer(
io::Printer* printer, int index) {
std::map<string, string> vars;
vars["classname"] = descriptor_->name();
vars["index"] = SimpleItoa(index);
printer->Print(vars,
"$classname$_descriptor_ = file->service($index$);\n");
}
// ===================================================================
void ServiceGenerator::GenerateImplementation(io::Printer* printer) {
vars_["index"] = SimpleItoa(index_in_metadata_);
printer->Print(
vars_,
"$classname$::~$classname$() {}\n"
"\n"
"const ::google::protobuf::ServiceDescriptor* $classname$::descriptor() {\n"
" $file_namespace$::protobuf_AssignDescriptorsOnce();\n"
" return $file_namespace$::file_level_service_descriptors[$index$];\n"
"}\n"
"\n"
"const ::google::protobuf::ServiceDescriptor* $classname$::GetDescriptor() {\n"
" return descriptor();\n"
"}\n"
"\n");
// Generate methods of the interface.
GenerateNotImplementedMethods(printer);
GenerateCallMethod(printer);
GenerateGetPrototype(REQUEST, printer);
GenerateGetPrototype(RESPONSE, printer);
// Generate stub implementation.
printer->Print(vars_,
"$classname$_Stub::$classname$_Stub(::google::protobuf::RpcChannel* channel)\n"
" : channel_(channel), owns_channel_(false) {}\n"
"$classname$_Stub::$classname$_Stub(\n"
" ::google::protobuf::RpcChannel* channel,\n"
" ::google::protobuf::Service::ChannelOwnership ownership)\n"
" : channel_(channel),\n"
" owns_channel_(ownership == ::google::protobuf::Service::STUB_OWNS_CHANNEL) {}\n"
"$classname$_Stub::~$classname$_Stub() {\n"
" if (owns_channel_) delete channel_;\n"
"}\n"
"\n");
GenerateStubMethods(printer);
}
void ServiceGenerator::GenerateNotImplementedMethods(io::Printer* printer) {
for (int i = 0; i < descriptor_->method_count(); i++) {
const MethodDescriptor* method = descriptor_->method(i);
std::map<string, string> sub_vars;
sub_vars["classname"] = descriptor_->name();
sub_vars["name"] = method->name();
sub_vars["index"] = SimpleItoa(i);
sub_vars["input_type"] = ClassName(method->input_type(), true);
sub_vars["output_type"] = ClassName(method->output_type(), true);
printer->Print(sub_vars,
"void $classname$::$name$(::google::protobuf::RpcController* controller,\n"
" const $input_type$*,\n"
" $output_type$*,\n"
" ::google::protobuf::Closure* done) {\n"
" controller->SetFailed(\"Method $name$() not implemented.\");\n"
" done->Run();\n"
"}\n"
"\n");
}
}
void ServiceGenerator::GenerateCallMethod(io::Printer* printer) {
printer->Print(
vars_,
"void $classname$::CallMethod(const ::google::protobuf::MethodDescriptor* method,\n"
" ::google::protobuf::RpcController* controller,\n"
" const ::google::protobuf::Message* request,\n"
" ::google::protobuf::Message* response,\n"
" ::google::protobuf::Closure* done) {\n"
" GOOGLE_DCHECK_EQ(method->service(), "
"$file_namespace$::file_level_service_descriptors[$index$]);\n"
" switch(method->index()) {\n");
for (int i = 0; i < descriptor_->method_count(); i++) {
const MethodDescriptor* method = descriptor_->method(i);
std::map<string, string> sub_vars;
sub_vars["name"] = method->name();
sub_vars["index"] = SimpleItoa(i);
sub_vars["input_type"] = ClassName(method->input_type(), true);
sub_vars["output_type"] = ClassName(method->output_type(), true);
// Note: down_cast does not work here because it only works on pointers,
// not references.
printer->Print(sub_vars,
" case $index$:\n"
" $name$(controller,\n"
" ::google::protobuf::down_cast<const $input_type$*>(request),\n"
" ::google::protobuf::down_cast< $output_type$*>(response),\n"
" done);\n"
" break;\n");
}
printer->Print(vars_,
" default:\n"
" GOOGLE_LOG(FATAL) << \"Bad method index; this should never happen.\";\n"
" break;\n"
" }\n"
"}\n"
"\n");
}
void ServiceGenerator::GenerateGetPrototype(RequestOrResponse which,
io::Printer* printer) {
if (which == REQUEST) {
printer->Print(vars_,
"const ::google::protobuf::Message& $classname$::GetRequestPrototype(\n");
} else {
printer->Print(vars_,
"const ::google::protobuf::Message& $classname$::GetResponsePrototype(\n");
}
printer->Print(vars_,
" const ::google::protobuf::MethodDescriptor* method) const {\n"
" GOOGLE_DCHECK_EQ(method->service(), descriptor());\n"
" switch(method->index()) {\n");
for (int i = 0; i < descriptor_->method_count(); i++) {
const MethodDescriptor* method = descriptor_->method(i);
const Descriptor* type =
(which == REQUEST) ? method->input_type() : method->output_type();
std::map<string, string> sub_vars;
sub_vars["index"] = SimpleItoa(i);
sub_vars["type"] = ClassName(type, true);
printer->Print(sub_vars,
" case $index$:\n"
" return $type$::default_instance();\n");
}
printer->Print(
" default:\n"
" GOOGLE_LOG(FATAL) << \"Bad method index; this should never happen.\";\n"
" return *::google::protobuf::MessageFactory::generated_factory()\n"
" ->GetPrototype(method->$input_or_output$_type());\n"
" }\n"
"}\n"
"\n",
"input_or_output", which == REQUEST ? "input" : "output");
}
void ServiceGenerator::GenerateStubMethods(io::Printer* printer) {
for (int i = 0; i < descriptor_->method_count(); i++) {
const MethodDescriptor* method = descriptor_->method(i);
std::map<string, string> sub_vars;
sub_vars["classname"] = descriptor_->name();
sub_vars["name"] = method->name();
sub_vars["index"] = SimpleItoa(i);
sub_vars["input_type"] = ClassName(method->input_type(), true);
sub_vars["output_type"] = ClassName(method->output_type(), true);
printer->Print(sub_vars,
"void $classname$_Stub::$name$(::google::protobuf::RpcController* controller,\n"
" const $input_type$* request,\n"
" $output_type$* response,\n"
" ::google::protobuf::Closure* done) {\n"
" channel_->CallMethod(descriptor()->method($index$),\n"
" controller, request, response, done);\n"
"}\n");
}
}
} // namespace cpp
} // namespace compiler
} // namespace protobuf
} // namespace google

View File

@ -0,0 +1,121 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_SERVICE_H__
#define GOOGLE_PROTOBUF_COMPILER_CPP_SERVICE_H__
#include <map>
#include <string>
#include <google/protobuf/compiler/cpp/cpp_options.h>
#include <google/protobuf/descriptor.h>
namespace google {
namespace protobuf {
namespace io {
class Printer; // printer.h
}
}
namespace protobuf {
namespace compiler {
namespace cpp {
class ServiceGenerator {
public:
// See generator.cc for the meaning of dllexport_decl.
explicit ServiceGenerator(const ServiceDescriptor* descriptor,
const Options& options);
~ServiceGenerator();
// Header stuff.
// Generate the class definitions for the service's interface and the
// stub implementation.
void GenerateDeclarations(io::Printer* printer);
// Source file stuff.
// Generate code that initializes the global variable storing the service's
// descriptor.
void GenerateDescriptorInitializer(io::Printer* printer, int index);
// Generate implementations of everything declared by GenerateDeclarations().
void GenerateImplementation(io::Printer* printer);
private:
enum RequestOrResponse { REQUEST, RESPONSE };
enum VirtualOrNon { VIRTUAL, NON_VIRTUAL };
// Header stuff.
// Generate the service abstract interface.
void GenerateInterface(io::Printer* printer);
// Generate the stub class definition.
void GenerateStubDefinition(io::Printer* printer);
// Prints signatures for all methods in the
void GenerateMethodSignatures(VirtualOrNon virtual_or_non,
io::Printer* printer);
// Source file stuff.
// Generate the default implementations of the service methods, which
// produce a "not implemented" error.
void GenerateNotImplementedMethods(io::Printer* printer);
// Generate the CallMethod() method of the service.
void GenerateCallMethod(io::Printer* printer);
// Generate the Get{Request,Response}Prototype() methods.
void GenerateGetPrototype(RequestOrResponse which, io::Printer* printer);
// Generate the stub's implementations of the service methods.
void GenerateStubMethods(io::Printer* printer);
const ServiceDescriptor* descriptor_;
std::map<string, string> vars_;
int index_in_metadata_;
friend class FileGenerator;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ServiceGenerator);
};
} // namespace cpp
} // namespace compiler
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_SERVICE_H__

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,141 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_STRING_FIELD_H__
#define GOOGLE_PROTOBUF_COMPILER_CPP_STRING_FIELD_H__
#include <map>
#include <string>
#include <google/protobuf/compiler/cpp/cpp_field.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {
class StringFieldGenerator : public FieldGenerator {
public:
StringFieldGenerator(const FieldDescriptor* descriptor,
const Options& options);
~StringFieldGenerator();
// implements FieldGenerator ---------------------------------------
void GeneratePrivateMembers(io::Printer* printer) const;
void GenerateStaticMembers(io::Printer* printer) const;
void GenerateAccessorDeclarations(io::Printer* printer) const;
void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const;
void GenerateClearingCode(io::Printer* printer) const;
void GenerateMessageClearingCode(io::Printer* printer) const;
void GenerateMergingCode(io::Printer* printer) const;
void GenerateSwappingCode(io::Printer* printer) const;
void GenerateConstructorCode(io::Printer* printer) const;
void GenerateCopyConstructorCode(io::Printer* printer) const;
void GenerateDestructorCode(io::Printer* printer) const;
bool GenerateArenaDestructorCode(io::Printer* printer) const;
void GenerateDefaultInstanceAllocator(io::Printer* printer) const;
void GenerateMergeFromCodedStream(io::Printer* printer) const;
void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
void GenerateByteSize(io::Printer* printer) const;
uint32 CalculateFieldTag() const;
bool IsInlined() const { return inlined_; }
bool MergeFromCodedStreamNeedsArena() const;
protected:
const FieldDescriptor* descriptor_;
std::map<string, string> variables_;
const bool lite_;
bool inlined_;
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringFieldGenerator);
};
class StringOneofFieldGenerator : public StringFieldGenerator {
public:
StringOneofFieldGenerator(const FieldDescriptor* descriptor,
const Options& options);
~StringOneofFieldGenerator();
// implements FieldGenerator ---------------------------------------
void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
void GenerateClearingCode(io::Printer* printer) const;
// StringFieldGenerator, from which we inherit, overrides this so we need to
// override it as well.
void GenerateMessageClearingCode(io::Printer* printer) const;
void GenerateSwappingCode(io::Printer* printer) const;
void GenerateConstructorCode(io::Printer* printer) const;
void GenerateDestructorCode(io::Printer* printer) const;
void GenerateMergeFromCodedStream(io::Printer* printer) const;
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringOneofFieldGenerator);
};
class RepeatedStringFieldGenerator : public FieldGenerator {
public:
RepeatedStringFieldGenerator(const FieldDescriptor* descriptor,
const Options& options);
~RepeatedStringFieldGenerator();
// implements FieldGenerator ---------------------------------------
void GeneratePrivateMembers(io::Printer* printer) const;
void GenerateAccessorDeclarations(io::Printer* printer) const;
void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
void GenerateClearingCode(io::Printer* printer) const;
void GenerateMergingCode(io::Printer* printer) const;
void GenerateSwappingCode(io::Printer* printer) const;
void GenerateConstructorCode(io::Printer* printer) const;
void GenerateCopyConstructorCode(io::Printer* printer) const;
void GenerateMergeFromCodedStream(io::Printer* printer) const;
void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
void GenerateByteSize(io::Printer* printer) const;
private:
const FieldDescriptor* descriptor_;
std::map<string, string> variables_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedStringFieldGenerator);
};
} // namespace cpp
} // namespace compiler
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_STRING_FIELD_H__

View File

@ -0,0 +1,160 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
//
// This file tests that various identifiers work as field and type names even
// though the same identifiers are used internally by the C++ code generator.
syntax = "proto2";
// Some generic_services option(s) added automatically.
// See: http://go/proto2-generic-services-default
option cc_generic_services = true; // auto-added
// We don't put this in a package within proto2 because we need to make sure
// that the generated code doesn't depend on being in the proto2 namespace.
package protobuf_unittest;
// Test that fields can have names like "input" and "i" which are also used
// internally by the code generator for local variables.
message TestConflictingSymbolNames {
message BuildDescriptors {}
message TypeTraits {}
optional int32 input = 1;
optional int32 output = 2;
optional string length = 3;
repeated int32 i = 4;
repeated string new_element = 5 [ctype=STRING_PIECE];
optional int32 total_size = 6;
optional int32 tag = 7;
enum TestEnum { FOO = 0; }
message Data1 { repeated int32 data = 1; }
message Data2 { repeated TestEnum data = 1; }
message Data3 { repeated string data = 1; }
message Data4 { repeated Data4 data = 1; }
message Data5 { repeated string data = 1 [ctype=STRING_PIECE]; }
message Data6 { repeated string data = 1 [ctype=CORD]; }
optional int32 source = 8;
optional int32 value = 9;
optional int32 file = 10;
optional int32 from = 11;
optional int32 handle_uninterpreted = 12;
repeated int32 index = 13;
optional int32 controller = 14;
optional int32 already_here = 15;
optional uint32 uint32 = 16;
optional uint64 uint64 = 17;
optional string string = 18;
optional int32 memset = 19;
optional int32 int32 = 20;
optional int64 int64 = 21;
optional uint32 cached_size = 22;
optional uint32 extensions = 23;
optional uint32 bit = 24;
optional uint32 bits = 25;
optional uint32 offsets = 26;
optional uint32 reflection = 27;
message Cord {}
optional string some_cord = 28 [ctype=CORD];
message StringPiece {}
optional string some_string_piece = 29 [ctype=STRING_PIECE];
// Some keywords.
optional uint32 int = 30;
optional uint32 friend = 31;
optional uint32 class = 37;
optional uint32 typedecl = 39;
optional uint32 auto = 40;
// The generator used to #define a macro called "DO" inside the .cc file.
message DO {}
optional DO do = 32;
// Some template parameter names for extensions.
optional int32 field_type = 33;
optional bool is_packed = 34;
// test conflicting release_$name$. "length" and "do" field in this message
// must remain string or message fields to make the test valid.
optional string release_length = 35;
// A more extreme case, the field name "do" here is a keyword, which will be
// escaped to "do_" already. Test there is no conflict even with escaped field
// names.
optional DO release_do = 36;
// For clashing local variables in Serialize and ByteSize calculation.
optional string target = 38;
extensions 1000 to max; // NO_PROTO3
}
message TestConflictingSymbolNamesExtension { // NO_PROTO3
extend TestConflictingSymbolNames { // NO_PROTO3
repeated int32 repeated_int32_ext = 20423638 [packed=true]; // NO_PROTO3
} // NO_PROTO3
} // NO_PROTO3
message TestConflictingEnumNames { // NO_PROTO3
enum NestedConflictingEnum { // NO_PROTO3
and = 1; // NO_PROTO3
class = 2; // NO_PROTO3
int = 3; // NO_PROTO3
typedef = 4; // NO_PROTO3
XOR = 5; // NO_PROTO3
} // NO_PROTO3
optional NestedConflictingEnum conflicting_enum = 1; // NO_PROTO3
} // NO_PROTO3
enum ConflictingEnum { // NO_PROTO3
NOT_EQ = 1; // NO_PROTO3
volatile = 2; // NO_PROTO3
return = 3; // NO_PROTO3
} // NO_PROTO3
message DummyMessage {}
// Message names that could conflict.
message Shutdown {}
message TableStruct {}
service TestConflictingMethodNames {
rpc Closure(DummyMessage) returns (DummyMessage);
}

View File

@ -0,0 +1,43 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Test that proto2 compiler can generate valid code when the enum value
// is INT_MAX. Note that this is a compile-only test and this proto is not
// referenced in any C++ code.
syntax = "proto2";
package protobuf_unittest;
message TestLargeEnumValue {
enum EnumWithLargeValue {
VALUE_1 = 1;
VALUE_MAX = 0x7fffffff;
}
}

View File

@ -0,0 +1,122 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
//
// To test the code generator, we actually use it to generate code for
// google/protobuf/unittest.proto, then test that. This means that we
// are actually testing the parser and other parts of the system at the same
// time, and that problems in the generator may show up as compile-time errors
// rather than unittest failures, which may be surprising. However, testing
// the output of the C++ generator directly would be very hard. We can't very
// well just check it against golden files since those files would have to be
// updated for any small change; such a test would be very brittle and probably
// not very helpful. What we really want to test is that the code compiles
// correctly and produces the interfaces we expect, which is why this test
// is written this way.
#include <google/protobuf/compiler/cpp/cpp_unittest.h>
#include <google/protobuf/unittest.pb.h>
#include <google/protobuf/unittest_optimize_for.pb.h>
#include <google/protobuf/unittest_embed_optimize_for.pb.h>
#include <google/protobuf/test_util.h>
#define MESSAGE_TEST_NAME MessageTest
#define GENERATED_DESCRIPTOR_TEST_NAME GeneratedDescriptorTest
#define GENERATED_MESSAGE_TEST_NAME GeneratedMessageTest
#define GENERATED_ENUM_TEST_NAME GeneratedEnumTest
#define GENERATED_SERVICE_TEST_NAME GeneratedServiceTest
#define HELPERS_TEST_NAME HelpersTest
#define DESCRIPTOR_INIT_TEST_NAME DescriptorInitializationTest
#define UNITTEST_PROTO_PATH "google/protobuf/unittest.proto"
#define UNITTEST ::protobuf_unittest
#define UNITTEST_IMPORT ::protobuf_unittest_import
// Must include after the above macros.
#include <google/protobuf/compiler/cpp/cpp_unittest.inc>
namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {
// Can't use an anonymous namespace here due to brokenness of Tru64 compiler.
namespace cpp_unittest {
namespace protobuf_unittest = ::protobuf_unittest;
TEST(GENERATED_MESSAGE_TEST_NAME, TestConflictingSymbolNames) {
// test_bad_identifiers.proto successfully compiled, then it works. The
// following is just a token usage to insure that the code is, in fact,
// being compiled and linked.
protobuf_unittest::TestConflictingSymbolNames message;
message.set_uint32(1);
EXPECT_EQ(3, message.ByteSizeLong());
message.set_friend_(5);
EXPECT_EQ(5, message.friend_());
message.set_class_(6);
EXPECT_EQ(6, message.class_());
// Instantiate extension template functions to test conflicting template
// parameter names.
typedef protobuf_unittest::TestConflictingSymbolNamesExtension ExtensionMessage;
message.AddExtension(ExtensionMessage::repeated_int32_ext, 123);
EXPECT_EQ(123,
message.GetExtension(ExtensionMessage::repeated_int32_ext, 0));
}
TEST(GENERATED_MESSAGE_TEST_NAME, TestConflictingEnumNames) {
protobuf_unittest::TestConflictingEnumNames message;
message.set_conflicting_enum(protobuf_unittest::TestConflictingEnumNames_NestedConflictingEnum_and_);
EXPECT_EQ(1, message.conflicting_enum());
message.set_conflicting_enum(protobuf_unittest::TestConflictingEnumNames_NestedConflictingEnum_XOR);
EXPECT_EQ(5, message.conflicting_enum());
protobuf_unittest::ConflictingEnum conflicting_enum;
conflicting_enum = protobuf_unittest::NOT_EQ;
EXPECT_EQ(1, conflicting_enum);
conflicting_enum = protobuf_unittest::return_;
EXPECT_EQ(3, conflicting_enum);
}
} // namespace cpp_unittest
} // namespace cpp
} // namespace compiler
} // namespace protobuf
} // namespace google

View File

@ -0,0 +1,51 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// This header declares the namespace google::protobuf::protobuf_unittest in order to expose
// any problems with the generated class names. We use this header to ensure
// unittest.cc will declare the namespace prior to other includes, while obeying
// normal include ordering.
//
// When generating a class name of "foo.Bar" we must ensure we prefix the class
// name with "::", in case the namespace google::protobuf::foo exists. We intentionally
// trigger that case here by declaring google::protobuf::protobuf_unittest.
//
// See ClassName in helpers.h for more details.
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_UNITTEST_H__
#define GOOGLE_PROTOBUF_COMPILER_CPP_UNITTEST_H__
namespace google {
namespace protobuf {
namespace protobuf_unittest {}
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_UNITTEST_H__

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,162 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <memory>
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
#include <google/protobuf/compiler/cpp/cpp_generator.h>
#include <google/protobuf/compiler/annotation_test_util.h>
#include <google/protobuf/compiler/command_line_interface.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/testing/file.h>
#include <google/protobuf/testing/file.h>
#include <google/protobuf/testing/googletest.h>
#include <gtest/gtest.h>
namespace google {
namespace atu = ::google::protobuf::compiler::annotation_test_util;
namespace protobuf {
namespace compiler {
namespace cpp {
namespace {
class CppMetadataTest : public ::testing::Test {
public:
// Tries to capture a FileDescriptorProto, GeneratedCodeInfo, and output
// code from the previously added file with name `filename`. Returns true on
// success. If pb_h is non-null, expects a .pb.h and a .pb.h.meta (copied to
// pb_h and pb_h_info respecfively); similarly for proto_h and proto_h_info.
bool CaptureMetadata(const string& filename, FileDescriptorProto* file,
string* pb_h, GeneratedCodeInfo* pb_h_info,
string* proto_h, GeneratedCodeInfo* proto_h_info,
string* pb_cc) {
google::protobuf::compiler::CommandLineInterface cli;
CppGenerator cpp_generator;
cli.RegisterGenerator("--cpp_out", &cpp_generator, "");
string cpp_out =
"--cpp_out=annotate_headers=true,"
"annotation_pragma_name=pragma_name,"
"annotation_guard_name=guard_name:" +
TestTempDir();
const bool result =
atu::RunProtoCompiler(filename, cpp_out, &cli, file);
if (!result) {
return result;
}
string output_base = TestTempDir() + "/" + StripProto(filename);
if (pb_cc != NULL) {
GOOGLE_CHECK_OK(
File::GetContents(output_base + ".pb.cc", pb_cc, true));
}
if (pb_h != NULL && pb_h_info != NULL) {
GOOGLE_CHECK_OK(
File::GetContents(output_base + ".pb.h", pb_h, true));
if (!atu::DecodeMetadata(output_base + ".pb.h.meta", pb_h_info)) {
return false;
}
}
if (proto_h != NULL && proto_h_info != NULL) {
GOOGLE_CHECK_OK(File::GetContents(output_base + ".proto.h", proto_h,
true));
if (!atu::DecodeMetadata(output_base + ".proto.h.meta", proto_h_info)) {
return false;
}
}
return true;
}
};
const char kSmallTestFile[] =
"syntax = \"proto2\";\n"
"package foo;\n"
"enum Enum { VALUE = 0; }\n"
"message Message { }\n";
TEST_F(CppMetadataTest, CapturesEnumNames) {
FileDescriptorProto file;
GeneratedCodeInfo info;
string pb_h;
atu::AddFile("test.proto", kSmallTestFile);
EXPECT_TRUE(
CaptureMetadata("test.proto", &file, &pb_h, &info, NULL, NULL, NULL));
EXPECT_EQ("Enum", file.enum_type(0).name());
std::vector<int> enum_path;
enum_path.push_back(FileDescriptorProto::kEnumTypeFieldNumber);
enum_path.push_back(0);
const GeneratedCodeInfo::Annotation* enum_annotation =
atu::FindAnnotationOnPath(info, "test.proto", enum_path);
EXPECT_TRUE(NULL != enum_annotation);
EXPECT_TRUE(atu::AnnotationMatchesSubstring(pb_h, enum_annotation, "Enum"));
}
TEST_F(CppMetadataTest, AddsPragma) {
FileDescriptorProto file;
GeneratedCodeInfo info;
string pb_h;
atu::AddFile("test.proto", kSmallTestFile);
EXPECT_TRUE(
CaptureMetadata("test.proto", &file, &pb_h, &info, NULL, NULL, NULL));
EXPECT_TRUE(pb_h.find("#ifdef guard_name") != string::npos);
EXPECT_TRUE(pb_h.find("#pragma pragma_name \"test.pb.h.meta\"") !=
string::npos);
}
TEST_F(CppMetadataTest, CapturesMessageNames) {
FileDescriptorProto file;
GeneratedCodeInfo info;
string pb_h;
atu::AddFile("test.proto", kSmallTestFile);
EXPECT_TRUE(
CaptureMetadata("test.proto", &file, &pb_h, &info, NULL, NULL, NULL));
EXPECT_EQ("Message", file.message_type(0).name());
std::vector<int> message_path;
message_path.push_back(FileDescriptorProto::kMessageTypeFieldNumber);
message_path.push_back(0);
const GeneratedCodeInfo::Annotation* message_annotation =
atu::FindAnnotationOnPath(info, "test.proto", message_path);
EXPECT_TRUE(NULL != message_annotation);
EXPECT_TRUE(
atu::AnnotationMatchesSubstring(pb_h, message_annotation, "Message"));
}
} // namespace
} // namespace cpp
} // namespace compiler
} // namespace protobuf
} // namespace google

View File

@ -0,0 +1,200 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// This test insures that
// csharp/src/Google.Protobuf/Reflection/Descriptor.cs match exactly
// what would be generated by the protocol compiler. The file is not
// generated automatically at build time.
//
// If this test fails, run the script
// "generate_descriptor_proto.sh" and add the changed files under
// csharp/src/ to your changelist.
#include <map>
#include <google/protobuf/compiler/csharp/csharp_generator.h>
#include <google/protobuf/compiler/importer.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/stubs/map_util.h>
#include <google/protobuf/stubs/stl_util.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/substitute.h>
#include <google/protobuf/testing/file.h>
#include <google/protobuf/testing/file.h>
#include <google/protobuf/testing/googletest.h>
#include <gtest/gtest.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace csharp {
namespace {
class MockErrorCollector : public MultiFileErrorCollector {
public:
MockErrorCollector() {}
~MockErrorCollector() {}
string text_;
// implements ErrorCollector ---------------------------------------
void AddError(const string& filename, int line, int column,
const string& message) {
strings::SubstituteAndAppend(&text_, "$0:$1:$2: $3\n",
filename, line, column, message);
}
};
class MockGeneratorContext : public GeneratorContext {
public:
MockGeneratorContext() {}
~MockGeneratorContext() {
STLDeleteValues(&files_);
}
void ExpectFileMatches(const string& virtual_filename,
const string& physical_filename) {
string* expected_contents = FindPtrOrNull(files_, virtual_filename);
ASSERT_TRUE(expected_contents != NULL)
<< "Generator failed to generate file: " << virtual_filename;
string actual_contents;
GOOGLE_CHECK_OK(
File::GetContents(TestSourceDir() + "/" + physical_filename,
&actual_contents, true))
<< "Unable to get " << physical_filename;
EXPECT_TRUE(actual_contents == *expected_contents)
<< physical_filename << " needs to be regenerated. Please run "
"generate_descriptor_proto.sh. Then add this file "
"to your CL.";
}
// implements GeneratorContext --------------------------------------
virtual io::ZeroCopyOutputStream* Open(const string& filename) {
string** map_slot = &files_[filename];
delete *map_slot;
*map_slot = new string;
return new io::StringOutputStream(*map_slot);
}
private:
std::map<string, string*> files_;
};
class GenerateAndTest {
public:
GenerateAndTest() {}
void Run(const FileDescriptor* proto_file, string file1, string file2) {
ASSERT_TRUE(proto_file != NULL) << TestSourceDir();
ASSERT_TRUE(generator_.Generate(proto_file, parameter_,
&context_, &error_));
context_.ExpectFileMatches(file1, file2);
}
void SetParameter(string parameter) {
parameter_ = parameter;
}
private:
Generator generator_;
MockGeneratorContext context_;
string error_;
string parameter_;
};
TEST(CsharpBootstrapTest, GeneratedCsharpDescriptorMatches) {
// Skip this whole test if the csharp directory doesn't exist (i.e., a C++11
// only distribution).
string descriptor_file_name =
"../csharp/src/Google.Protobuf/Reflection/Descriptor.cs";
if (!File::Exists(TestSourceDir() + "/" + descriptor_file_name)) {
return;
}
MockErrorCollector error_collector;
DiskSourceTree source_tree;
Importer importer(&source_tree, &error_collector);
GenerateAndTest generate_test;
generate_test.SetParameter("base_namespace=Google.Protobuf");
source_tree.MapPath("", TestSourceDir());
generate_test.Run(importer.Import("google/protobuf/descriptor.proto"),
"Reflection/Descriptor.cs",
"../csharp/src/Google.Protobuf/Reflection/Descriptor.cs");
generate_test.Run(importer.Import("google/protobuf/any.proto"),
"WellKnownTypes/Any.cs",
"../csharp/src/Google.Protobuf/WellKnownTypes/Any.cs");
generate_test.Run(importer.Import("google/protobuf/api.proto"),
"WellKnownTypes/Api.cs",
"../csharp/src/Google.Protobuf/WellKnownTypes/Api.cs");
generate_test.Run(importer.Import("google/protobuf/duration.proto"),
"WellKnownTypes/Duration.cs",
"../csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs");
generate_test.Run(importer.Import("google/protobuf/empty.proto"),
"WellKnownTypes/Empty.cs",
"../csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs");
generate_test.Run(importer.Import("google/protobuf/field_mask.proto"),
"WellKnownTypes/FieldMask.cs",
"../csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs");
generate_test.Run(importer.Import("google/protobuf/source_context.proto"),
"WellKnownTypes/SourceContext.cs",
"../csharp/src/Google.Protobuf/WellKnownTypes/SourceContext.cs");
generate_test.Run(importer.Import("google/protobuf/struct.proto"),
"WellKnownTypes/Struct.cs",
"../csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs");
generate_test.Run(importer.Import("google/protobuf/timestamp.proto"),
"WellKnownTypes/Timestamp.cs",
"../csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs");
generate_test.Run(importer.Import("google/protobuf/type.proto"),
"WellKnownTypes/Type.cs",
"../csharp/src/Google.Protobuf/WellKnownTypes/Type.cs");
generate_test.Run(importer.Import("google/protobuf/wrappers.proto"),
"WellKnownTypes/Wrappers.cs",
"../csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs");
generate_test.SetParameter("");
source_tree.MapPath("", TestSourceDir() + "/../conformance");
generate_test.Run(importer.Import("conformance.proto"),
"Conformance.cs",
"../csharp/src/Google.Protobuf.Conformance/Conformance.cs");
EXPECT_EQ("", error_collector.text_);
}
} // namespace
} // namespace csharp
} // namespace compiler
} // namespace protobuf
} // namespace google

View File

@ -0,0 +1,114 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/stubs/strutil.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace csharp {
// Functions to create C# XML documentation comments.
// Currently this only includes documentation comments containing text specified as comments
// in the .proto file; documentation comments generated just from field/message/enum/proto names
// is inlined in the relevant code. If more control is required, that code can be moved here.
void WriteDocCommentBodyImpl(io::Printer* printer, SourceLocation location) {
string comments = location.leading_comments.empty() ?
location.trailing_comments : location.leading_comments;
if (comments.empty()) {
return;
}
// XML escaping... no need for apostrophes etc as the whole text is going to be a child
// node of a summary element, not part of an attribute.
comments = StringReplace(comments, "&", "&amp;", true);
comments = StringReplace(comments, "<", "&lt;", true);
std::vector<string> lines = Split(comments, "\n", false /* skip_empty */);
// TODO: We really should work out which part to put in the summary and which to put in the remarks...
// but that needs to be part of a bigger effort to understand the markdown better anyway.
printer->Print("/// <summary>\n");
bool last_was_empty = false;
// We squash multiple blank lines down to one, and remove any trailing blank lines. We need
// to preserve the blank lines themselves, as this is relevant in the markdown.
// Note that we can't remove leading or trailing whitespace as *that's* relevant in markdown too.
// (We don't skip "just whitespace" lines, either.)
for (std::vector<string>::iterator it = lines.begin(); it != lines.end(); ++it) {
string line = *it;
if (line.empty()) {
last_was_empty = true;
} else {
if (last_was_empty) {
printer->Print("///\n");
}
last_was_empty = false;
printer->Print("///$line$\n", "line", *it);
}
}
printer->Print("/// </summary>\n");
}
template <typename DescriptorType>
static void WriteDocCommentBody(
io::Printer* printer, const DescriptorType* descriptor) {
SourceLocation location;
if (descriptor->GetSourceLocation(&location)) {
WriteDocCommentBodyImpl(printer, location);
}
}
void WriteMessageDocComment(io::Printer* printer, const Descriptor* message) {
WriteDocCommentBody(printer, message);
}
void WritePropertyDocComment(io::Printer* printer, const FieldDescriptor* field) {
WriteDocCommentBody(printer, field);
}
void WriteEnumDocComment(io::Printer* printer, const EnumDescriptor* enumDescriptor) {
WriteDocCommentBody(printer, enumDescriptor);
}
void WriteEnumValueDocComment(io::Printer* printer, const EnumValueDescriptor* value) {
WriteDocCommentBody(printer, value);
}
void WriteMethodDocComment(io::Printer* printer, const MethodDescriptor* method) {
WriteDocCommentBody(printer, method);
}
} // namespace csharp
} // namespace compiler
} // namespace protobuf
} // namespace google

View File

@ -0,0 +1,51 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_DOC_COMMENT_H__
#define GOOGLE_PROTOBUF_COMPILER_CSHARP_DOC_COMMENT_H__
#include <google/protobuf/io/printer.h>
#include <google/protobuf/descriptor.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace csharp {
void WriteMessageDocComment(io::Printer* printer, const Descriptor* message);
void WritePropertyDocComment(io::Printer* printer, const FieldDescriptor* field);
void WriteEnumDocComment(io::Printer* printer, const EnumDescriptor* enumDescriptor);
void WriteEnumValueDocComment(io::Printer* printer, const EnumValueDescriptor* value);
void WriteMethodDocComment(io::Printer* printer, const MethodDescriptor* method);
} // namespace csharp
} // namespace compiler
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_DOC_COMMENT_H__

View File

@ -0,0 +1,99 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <sstream>
#include <google/protobuf/compiler/code_generator.h>
#include <google/protobuf/compiler/plugin.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
#include <google/protobuf/compiler/csharp/csharp_enum.h>
#include <google/protobuf/compiler/csharp/csharp_helpers.h>
#include <google/protobuf/compiler/csharp/csharp_options.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace csharp {
EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor, const Options* options) :
SourceGeneratorBase(descriptor->file(), options),
descriptor_(descriptor) {
}
EnumGenerator::~EnumGenerator() {
}
void EnumGenerator::Generate(io::Printer* printer) {
WriteEnumDocComment(printer, descriptor_);
printer->Print("$access_level$ enum $name$ {\n",
"access_level", class_access_level(),
"name", descriptor_->name());
printer->Indent();
std::set<string> used_names;
std::set<int> used_number;
for (int i = 0; i < descriptor_->value_count(); i++) {
WriteEnumValueDocComment(printer, descriptor_->value(i));
string original_name = descriptor_->value(i)->name();
string name = GetEnumValueName(descriptor_->name(), descriptor_->value(i)->name());
// Make sure we don't get any duplicate names due to prefix removal.
while (!used_names.insert(name).second) {
// It's possible we'll end up giving this warning multiple times, but that's better than not at all.
GOOGLE_LOG(WARNING) << "Duplicate enum value " << name << " (originally " << original_name
<< ") in " << descriptor_->name() << "; adding underscore to distinguish";
name += "_";
}
int number = descriptor_->value(i)->number();
if (!used_number.insert(number).second) {
printer->Print("[pbr::OriginalName(\"$original_name$\", PreferredAlias = false)] $name$ = $number$,\n",
"original_name", original_name,
"name", name,
"number", SimpleItoa(number));
} else {
printer->Print("[pbr::OriginalName(\"$original_name$\")] $name$ = $number$,\n",
"original_name", original_name,
"name", name,
"number", SimpleItoa(number));
}
}
printer->Outdent();
printer->Print("}\n");
printer->Print("\n");
}
} // namespace csharp
} // namespace compiler
} // namespace protobuf
} // namespace google

View File

@ -0,0 +1,63 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_H__
#define GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_H__
#include <string>
#include <google/protobuf/compiler/code_generator.h>
#include <google/protobuf/compiler/csharp/csharp_source_generator_base.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace csharp {
class EnumGenerator : public SourceGeneratorBase {
public:
EnumGenerator(const EnumDescriptor* descriptor, const Options* options);
~EnumGenerator();
void Generate(io::Printer* printer);
private:
const EnumDescriptor* descriptor_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator);
};
} // namespace csharp
} // namespace compiler
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_H__

View File

@ -0,0 +1,124 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <sstream>
#include <google/protobuf/compiler/code_generator.h>
#include <google/protobuf/compiler/plugin.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/compiler/csharp/csharp_helpers.h>
#include <google/protobuf/compiler/csharp/csharp_options.h>
#include <google/protobuf/compiler/csharp/csharp_enum_field.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace csharp {
EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor,
int fieldOrdinal, const Options *options)
: PrimitiveFieldGenerator(descriptor, fieldOrdinal, options) {
}
EnumFieldGenerator::~EnumFieldGenerator() {
}
void EnumFieldGenerator::GenerateParsingCode(io::Printer* printer) {
printer->Print(variables_,
"$name$_ = ($type_name$) input.ReadEnum();\n");
}
void EnumFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
printer->Print(variables_,
"if ($has_property_check$) {\n"
" output.WriteRawTag($tag_bytes$);\n"
" output.WriteEnum((int) $property_name$);\n"
"}\n");
}
void EnumFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
printer->Print(
variables_,
"if ($has_property_check$) {\n"
" size += $tag_size$ + pb::CodedOutputStream.ComputeEnumSize((int) $property_name$);\n"
"}\n");
}
void EnumFieldGenerator::GenerateCodecCode(io::Printer* printer) {
printer->Print(
variables_,
"pb::FieldCodec.ForEnum($tag$, x => (int) x, x => ($type_name$) x)");
}
EnumOneofFieldGenerator::EnumOneofFieldGenerator(
const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options)
: PrimitiveOneofFieldGenerator(descriptor, fieldOrdinal, options) {
}
EnumOneofFieldGenerator::~EnumOneofFieldGenerator() {
}
void EnumOneofFieldGenerator::GenerateMergingCode(io::Printer* printer) {
printer->Print(variables_, "$property_name$ = other.$property_name$;\n");
}
void EnumOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) {
// TODO(jonskeet): What about if we read the default value?
printer->Print(
variables_,
"$oneof_name$_ = input.ReadEnum();\n"
"$oneof_name$Case_ = $oneof_property_name$OneofCase.$property_name$;\n");
}
void EnumOneofFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
printer->Print(
variables_,
"if ($has_property_check$) {\n"
" output.WriteRawTag($tag_bytes$);\n"
" output.WriteEnum((int) $property_name$);\n"
"}\n");
}
void EnumOneofFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
printer->Print(
variables_,
"if ($has_property_check$) {\n"
" size += $tag_size$ + pb::CodedOutputStream.ComputeEnumSize((int) $property_name$);\n"
"}\n");
}
} // namespace csharp
} // namespace compiler
} // namespace protobuf
} // namespace google

View File

@ -0,0 +1,82 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_FIELD_H__
#define GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_FIELD_H__
#include <string>
#include <google/protobuf/compiler/code_generator.h>
#include <google/protobuf/compiler/csharp/csharp_primitive_field.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace csharp {
class EnumFieldGenerator : public PrimitiveFieldGenerator {
public:
EnumFieldGenerator(const FieldDescriptor* descriptor,
int fieldOrdinal,
const Options *options);
~EnumFieldGenerator();
virtual void GenerateCodecCode(io::Printer* printer);
virtual void GenerateParsingCode(io::Printer* printer);
virtual void GenerateSerializationCode(io::Printer* printer);
virtual void GenerateSerializedSizeCode(io::Printer* printer);
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator);
};
class EnumOneofFieldGenerator : public PrimitiveOneofFieldGenerator {
public:
EnumOneofFieldGenerator(const FieldDescriptor* descriptor,
int fieldOrdinal,
const Options *options);
~EnumOneofFieldGenerator();
virtual void GenerateMergingCode(io::Printer* printer);
virtual void GenerateParsingCode(io::Printer* printer);
virtual void GenerateSerializationCode(io::Printer* printer);
virtual void GenerateSerializedSizeCode(io::Printer* printer);
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumOneofFieldGenerator);
};
} // namespace csharp
} // namespace compiler
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_FIELD_H__

View File

@ -0,0 +1,430 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <limits>
#include <sstream>
#include <google/protobuf/compiler/code_generator.h>
#include <google/protobuf/compiler/plugin.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/stubs/mathlimits.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/wire_format.h>
#include <google/protobuf/compiler/csharp/csharp_field_base.h>
#include <google/protobuf/compiler/csharp/csharp_helpers.h>
#include <google/protobuf/compiler/csharp/csharp_names.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace csharp {
void FieldGeneratorBase::SetCommonFieldVariables(
std::map<string, string>* variables) {
// Note: this will be valid even though the tag emitted for packed and unpacked versions of
// repeated fields varies by wire format. The wire format is encoded in the bottom 3 bits, which
// never effects the tag size.
int tag_size = internal::WireFormat::TagSize(descriptor_->number(), descriptor_->type());
uint tag = internal::WireFormat::MakeTag(descriptor_);
uint8 tag_array[5];
io::CodedOutputStream::WriteTagToArray(tag, tag_array);
string tag_bytes = SimpleItoa(tag_array[0]);
for (int i = 1; i < tag_size; i++) {
tag_bytes += ", " + SimpleItoa(tag_array[i]);
}
(*variables)["access_level"] = "public";
(*variables)["tag"] = SimpleItoa(tag);
(*variables)["tag_size"] = SimpleItoa(tag_size);
(*variables)["tag_bytes"] = tag_bytes;
(*variables)["property_name"] = property_name();
(*variables)["type_name"] = type_name();
(*variables)["name"] = name();
(*variables)["descriptor_name"] = descriptor_->name();
(*variables)["default_value"] = default_value();
if (has_default_value()) {
(*variables)["name_def_message"] =
(*variables)["name"] + "_ = " + (*variables)["default_value"];
} else {
(*variables)["name_def_message"] = (*variables)["name"] + "_";
}
(*variables)["capitalized_type_name"] = capitalized_type_name();
(*variables)["number"] = number();
(*variables)["has_property_check"] =
(*variables)["property_name"] + " != " + (*variables)["default_value"];
(*variables)["other_has_property_check"] = "other." +
(*variables)["property_name"] + " != " + (*variables)["default_value"];
}
void FieldGeneratorBase::SetCommonOneofFieldVariables(
std::map<string, string>* variables) {
(*variables)["oneof_name"] = oneof_name();
(*variables)["has_property_check"] =
oneof_name() + "Case_ == " + oneof_property_name() +
"OneofCase." + property_name();
(*variables)["oneof_property_name"] = oneof_property_name();
}
FieldGeneratorBase::FieldGeneratorBase(const FieldDescriptor* descriptor,
int fieldOrdinal, const Options* options)
: SourceGeneratorBase(descriptor->file(), options),
descriptor_(descriptor),
fieldOrdinal_(fieldOrdinal) {
SetCommonFieldVariables(&variables_);
}
FieldGeneratorBase::~FieldGeneratorBase() {
}
void FieldGeneratorBase::GenerateFreezingCode(io::Printer* printer) {
// No-op: only message fields and repeated fields need
// special handling for freezing, so default to not generating any code.
}
void FieldGeneratorBase::GenerateCodecCode(io::Printer* printer) {
// No-op: expect this to be overridden by appropriate types.
// Could fail if we get called here though...
}
void FieldGeneratorBase::AddDeprecatedFlag(io::Printer* printer) {
if (descriptor_->options().deprecated()) {
printer->Print("[global::System.ObsoleteAttribute]\n");
} else if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE &&
descriptor_->message_type()->options().deprecated()) {
printer->Print("[global::System.ObsoleteAttribute]\n");
}
}
void FieldGeneratorBase::AddPublicMemberAttributes(io::Printer* printer) {
AddDeprecatedFlag(printer);
WriteGeneratedCodeAttributes(printer);
}
std::string FieldGeneratorBase::oneof_property_name() {
return UnderscoresToCamelCase(descriptor_->containing_oneof()->name(), true);
}
std::string FieldGeneratorBase::oneof_name() {
return UnderscoresToCamelCase(descriptor_->containing_oneof()->name(), false);
}
std::string FieldGeneratorBase::property_name() {
return GetPropertyName(descriptor_);
}
std::string FieldGeneratorBase::name() {
return UnderscoresToCamelCase(GetFieldName(descriptor_), false);
}
std::string FieldGeneratorBase::type_name() {
return type_name(descriptor_);
}
std::string FieldGeneratorBase::type_name(const FieldDescriptor* descriptor) {
switch (descriptor->type()) {
case FieldDescriptor::TYPE_ENUM:
return GetClassName(descriptor->enum_type());
case FieldDescriptor::TYPE_MESSAGE:
case FieldDescriptor::TYPE_GROUP:
if (IsWrapperType(descriptor)) {
const FieldDescriptor* wrapped_field =
descriptor->message_type()->field(0);
string wrapped_field_type_name = type_name(wrapped_field);
// String and ByteString go to the same type; other wrapped types
// go to the nullable equivalent.
if (wrapped_field->type() == FieldDescriptor::TYPE_STRING ||
wrapped_field->type() == FieldDescriptor::TYPE_BYTES) {
return wrapped_field_type_name;
} else {
return wrapped_field_type_name + "?";
}
}
return GetClassName(descriptor->message_type());
case FieldDescriptor::TYPE_DOUBLE:
return "double";
case FieldDescriptor::TYPE_FLOAT:
return "float";
case FieldDescriptor::TYPE_INT64:
return "long";
case FieldDescriptor::TYPE_UINT64:
return "ulong";
case FieldDescriptor::TYPE_INT32:
return "int";
case FieldDescriptor::TYPE_FIXED64:
return "ulong";
case FieldDescriptor::TYPE_FIXED32:
return "uint";
case FieldDescriptor::TYPE_BOOL:
return "bool";
case FieldDescriptor::TYPE_STRING:
return "string";
case FieldDescriptor::TYPE_BYTES:
return "pb::ByteString";
case FieldDescriptor::TYPE_UINT32:
return "uint";
case FieldDescriptor::TYPE_SFIXED32:
return "int";
case FieldDescriptor::TYPE_SFIXED64:
return "long";
case FieldDescriptor::TYPE_SINT32:
return "int";
case FieldDescriptor::TYPE_SINT64:
return "long";
default:
GOOGLE_LOG(FATAL)<< "Unknown field type.";
return "";
}
}
bool FieldGeneratorBase::has_default_value() {
switch (descriptor_->type()) {
case FieldDescriptor::TYPE_ENUM:
case FieldDescriptor::TYPE_MESSAGE:
case FieldDescriptor::TYPE_GROUP:
return true;
case FieldDescriptor::TYPE_DOUBLE:
return descriptor_->default_value_double() != 0.0;
case FieldDescriptor::TYPE_FLOAT:
return descriptor_->default_value_float() != 0.0;
case FieldDescriptor::TYPE_INT64:
return descriptor_->default_value_int64() != 0L;
case FieldDescriptor::TYPE_UINT64:
return descriptor_->default_value_uint64() != 0L;
case FieldDescriptor::TYPE_INT32:
return descriptor_->default_value_int32() != 0;
case FieldDescriptor::TYPE_FIXED64:
return descriptor_->default_value_uint64() != 0L;
case FieldDescriptor::TYPE_FIXED32:
return descriptor_->default_value_uint32() != 0;
case FieldDescriptor::TYPE_BOOL:
return descriptor_->default_value_bool();
case FieldDescriptor::TYPE_STRING:
return true;
case FieldDescriptor::TYPE_BYTES:
return true;
case FieldDescriptor::TYPE_UINT32:
return descriptor_->default_value_uint32() != 0;
case FieldDescriptor::TYPE_SFIXED32:
return descriptor_->default_value_int32() != 0;
case FieldDescriptor::TYPE_SFIXED64:
return descriptor_->default_value_int64() != 0L;
case FieldDescriptor::TYPE_SINT32:
return descriptor_->default_value_int32() != 0;
case FieldDescriptor::TYPE_SINT64:
return descriptor_->default_value_int64() != 0L;
default:
GOOGLE_LOG(FATAL)<< "Unknown field type.";
return true;
}
}
bool FieldGeneratorBase::is_nullable_type() {
switch (descriptor_->type()) {
case FieldDescriptor::TYPE_ENUM:
case FieldDescriptor::TYPE_DOUBLE:
case FieldDescriptor::TYPE_FLOAT:
case FieldDescriptor::TYPE_INT64:
case FieldDescriptor::TYPE_UINT64:
case FieldDescriptor::TYPE_INT32:
case FieldDescriptor::TYPE_FIXED64:
case FieldDescriptor::TYPE_FIXED32:
case FieldDescriptor::TYPE_BOOL:
case FieldDescriptor::TYPE_UINT32:
case FieldDescriptor::TYPE_SFIXED32:
case FieldDescriptor::TYPE_SFIXED64:
case FieldDescriptor::TYPE_SINT32:
case FieldDescriptor::TYPE_SINT64:
return false;
case FieldDescriptor::TYPE_MESSAGE:
case FieldDescriptor::TYPE_GROUP:
case FieldDescriptor::TYPE_STRING:
case FieldDescriptor::TYPE_BYTES:
return true;
default:
GOOGLE_LOG(FATAL)<< "Unknown field type.";
return true;
}
}
bool AllPrintableAscii(const std::string& text) {
for(int i = 0; i < text.size(); i++) {
if (text[i] < 0x20 || text[i] > 0x7e) {
return false;
}
}
return true;
}
std::string FieldGeneratorBase::GetStringDefaultValueInternal() {
// No other default values needed for proto3...
return "\"\"";
}
std::string FieldGeneratorBase::GetBytesDefaultValueInternal() {
// No other default values needed for proto3...
return "pb::ByteString.Empty";
}
std::string FieldGeneratorBase::default_value() {
return default_value(descriptor_);
}
std::string FieldGeneratorBase::default_value(const FieldDescriptor* descriptor) {
switch (descriptor->type()) {
case FieldDescriptor::TYPE_ENUM:
// All proto3 enums have a default value of 0, and there's an implicit conversion from the constant 0 to
// any C# enum. This means we don't need to work out what we actually mapped the enum value name to.
return "0";
case FieldDescriptor::TYPE_MESSAGE:
case FieldDescriptor::TYPE_GROUP:
if (IsWrapperType(descriptor)) {
const FieldDescriptor* wrapped_field = descriptor->message_type()->field(0);
return default_value(wrapped_field);
} else {
return "null";
}
case FieldDescriptor::TYPE_DOUBLE: {
double value = descriptor->default_value_double();
if (value == std::numeric_limits<double>::infinity()) {
return "double.PositiveInfinity";
} else if (value == -std::numeric_limits<double>::infinity()) {
return "double.NegativeInfinity";
} else if (MathLimits<double>::IsNaN(value)) {
return "double.NaN";
}
return SimpleDtoa(value) + "D";
}
case FieldDescriptor::TYPE_FLOAT: {
float value = descriptor->default_value_float();
if (value == std::numeric_limits<float>::infinity()) {
return "float.PositiveInfinity";
} else if (value == -std::numeric_limits<float>::infinity()) {
return "float.NegativeInfinity";
} else if (MathLimits<float>::IsNaN(value)) {
return "float.NaN";
}
return SimpleFtoa(value) + "F";
}
case FieldDescriptor::TYPE_INT64:
return SimpleItoa(descriptor->default_value_int64()) + "L";
case FieldDescriptor::TYPE_UINT64:
return SimpleItoa(descriptor->default_value_uint64()) + "UL";
case FieldDescriptor::TYPE_INT32:
return SimpleItoa(descriptor->default_value_int32());
case FieldDescriptor::TYPE_FIXED64:
return SimpleItoa(descriptor->default_value_uint64()) + "UL";
case FieldDescriptor::TYPE_FIXED32:
return SimpleItoa(descriptor->default_value_uint32());
case FieldDescriptor::TYPE_BOOL:
if (descriptor->default_value_bool()) {
return "true";
} else {
return "false";
}
case FieldDescriptor::TYPE_STRING:
return GetStringDefaultValueInternal();
case FieldDescriptor::TYPE_BYTES:
return GetBytesDefaultValueInternal();
case FieldDescriptor::TYPE_UINT32:
return SimpleItoa(descriptor->default_value_uint32());
case FieldDescriptor::TYPE_SFIXED32:
return SimpleItoa(descriptor->default_value_int32());
case FieldDescriptor::TYPE_SFIXED64:
return SimpleItoa(descriptor->default_value_int64()) + "L";
case FieldDescriptor::TYPE_SINT32:
return SimpleItoa(descriptor->default_value_int32());
case FieldDescriptor::TYPE_SINT64:
return SimpleItoa(descriptor->default_value_int64()) + "L";
default:
GOOGLE_LOG(FATAL)<< "Unknown field type.";
return "";
}
}
std::string FieldGeneratorBase::number() {
return SimpleItoa(descriptor_->number());
}
std::string FieldGeneratorBase::capitalized_type_name() {
switch (descriptor_->type()) {
case FieldDescriptor::TYPE_ENUM:
return "Enum";
case FieldDescriptor::TYPE_MESSAGE:
return "Message";
case FieldDescriptor::TYPE_GROUP:
return "Group";
case FieldDescriptor::TYPE_DOUBLE:
return "Double";
case FieldDescriptor::TYPE_FLOAT:
return "Float";
case FieldDescriptor::TYPE_INT64:
return "Int64";
case FieldDescriptor::TYPE_UINT64:
return "UInt64";
case FieldDescriptor::TYPE_INT32:
return "Int32";
case FieldDescriptor::TYPE_FIXED64:
return "Fixed64";
case FieldDescriptor::TYPE_FIXED32:
return "Fixed32";
case FieldDescriptor::TYPE_BOOL:
return "Bool";
case FieldDescriptor::TYPE_STRING:
return "String";
case FieldDescriptor::TYPE_BYTES:
return "Bytes";
case FieldDescriptor::TYPE_UINT32:
return "UInt32";
case FieldDescriptor::TYPE_SFIXED32:
return "SFixed32";
case FieldDescriptor::TYPE_SFIXED64:
return "SFixed64";
case FieldDescriptor::TYPE_SINT32:
return "SInt32";
case FieldDescriptor::TYPE_SINT64:
return "SInt64";
default:
GOOGLE_LOG(FATAL)<< "Unknown field type.";
return "";
}
}
} // namespace csharp
} // namespace compiler
} // namespace protobuf
} // namespace google

View File

@ -0,0 +1,105 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_FIELD_BASE_H__
#define GOOGLE_PROTOBUF_COMPILER_CSHARP_FIELD_BASE_H__
#include <string>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/compiler/code_generator.h>
#include <google/protobuf/compiler/csharp/csharp_source_generator_base.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace csharp {
class FieldGeneratorBase : public SourceGeneratorBase {
public:
FieldGeneratorBase(const FieldDescriptor* descriptor,
int fieldOrdinal,
const Options* options);
~FieldGeneratorBase();
virtual void GenerateCloningCode(io::Printer* printer) = 0;
virtual void GenerateFreezingCode(io::Printer* printer);
virtual void GenerateCodecCode(io::Printer* printer);
virtual void GenerateMembers(io::Printer* printer) = 0;
virtual void GenerateMergingCode(io::Printer* printer) = 0;
virtual void GenerateParsingCode(io::Printer* printer) = 0;
virtual void GenerateSerializationCode(io::Printer* printer) = 0;
virtual void GenerateSerializedSizeCode(io::Printer* printer) = 0;
virtual void WriteHash(io::Printer* printer) = 0;
virtual void WriteEquals(io::Printer* printer) = 0;
// Currently unused, as we use reflection to generate JSON
virtual void WriteToString(io::Printer* printer) = 0;
protected:
const FieldDescriptor* descriptor_;
const int fieldOrdinal_;
std::map<string, string> variables_;
void AddDeprecatedFlag(io::Printer* printer);
void AddNullCheck(io::Printer* printer);
void AddNullCheck(io::Printer* printer, const std::string& name);
void AddPublicMemberAttributes(io::Printer* printer);
void SetCommonOneofFieldVariables(std::map<string, string>* variables);
std::string oneof_property_name();
std::string oneof_name();
std::string property_name();
std::string name();
std::string type_name();
std::string type_name(const FieldDescriptor* descriptor);
bool has_default_value();
bool is_nullable_type();
std::string default_value();
std::string default_value(const FieldDescriptor* descriptor);
std::string number();
std::string capitalized_type_name();
private:
void SetCommonFieldVariables(std::map<string, string>* variables);
std::string GetStringDefaultValueInternal();
std::string GetBytesDefaultValueInternal();
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorBase);
};
} // namespace csharp
} // namespace compiler
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_FIELD_BASE_H__

View File

@ -0,0 +1,113 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <sstream>
#include <google/protobuf/compiler/code_generator.h>
#include <google/protobuf/compiler/plugin.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/compiler/csharp/csharp_generator.h>
#include <google/protobuf/compiler/csharp/csharp_helpers.h>
#include <google/protobuf/compiler/csharp/csharp_names.h>
#include <google/protobuf/compiler/csharp/csharp_options.h>
#include <google/protobuf/compiler/csharp/csharp_reflection_class.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace csharp {
void GenerateFile(const google::protobuf::FileDescriptor* file,
io::Printer* printer,
const Options* options) {
ReflectionClassGenerator reflectionClassGenerator(file, options);
reflectionClassGenerator.Generate(printer);
}
bool Generator::Generate(
const FileDescriptor* file,
const string& parameter,
GeneratorContext* generator_context,
string* error) const {
std::vector<std::pair<string, string> > options;
ParseGeneratorParameter(parameter, &options);
// We only support proto3 - but we make an exception for descriptor.proto.
if (file->syntax() != FileDescriptor::SYNTAX_PROTO3 && !IsDescriptorProto(file)) {
*error = "C# code generation only supports proto3 syntax";
return false;
}
struct Options cli_options;
for (int i = 0; i < options.size(); i++) {
if (options[i].first == "file_extension") {
cli_options.file_extension = options[i].second;
} else if (options[i].first == "base_namespace") {
cli_options.base_namespace = options[i].second;
cli_options.base_namespace_specified = true;
} else if (options[i].first == "internal_access") {
cli_options.internal_access = true;
} else {
*error = "Unknown generator option: " + options[i].first;
return false;
}
}
string filename_error = "";
std::string filename = GetOutputFile(file,
cli_options.file_extension,
cli_options.base_namespace_specified,
cli_options.base_namespace,
&filename_error);
if (filename.empty()) {
*error = filename_error;
return false;
}
std::unique_ptr<io::ZeroCopyOutputStream> output(
generator_context->Open(filename));
io::Printer printer(output.get(), '$');
GenerateFile(file, &printer, &cli_options);
return true;
}
} // namespace csharp
} // namespace compiler
} // namespace protobuf
} // namespace google

View File

@ -0,0 +1,64 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Generates C# code for a given .proto file.
#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_GENERATOR_H__
#define GOOGLE_PROTOBUF_COMPILER_CSHARP_GENERATOR_H__
#include <string>
#include <google/protobuf/compiler/code_generator.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace csharp {
// CodeGenerator implementation which generates a C# source file and
// header. If you create your own protocol compiler binary and you want
// it to support C# output, you can do so by registering an instance of this
// CodeGenerator with the CommandLineInterface in your main() function.
class LIBPROTOC_EXPORT Generator
: public google::protobuf::compiler::CodeGenerator {
public:
virtual bool Generate(
const FileDescriptor* file,
const string& parameter,
GeneratorContext* generator_context,
string* error) const;
};
} // namespace csharp
} // namespace compiler
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_GENERATOR_H__

View File

@ -0,0 +1,70 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2014 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <memory>
#include <google/protobuf/compiler/command_line_interface.h>
#include <google/protobuf/compiler/csharp/csharp_helpers.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/testing/googletest.h>
#include <gtest/gtest.h>
#include <google/protobuf/testing/file.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace csharp {
namespace {
TEST(CSharpEnumValue, PascalCasedPrefixStripping) {
EXPECT_EQ("Bar", GetEnumValueName("Foo", "BAR"));
EXPECT_EQ("BarBaz", GetEnumValueName("Foo", "BAR_BAZ"));
EXPECT_EQ("Bar", GetEnumValueName("Foo", "FOO_BAR"));
EXPECT_EQ("Bar", GetEnumValueName("Foo", "FOO__BAR"));
EXPECT_EQ("BarBaz", GetEnumValueName("Foo", "FOO_BAR_BAZ"));
EXPECT_EQ("BarBaz", GetEnumValueName("Foo", "Foo_BarBaz"));
EXPECT_EQ("Bar", GetEnumValueName("FO_O", "FOO_BAR"));
EXPECT_EQ("Bar", GetEnumValueName("FOO", "F_O_O_BAR"));
EXPECT_EQ("Bar", GetEnumValueName("Foo", "BAR"));
EXPECT_EQ("BarBaz", GetEnumValueName("Foo", "BAR_BAZ"));
EXPECT_EQ("Foo", GetEnumValueName("Foo", "FOO"));
EXPECT_EQ("Foo", GetEnumValueName("Foo", "FOO___"));
// Identifiers can't start with digits
EXPECT_EQ("_2Bar", GetEnumValueName("Foo", "FOO_2_BAR"));
EXPECT_EQ("_2", GetEnumValueName("Foo", "FOO___2"));
}
} // namespace
} // namespace csharp
} // namespace compiler
} // namespace protobuf
} // namespace google

View File

@ -0,0 +1,507 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
#include <algorithm>
#include <google/protobuf/stubs/hash.h>
#include <limits>
#include <vector>
#include <google/protobuf/compiler/csharp/csharp_helpers.h>
#include <google/protobuf/compiler/csharp/csharp_names.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/wire_format.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/substitute.h>
#include <google/protobuf/compiler/csharp/csharp_field_base.h>
#include <google/protobuf/compiler/csharp/csharp_enum_field.h>
#include <google/protobuf/compiler/csharp/csharp_map_field.h>
#include <google/protobuf/compiler/csharp/csharp_message_field.h>
#include <google/protobuf/compiler/csharp/csharp_options.h>
#include <google/protobuf/compiler/csharp/csharp_primitive_field.h>
#include <google/protobuf/compiler/csharp/csharp_repeated_enum_field.h>
#include <google/protobuf/compiler/csharp/csharp_repeated_message_field.h>
#include <google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h>
#include <google/protobuf/compiler/csharp/csharp_wrapper_field.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace csharp {
CSharpType GetCSharpType(FieldDescriptor::Type type) {
switch (type) {
case FieldDescriptor::TYPE_INT32:
return CSHARPTYPE_INT32;
case FieldDescriptor::TYPE_INT64:
return CSHARPTYPE_INT64;
case FieldDescriptor::TYPE_UINT32:
return CSHARPTYPE_UINT32;
case FieldDescriptor::TYPE_UINT64:
return CSHARPTYPE_UINT32;
case FieldDescriptor::TYPE_SINT32:
return CSHARPTYPE_INT32;
case FieldDescriptor::TYPE_SINT64:
return CSHARPTYPE_INT64;
case FieldDescriptor::TYPE_FIXED32:
return CSHARPTYPE_UINT32;
case FieldDescriptor::TYPE_FIXED64:
return CSHARPTYPE_UINT64;
case FieldDescriptor::TYPE_SFIXED32:
return CSHARPTYPE_INT32;
case FieldDescriptor::TYPE_SFIXED64:
return CSHARPTYPE_INT64;
case FieldDescriptor::TYPE_FLOAT:
return CSHARPTYPE_FLOAT;
case FieldDescriptor::TYPE_DOUBLE:
return CSHARPTYPE_DOUBLE;
case FieldDescriptor::TYPE_BOOL:
return CSHARPTYPE_BOOL;
case FieldDescriptor::TYPE_ENUM:
return CSHARPTYPE_ENUM;
case FieldDescriptor::TYPE_STRING:
return CSHARPTYPE_STRING;
case FieldDescriptor::TYPE_BYTES:
return CSHARPTYPE_BYTESTRING;
case FieldDescriptor::TYPE_GROUP:
return CSHARPTYPE_MESSAGE;
case FieldDescriptor::TYPE_MESSAGE:
return CSHARPTYPE_MESSAGE;
// No default because we want the compiler to complain if any new
// types are added.
}
GOOGLE_LOG(FATAL)<< "Can't get here.";
return (CSharpType) -1;
}
std::string StripDotProto(const std::string& proto_file) {
int lastindex = proto_file.find_last_of(".");
return proto_file.substr(0, lastindex);
}
std::string GetFileNamespace(const FileDescriptor* descriptor) {
if (descriptor->options().has_csharp_namespace()) {
return descriptor->options().csharp_namespace();
}
return UnderscoresToCamelCase(descriptor->package(), true, true);
}
// Returns the Pascal-cased last part of the proto file. For example,
// input of "google/protobuf/foo_bar.proto" would result in "FooBar".
std::string GetFileNameBase(const FileDescriptor* descriptor) {
std::string proto_file = descriptor->name();
int lastslash = proto_file.find_last_of("/");
std::string base = proto_file.substr(lastslash + 1);
return UnderscoresToPascalCase(StripDotProto(base));
}
std::string GetReflectionClassUnqualifiedName(const FileDescriptor* descriptor) {
// TODO: Detect collisions with existing messages,
// and append an underscore if necessary.
return GetFileNameBase(descriptor) + "Reflection";
}
// TODO(jtattermusch): can we reuse a utility function?
std::string UnderscoresToCamelCase(const std::string& input,
bool cap_next_letter,
bool preserve_period) {
string result;
// Note: I distrust ctype.h due to locales.
for (int i = 0; i < input.size(); i++) {
if ('a' <= input[i] && input[i] <= 'z') {
if (cap_next_letter) {
result += input[i] + ('A' - 'a');
} else {
result += input[i];
}
cap_next_letter = false;
} else if ('A' <= input[i] && input[i] <= 'Z') {
if (i == 0 && !cap_next_letter) {
// Force first letter to lower-case unless explicitly told to
// capitalize it.
result += input[i] + ('a' - 'A');
} else {
// Capital letters after the first are left as-is.
result += input[i];
}
cap_next_letter = false;
} else if ('0' <= input[i] && input[i] <= '9') {
result += input[i];
cap_next_letter = true;
} else {
cap_next_letter = true;
if (input[i] == '.' && preserve_period) {
result += '.';
}
}
}
// Add a trailing "_" if the name should be altered.
if (input[input.size() - 1] == '#') {
result += '_';
}
return result;
}
std::string UnderscoresToPascalCase(const std::string& input) {
return UnderscoresToCamelCase(input, true);
}
// Convert a string which is expected to be SHOUTY_CASE (but may not be *precisely* shouty)
// into a PascalCase string. Precise rules implemented:
// Previous input character Current character Case
// Any Non-alphanumeric Skipped
// None - first char of input Alphanumeric Upper
// Non-letter (e.g. _ or 1) Alphanumeric Upper
// Numeric Alphanumeric Upper
// Lower letter Alphanumeric Same as current
// Upper letter Alphanumeric Lower
std::string ShoutyToPascalCase(const std::string& input) {
string result;
// Simple way of implementing "always start with upper"
char previous = '_';
for (int i = 0; i < input.size(); i++) {
char current = input[i];
if (!ascii_isalnum(current)) {
previous = current;
continue;
}
if (!ascii_isalnum(previous)) {
result += ascii_toupper(current);
} else if (ascii_isdigit(previous)) {
result += ascii_toupper(current);
} else if (ascii_islower(previous)) {
result += current;
} else {
result += ascii_tolower(current);
}
previous = current;
}
return result;
}
// Attempt to remove a prefix from a value, ignoring casing and skipping underscores.
// (foo, foo_bar) => bar - underscore after prefix is skipped
// (FOO, foo_bar) => bar - casing is ignored
// (foo_bar, foobarbaz) => baz - underscore in prefix is ignored
// (foobar, foo_barbaz) => baz - underscore in value is ignored
// (foo, bar) => bar - prefix isn't matched; return original value
std::string TryRemovePrefix(const std::string& prefix, const std::string& value) {
// First normalize to a lower-case no-underscores prefix to match against
std::string prefix_to_match = "";
for (size_t i = 0; i < prefix.size(); i++) {
if (prefix[i] != '_') {
prefix_to_match += ascii_tolower(prefix[i]);
}
}
// This keeps track of how much of value we've consumed
size_t prefix_index, value_index;
for (prefix_index = 0, value_index = 0;
prefix_index < prefix_to_match.size() && value_index < value.size();
value_index++) {
// Skip over underscores in the value
if (value[value_index] == '_') {
continue;
}
if (ascii_tolower(value[value_index]) != prefix_to_match[prefix_index++]) {
// Failed to match the prefix - bail out early.
return value;
}
}
// If we didn't finish looking through the prefix, we can't strip it.
if (prefix_index < prefix_to_match.size()) {
return value;
}
// Step over any underscores after the prefix
while (value_index < value.size() && value[value_index] == '_') {
value_index++;
}
// If there's nothing left (e.g. it was a prefix with only underscores afterwards), don't strip.
if (value_index == value.size()) {
return value;
}
return value.substr(value_index);
}
// Format the enum value name in a pleasant way for C#:
// - Strip the enum name as a prefix if possible
// - Convert to PascalCase.
// For example, an enum called Color with a value of COLOR_BLUE should
// result in an enum value in C# called just Blue
std::string GetEnumValueName(const std::string& enum_name, const std::string& enum_value_name) {
std::string stripped = TryRemovePrefix(enum_name, enum_value_name);
std::string result = ShoutyToPascalCase(stripped);
// Just in case we have an enum name of FOO and a value of FOO_2... make sure the returned
// string is a valid identifier.
if (ascii_isdigit(result[0])) {
result = "_" + result;
}
return result;
}
std::string ToCSharpName(const std::string& name, const FileDescriptor* file) {
std::string result = GetFileNamespace(file);
if (result != "") {
result += '.';
}
string classname;
if (file->package().empty()) {
classname = name;
} else {
// Strip the proto package from full_name since we've replaced it with
// the C# namespace.
classname = name.substr(file->package().size() + 1);
}
result += StringReplace(classname, ".", ".Types.", true);
return "global::" + result;
}
std::string GetReflectionClassName(const FileDescriptor* descriptor) {
std::string result = GetFileNamespace(descriptor);
if (!result.empty()) {
result += '.';
}
result += GetReflectionClassUnqualifiedName(descriptor);
return "global::" + result;
}
std::string GetClassName(const Descriptor* descriptor) {
return ToCSharpName(descriptor->full_name(), descriptor->file());
}
std::string GetClassName(const EnumDescriptor* descriptor) {
return ToCSharpName(descriptor->full_name(), descriptor->file());
}
// Groups are hacky: The name of the field is just the lower-cased name
// of the group type. In C#, though, we would like to retain the original
// capitalization of the type name.
std::string GetFieldName(const FieldDescriptor* descriptor) {
if (descriptor->type() == FieldDescriptor::TYPE_GROUP) {
return descriptor->message_type()->name();
} else {
return descriptor->name();
}
}
std::string GetFieldConstantName(const FieldDescriptor* field) {
return GetPropertyName(field) + "FieldNumber";
}
std::string GetPropertyName(const FieldDescriptor* descriptor) {
// TODO(jtattermusch): consider introducing csharp_property_name field option
std::string property_name = UnderscoresToPascalCase(GetFieldName(descriptor));
// Avoid either our own type name or reserved names. Note that not all names
// are reserved - a field called to_string, write_to etc would still cause a problem.
// There are various ways of ending up with naming collisions, but we try to avoid obvious
// ones.
if (property_name == descriptor->containing_type()->name()
|| property_name == "Types"
|| property_name == "Descriptor") {
property_name += "_";
}
return property_name;
}
std::string GetOutputFile(
const google::protobuf::FileDescriptor* descriptor,
const std::string file_extension,
const bool generate_directories,
const std::string base_namespace,
string* error) {
string relative_filename = GetFileNameBase(descriptor) + file_extension;
if (!generate_directories) {
return relative_filename;
}
string ns = GetFileNamespace(descriptor);
string namespace_suffix = ns;
if (!base_namespace.empty()) {
// Check that the base_namespace is either equal to or a leading part of
// the file namespace. This isn't just a simple prefix; "Foo.B" shouldn't
// be regarded as a prefix of "Foo.Bar". The simplest option is to add "."
// to both.
string extended_ns = ns + ".";
if (extended_ns.find(base_namespace + ".") != 0) {
*error = "Namespace " + ns + " is not a prefix namespace of base namespace " + base_namespace;
return ""; // This will be ignored, because we've set an error.
}
namespace_suffix = ns.substr(base_namespace.length());
if (namespace_suffix.find(".") == 0) {
namespace_suffix = namespace_suffix.substr(1);
}
}
string namespace_dir = StringReplace(namespace_suffix, ".", "/", true);
if (!namespace_dir.empty()) {
namespace_dir += "/";
}
return namespace_dir + relative_filename;
}
// TODO: c&p from Java protoc plugin
// For encodings with fixed sizes, returns that size in bytes. Otherwise
// returns -1.
int GetFixedSize(FieldDescriptor::Type type) {
switch (type) {
case FieldDescriptor::TYPE_INT32 : return -1;
case FieldDescriptor::TYPE_INT64 : return -1;
case FieldDescriptor::TYPE_UINT32 : return -1;
case FieldDescriptor::TYPE_UINT64 : return -1;
case FieldDescriptor::TYPE_SINT32 : return -1;
case FieldDescriptor::TYPE_SINT64 : return -1;
case FieldDescriptor::TYPE_FIXED32 : return internal::WireFormatLite::kFixed32Size;
case FieldDescriptor::TYPE_FIXED64 : return internal::WireFormatLite::kFixed64Size;
case FieldDescriptor::TYPE_SFIXED32: return internal::WireFormatLite::kSFixed32Size;
case FieldDescriptor::TYPE_SFIXED64: return internal::WireFormatLite::kSFixed64Size;
case FieldDescriptor::TYPE_FLOAT : return internal::WireFormatLite::kFloatSize;
case FieldDescriptor::TYPE_DOUBLE : return internal::WireFormatLite::kDoubleSize;
case FieldDescriptor::TYPE_BOOL : return internal::WireFormatLite::kBoolSize;
case FieldDescriptor::TYPE_ENUM : return -1;
case FieldDescriptor::TYPE_STRING : return -1;
case FieldDescriptor::TYPE_BYTES : return -1;
case FieldDescriptor::TYPE_GROUP : return -1;
case FieldDescriptor::TYPE_MESSAGE : return -1;
// No default because we want the compiler to complain if any new
// types are added.
}
GOOGLE_LOG(FATAL) << "Can't get here.";
return -1;
}
static const char base64_chars[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
std::string StringToBase64(const std::string& input) {
std::string result;
size_t remaining = input.size();
const unsigned char *src = (const unsigned char*) input.c_str();
while (remaining > 2) {
result += base64_chars[src[0] >> 2];
result += base64_chars[((src[0] & 0x3) << 4) | (src[1] >> 4)];
result += base64_chars[((src[1] & 0xf) << 2) | (src[2] >> 6)];
result += base64_chars[src[2] & 0x3f];
remaining -= 3;
src += 3;
}
switch (remaining) {
case 2:
result += base64_chars[src[0] >> 2];
result += base64_chars[((src[0] & 0x3) << 4) | (src[1] >> 4)];
result += base64_chars[(src[1] & 0xf) << 2];
result += '=';
src += 2;
break;
case 1:
result += base64_chars[src[0] >> 2];
result += base64_chars[((src[0] & 0x3) << 4)];
result += '=';
result += '=';
src += 1;
break;
}
return result;
}
std::string FileDescriptorToBase64(const FileDescriptor* descriptor) {
std::string fdp_bytes;
FileDescriptorProto fdp;
descriptor->CopyTo(&fdp);
fdp.SerializeToString(&fdp_bytes);
return StringToBase64(fdp_bytes);
}
FieldGeneratorBase* CreateFieldGenerator(const FieldDescriptor* descriptor,
int fieldOrdinal,
const Options* options) {
switch (descriptor->type()) {
case FieldDescriptor::TYPE_GROUP:
case FieldDescriptor::TYPE_MESSAGE:
if (descriptor->is_repeated()) {
if (descriptor->is_map()) {
return new MapFieldGenerator(descriptor, fieldOrdinal, options);
} else {
return new RepeatedMessageFieldGenerator(descriptor, fieldOrdinal, options);
}
} else {
if (IsWrapperType(descriptor)) {
if (descriptor->containing_oneof()) {
return new WrapperOneofFieldGenerator(descriptor, fieldOrdinal, options);
} else {
return new WrapperFieldGenerator(descriptor, fieldOrdinal, options);
}
} else {
if (descriptor->containing_oneof()) {
return new MessageOneofFieldGenerator(descriptor, fieldOrdinal, options);
} else {
return new MessageFieldGenerator(descriptor, fieldOrdinal, options);
}
}
}
case FieldDescriptor::TYPE_ENUM:
if (descriptor->is_repeated()) {
return new RepeatedEnumFieldGenerator(descriptor, fieldOrdinal, options);
} else {
if (descriptor->containing_oneof()) {
return new EnumOneofFieldGenerator(descriptor, fieldOrdinal, options);
} else {
return new EnumFieldGenerator(descriptor, fieldOrdinal, options);
}
}
default:
if (descriptor->is_repeated()) {
return new RepeatedPrimitiveFieldGenerator(descriptor, fieldOrdinal, options);
} else {
if (descriptor->containing_oneof()) {
return new PrimitiveOneofFieldGenerator(descriptor, fieldOrdinal, options);
} else {
return new PrimitiveFieldGenerator(descriptor, fieldOrdinal, options);
}
}
}
}
} // namespace csharp
} // namespace compiler
} // namespace protobuf
} // namespace google

View File

@ -0,0 +1,148 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_HELPERS_H__
#define GOOGLE_PROTOBUF_COMPILER_CSHARP_HELPERS_H__
#include <string>
#include <google/protobuf/stubs/port.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/compiler/code_generator.h>
#include <google/protobuf/io/printer.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace csharp {
struct Options;
class FieldGeneratorBase;
// TODO: start using this enum.
enum CSharpType {
CSHARPTYPE_INT32 = 1,
CSHARPTYPE_INT64 = 2,
CSHARPTYPE_UINT32 = 3,
CSHARPTYPE_UINT64 = 4,
CSHARPTYPE_FLOAT = 5,
CSHARPTYPE_DOUBLE = 6,
CSHARPTYPE_BOOL = 7,
CSHARPTYPE_STRING = 8,
CSHARPTYPE_BYTESTRING = 9,
CSHARPTYPE_MESSAGE = 10,
CSHARPTYPE_ENUM = 11,
MAX_CSHARPTYPE = 11
};
// Converts field type to corresponding C# type.
CSharpType GetCSharpType(FieldDescriptor::Type type);
std::string StripDotProto(const std::string& proto_file);
// Gets unqualified name of the reflection class
std::string GetReflectionClassUnqualifiedName(const FileDescriptor* descriptor);
std::string GetClassName(const EnumDescriptor* descriptor);
std::string GetFieldName(const FieldDescriptor* descriptor);
std::string GetFieldConstantName(const FieldDescriptor* field);
std::string GetPropertyName(const FieldDescriptor* descriptor);
int GetFixedSize(FieldDescriptor::Type type);
std::string UnderscoresToCamelCase(const std::string& input,
bool cap_next_letter,
bool preserve_period);
inline std::string UnderscoresToCamelCase(const std::string& input, bool cap_next_letter) {
return UnderscoresToCamelCase(input, cap_next_letter, false);
}
std::string UnderscoresToPascalCase(const std::string& input);
// Note that we wouldn't normally want to export this (we're not expecting
// it to be used outside libprotoc itself) but this exposes it for testing.
std::string LIBPROTOBUF_EXPORT GetEnumValueName(const std::string& enum_name, const std::string& enum_value_name);
// TODO(jtattermusch): perhaps we could move this to strutil
std::string StringToBase64(const std::string& input);
std::string FileDescriptorToBase64(const FileDescriptor* descriptor);
FieldGeneratorBase* CreateFieldGenerator(const FieldDescriptor* descriptor,
int fieldOrdinal,
const Options* options);
// Determines whether the given message is a map entry message,
// i.e. one implicitly created by protoc due to a map<key, value> field.
inline bool IsMapEntryMessage(const Descriptor* descriptor) {
return descriptor->options().map_entry();
}
// Determines whether we're generating code for the proto representation of
// descriptors etc, for use in the runtime. This is the only type which is
// allowed to use proto2 syntax, and it generates internal classes.
inline bool IsDescriptorProto(const FileDescriptor* descriptor) {
return descriptor->name() == "google/protobuf/descriptor.proto";
}
// Determines whether the given message is an options message within descriptor.proto.
inline bool IsDescriptorOptionMessage(const Descriptor* descriptor) {
if (!IsDescriptorProto(descriptor->file())) {
return false;
}
const string name = descriptor->full_name();
return name == "google.protobuf.FileOptions" ||
name == "google.protobuf.MessageOptions" ||
name == "google.protobuf.FieldOptions" ||
name == "google.protobuf.OneofOptions" ||
name == "google.protobuf.EnumOptions" ||
name == "google.protobuf.EnumValueOptions" ||
name == "google.protobuf.ServiceOptions" ||
name == "google.protobuf.MethodOptions";
}
inline bool IsWrapperType(const FieldDescriptor* descriptor) {
return descriptor->type() == FieldDescriptor::TYPE_MESSAGE &&
descriptor->message_type()->file()->name() == "google/protobuf/wrappers.proto";
}
} // namespace csharp
} // namespace compiler
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_HELPERS_H__

View File

@ -0,0 +1,141 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2015 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <sstream>
#include <google/protobuf/compiler/code_generator.h>
#include <google/protobuf/compiler/plugin.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
#include <google/protobuf/compiler/csharp/csharp_helpers.h>
#include <google/protobuf/compiler/csharp/csharp_map_field.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace csharp {
MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor,
int fieldOrdinal,
const Options* options)
: FieldGeneratorBase(descriptor, fieldOrdinal, options) {
}
MapFieldGenerator::~MapFieldGenerator() {
}
void MapFieldGenerator::GenerateMembers(io::Printer* printer) {
const FieldDescriptor* key_descriptor =
descriptor_->message_type()->FindFieldByName("key");
const FieldDescriptor* value_descriptor =
descriptor_->message_type()->FindFieldByName("value");
variables_["key_type_name"] = type_name(key_descriptor);
variables_["value_type_name"] = type_name(value_descriptor);
std::unique_ptr<FieldGeneratorBase> key_generator(
CreateFieldGenerator(key_descriptor, 1, this->options()));
std::unique_ptr<FieldGeneratorBase> value_generator(
CreateFieldGenerator(value_descriptor, 2, this->options()));
printer->Print(
variables_,
"private static readonly pbc::MapField<$key_type_name$, $value_type_name$>.Codec _map_$name$_codec\n"
" = new pbc::MapField<$key_type_name$, $value_type_name$>.Codec(");
key_generator->GenerateCodecCode(printer);
printer->Print(", ");
value_generator->GenerateCodecCode(printer);
printer->Print(
variables_,
", $tag$);\n"
"private readonly pbc::MapField<$key_type_name$, $value_type_name$> $name$_ = new pbc::MapField<$key_type_name$, $value_type_name$>();\n");
WritePropertyDocComment(printer, descriptor_);
AddPublicMemberAttributes(printer);
printer->Print(
variables_,
"$access_level$ pbc::MapField<$key_type_name$, $value_type_name$> $property_name$ {\n"
" get { return $name$_; }\n"
"}\n");
}
void MapFieldGenerator::GenerateMergingCode(io::Printer* printer) {
printer->Print(
variables_,
"$name$_.Add(other.$name$_);\n");
}
void MapFieldGenerator::GenerateParsingCode(io::Printer* printer) {
printer->Print(
variables_,
"$name$_.AddEntriesFrom(input, _map_$name$_codec);\n");
}
void MapFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
printer->Print(
variables_,
"$name$_.WriteTo(output, _map_$name$_codec);\n");
}
void MapFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
printer->Print(
variables_,
"size += $name$_.CalculateSize(_map_$name$_codec);\n");
}
void MapFieldGenerator::WriteHash(io::Printer* printer) {
printer->Print(
variables_,
"hash ^= $property_name$.GetHashCode();\n");
}
void MapFieldGenerator::WriteEquals(io::Printer* printer) {
printer->Print(
variables_,
"if (!$property_name$.Equals(other.$property_name$)) return false;\n");
}
void MapFieldGenerator::WriteToString(io::Printer* printer) {
// TODO: If we ever actually use ToString, we'll need to impleme this...
}
void MapFieldGenerator::GenerateCloningCode(io::Printer* printer) {
printer->Print(variables_,
"$name$_ = other.$name$_.Clone();\n");
}
void MapFieldGenerator::GenerateFreezingCode(io::Printer* printer) {
}
} // namespace csharp
} // namespace compiler
} // namespace protobuf
} // namespace google

Some files were not shown because too many files have changed in this diff Show More