use builtin protobuf-lite package in third_party

This commit is contained in:
Taku Kudo 2019-01-08 11:40:08 +09:00
parent 092a728975
commit 7b19d68be0
111 changed files with 42284 additions and 216 deletions

3
.gitignore vendored
View File

@ -53,9 +53,6 @@ spm_train
spm_normalize
spm_test
*.pb.cc
*.pb.h
.DS_Store
*.egg-info/
dist/

View File

@ -25,6 +25,7 @@ option(SPM_ENABLE_TENSORFLOW_SHARED "Makes a tensorflow compatible shared file."
option(SPM_ENABLE_TCMALLOC "Enable TCMalloc if available." ON)
option(SPM_TCMALLOC_STATIC "Link static library of TCMALLOC." OFF)
option(SPM_NO_THREADLOCAL "Disable thread_local operator" OFF)
option(SPM_USE_BUILTIN_PROTOBUF "Use built-in protobuf" ON)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
@ -35,13 +36,19 @@ set(libdir "\${exec_prefix}/lib")
set(includedir "\${prefix}/include")
set(GNUCXX_STD_SUPPORT_VERSION "4.3")
if(MSVC)
string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG})
string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_MINSIZEREL ${CMAKE_CXX_FLAGS_MINSIZEREL})
string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE})
string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_RELWITHDEBINFO ${CMAKE_CXX_FLAGS_RELWITHDEBINFO})
add_definitions("/wd4267 /wd4244 /wd4305 /Zc:strictStrings /utf-8")
endif(MSVC)
if (SPM_USE_BUILTIN_PROTOBUF)
set(libprotobuf_lite "")
else()
set(libprotobuf_lite "-lprotobuf-lite")
endif()
if (MSVC)
string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG})
string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_MINSIZEREL ${CMAKE_CXX_FLAGS_MINSIZEREL})
string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE})
string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_RELWITHDEBINFO ${CMAKE_CXX_FLAGS_RELWITHDEBINFO})
add_definitions("/wd4267 /wd4244 /wd4305 /Zc:strictStrings /utf-8")
endif()
if (APPLE)
set(CMAKE_MACOSX_RPATH ON)

View File

@ -1 +1 @@
0.1.6
0.1.8

45
data/extract_headers.pl Executable file
View File

@ -0,0 +1,45 @@
#!/usr/bin/perl
# Copyright 2018 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Extract header files required for build protobuf-lite
#
# usage: ./extract_headers.pl *.cc
use strict;
use warnings;
sub Process() {
my $file = shift @_;
if ($file =~ /\.h$/) {
print "$file\n";
}
return unless open(F, $file);
my @files = ();
while (<F>) {
chomp;
if (/\#include <(google\/protobuf\/[^>]+)>/) {
push @files, $1;
}
}
close(F);
for my $file (@files) {
&Process($file);
}
}
for my $f (@ARGV) {
&Process($f);
}

173
data/gen_spec_parser.pl Executable file
View File

@ -0,0 +1,173 @@
#!/usr/bin/perl
# Copyright 2018 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Generate spec_parser.h from sentencepiece_model.proto
#
# usage: ./gen_spec_parser.pl sentencepiece_model.proto > spec_parser.h
use strict;
use warnings;
sub ProcessPrinter() {
my ($filename) = @_;
my $classname = "";
my $valid = 0;
my %enum;
open(F, $filename) || die;
print "namespace {\n";
while (<F>) {
chomp;
if (/^\s*message (\S+)/) {
$classname = $1;
$valid = 0;
if ($classname =~ /(TrainerSpec|NormalizerSpec)/) {
print "inline std::string PrintProto(const $classname &message) {\n";
print " std::ostringstream os;\n\n";
print " os << \"$classname {\\n\";\n";
$valid = 1;
}
} elsif (/^\s*}/) {
next if (!$valid);
print " os << \"}\\n\";\n";
print "\n return os.str();\n";
print "}\n\n";
} elsif (/enum\s*(\S+)/) {
my $name = $1;
$enum{$name} = 1;
next if (!$valid);
print " static const std::map<$classname::$name, std::string> k${name}_Map = { ";
while (<F>) {
if (/(\S+)\s*=\s*(\d+)/) {
print "{$classname::$1, \"$1\"}, ";
} elsif (/}/) {
print " };\n";
last;
}
}
} elsif (/\s*(repeated|optional)\s+(\S+)\s+(\S+)\s*=\s*(\d+)/) {
next if (!$valid);
my $opt = $1;
my $type = $2;
my $name = $3;
if ($type =~ /(int|double|float|bool|string)/) {
if ($opt eq "optional") {
print " os << \" ${name}: \" << message.${name}() << \"\\n\";\n";
} else {
print " for (const auto &v : message.${name}())\n";
print " os << \" ${name}: \" << v << \"\\n\";\n";
}
} elsif (defined $enum{$type}) {
if ($opt eq "optional") {
print " {\n";
print " const auto it = k${type}_Map.find(message.${name}());\n";
print " if (it == k${type}_Map.end())\n";
print " os << \" ${name}: unknown\\n\";\n";
print " else\n";
print " os << \" ${name}: \" << it->second << \"\\n\";\n";
print " }\n";
} else {
print " for (const auto &v : message.${name}()) {\n";
print " const auto it = k${type}_Map.find(v);\n";
print " if (it == k${type}_Map.end())\n";
print " os << \" ${name}: unknown\\n\";\n";
print " else\n";
print " os << \" ${name}: \" << it->second << \"\\n\";\n";
print " }\n";
}
}
}
}
print "} // namespace\n\n";
close(F);
}
sub ProcessParser() {
my ($filename) = @_;
my $classname = "";
my $valid = 0;
my %enum;
open(F, $filename) || die;
while (<F>) {
if (/^\s*message (\S+)/) {
$classname = $1;
$valid = 0;
if ($classname =~ /(TrainerSpec|NormalizerSpec)/) {
print "util::Status SentencePieceTrainer::SetProtoField(const std::string& name, const std::string& value, $classname *message) {\n";
print " CHECK_OR_RETURN(message);\n\n";
$valid = 1;
}
} elsif (/^\s*}/) {
next if (!$valid);
print " return util::StatusBuilder(util::error::NOT_FOUND)\n";
print " << \"unknown field name \\\"\" << name << \"\\\" in ${classname}.\";\n";
print "}\n\n";
} elsif (/enum\s*(\S+)/) {
my $name = $1;
$enum{$name} = 1;
next if (!$valid);
print " static const std::map <std::string, $classname::$name> k${name}_Map = { ";
while (<F>) {
if (/(\S+)\s*=\s*(\d+)/) {
print "{\"$1\", $classname::$1}, ";
} elsif (/}/) {
print " };\n\n";
last;
}
}
} elsif (/\s*(repeated|optional)\s+(\S+)\s+(\S+)\s*=\s*(\d+)/) {
next if (!$valid);
my $opt = $1;
my $type = $2;
my $name = $3;
my $func_prefix = $opt eq "optional" ? "set_" : "add_";
my $body = "";
if ($type =~ /(int|double|float|bool)/) {
my $empty = $type eq "bool" ? "\"true\"" : "\"\"";
$body =
"${type} v;\n" .
" if (!string_util::lexical_cast(val.empty() ? ${empty} : val, &v))\n" .
" return util::StatusBuilder(util::error::INVALID_ARGUMENT) << \"cannot parse \\\"\" << val << \"\\\" as ${type}.\";\n" .
" message->${func_prefix}${name}(v);\n";
} elsif ($type =~ /string/) {
$body = "message->${func_prefix}${name}(val);\n";
} elsif ($type =~ /bytes/) {
$body = "message->${func_prefix}${name}(val.data(), val.size());\n";
} elsif (defined $enum{$type}) {
$body = "const auto it = k${type}_Map.find(string_util::ToUpper(val));\n" .
" if (it == k${type}_Map.end())\n" .
" return util::StatusBuilder(util::error::INVALID_ARGUMENT) << \"unknown enumeration value of \\\"\" << val << \"\\\" as ${type}.\";\n" .
" message->${func_prefix}${name}(it->second);\n";
}
print " if (name == \"${name}\") {\n";
if ($opt eq "repeated") {
print " for (const auto &val : string_util::Split(value, \",\")) {\n";
print " ${body}";
print " }\n";
} else {
print " const auto &val = value;\n";
print " ${body}";
}
print " return util::OkStatus();\n";
print " }\n\n";
}
}
close(F);
}
for my $file (@ARGV) {
&ProcessPrinter($file);
&ProcessParser($file);
}

View File

@ -15,7 +15,6 @@
set -e # exit immediately on error
set -x # display all commands
PROTOBUF_VERSION=3.6.1
CMAKE_VERSION=3.12.0
run_docker() {
@ -43,16 +42,6 @@ build() {
make install
cd ..
# Install protobuf
curl -L -O https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/protobuf-cpp-${PROTOBUF_VERSION}.tar.gz
tar zxfv protobuf-cpp-${PROTOBUF_VERSION}.tar.gz
cd protobuf-${PROTOBUF_VERSION}
cp -f ../../once.h src/google/protobuf/stubs/once.h
./configure --disable-shared --with-pic
make CXXFLAGS+="-std=c++11 -O3" CFLAGS+="-std=c++11 -O3" -j4
make install || true
cd ..
# Install sentencepiece
cmake ../.. -DSPM_ENABLE_SHARED=OFF
make -j4

View File

@ -16,8 +16,6 @@
set -e # exit immediately on error
set -x # display all commands
PROTOBUF_VERSION=3.6.1
build_python() {
VERSION=$1
URL=$2
@ -61,16 +59,6 @@ build() {
mkdir -p build
cd build
# Install protobuf
curl -L -O https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/protobuf-cpp-${PROTOBUF_VERSION}.tar.gz
tar zxfv protobuf-cpp-${PROTOBUF_VERSION}.tar.gz
cd protobuf-${PROTOBUF_VERSION}
./configure --disable-shared --with-pic
make CXXFLAGS+="-std=c++11 -O3 -DGOOGLE_PROTOBUF_NO_THREADLOCAL=1" \
CFLAGS+="-std=c++11 -O3 -DGOOGLE_PROTOBUF_NO_THREADLOCAL=1" -j4
make install || true
cd ..
# Install sentencepiece
cmake ../.. -DSPM_ENABLE_SHARED=OFF -DSPM_NO_THREADLOCAL=ON
make -j4 VERBOSE=1

View File

@ -53,8 +53,7 @@ def cflags():
def libs():
if sys.platform == 'win32':
return ['..\\build\\root\\lib\\sentencepiece.lib',
'..\\build\\root\\lib\\sentencepiece_train.lib',
'..\\build\\root\\lib\\libprotobuf.lib']
'..\\build\\root\\lib\\sentencepiece_train.lib']
return cmd('pkg-config sentencepiece --libs')

View File

@ -6,5 +6,5 @@ includedir=@includedir@
Name: @PROJECT_NAME@
Description: Unsupervised text tokenizer and detokenizer for Neural Network-based text generation.
Version: @PROJECT_VERSION@
Libs: -L${libdir} -lsentencepiece -lsentencepiece_train -lprotobuf @pkgconfiglibs@
Libs: -L${libdir} -lsentencepiece -lsentencepiece_train @libprotobuf_lite@ @pkgconfiglibs@
Cflags: -I${includedir} @pkgconfigcflags@

View File

@ -12,15 +12,56 @@
# See the License for the specific language governing permissions and
# limitations under the License.!
find_package(Protobuf REQUIRED)
include_directories(${Protobuf_INCLUDE_DIRS})
protobuf_generate_cpp(SPM_PROTO_SRCS SPM_PROTO_HDRS sentencepiece.proto)
protobuf_generate_cpp(SPM_MODEL_PROTO_SRCS SPM_MODEL_PROTO_HDRS sentencepiece_model.proto)
if (SPM_USE_BUILTIN_PROTOBUF)
set(SPM_PROTO_HDRS builtin_pb/sentencepiece.pb.h)
set(SPM_PROTO_SRCS builtin_pb/sentencepiece.pb.cc)
set(SPM_MODEL_PROTO_HDRS builtin_pb/sentencepiece_model.pb.h)
set(SPM_MODEL_PROTO_SRCS builtin_pb/sentencepiece_model.pb.cc)
set(PROTOBUF_LITE_LIBRARY "")
set(PROTOBUF_LITE_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/../third_party/protobuf-lite/arena.cc
${CMAKE_CURRENT_SOURCE_DIR}/../third_party/protobuf-lite/arenastring.cc
${CMAKE_CURRENT_SOURCE_DIR}/../third_party/protobuf-lite/bytestream.cc
${CMAKE_CURRENT_SOURCE_DIR}/../third_party/protobuf-lite/coded_stream.cc
${CMAKE_CURRENT_SOURCE_DIR}/../third_party/protobuf-lite/common.cc
${CMAKE_CURRENT_SOURCE_DIR}/../third_party/protobuf-lite/extension_set.cc
${CMAKE_CURRENT_SOURCE_DIR}/../third_party/protobuf-lite/generated_message_table_driven_lite.cc
${CMAKE_CURRENT_SOURCE_DIR}/../third_party/protobuf-lite/generated_message_util.cc
${CMAKE_CURRENT_SOURCE_DIR}/../third_party/protobuf-lite/implicit_weak_message.cc
${CMAKE_CURRENT_SOURCE_DIR}/../third_party/protobuf-lite/int128.cc
${CMAKE_CURRENT_SOURCE_DIR}/../third_party/protobuf-lite/io_win32.cc
${CMAKE_CURRENT_SOURCE_DIR}/../third_party/protobuf-lite/message_lite.cc
${CMAKE_CURRENT_SOURCE_DIR}/../third_party/protobuf-lite/repeated_field.cc
${CMAKE_CURRENT_SOURCE_DIR}/../third_party/protobuf-lite/status.cc
${CMAKE_CURRENT_SOURCE_DIR}/../third_party/protobuf-lite/statusor.cc
${CMAKE_CURRENT_SOURCE_DIR}/../third_party/protobuf-lite/stringpiece.cc
${CMAKE_CURRENT_SOURCE_DIR}/../third_party/protobuf-lite/stringprintf.cc
${CMAKE_CURRENT_SOURCE_DIR}/../third_party/protobuf-lite/structurally_valid.cc
${CMAKE_CURRENT_SOURCE_DIR}/../third_party/protobuf-lite/strutil.cc
${CMAKE_CURRENT_SOURCE_DIR}/../third_party/protobuf-lite/time.cc
${CMAKE_CURRENT_SOURCE_DIR}/../third_party/protobuf-lite/wire_format_lite.cc
${CMAKE_CURRENT_SOURCE_DIR}/../third_party/protobuf-lite/zero_copy_stream.cc
${CMAKE_CURRENT_SOURCE_DIR}/../third_party/protobuf-lite/zero_copy_stream_impl_lite.cc)
if (MSVC)
add_definitions("/DHAVE_PTHREAD /wd4018 /wd4514")
else()
add_definitions("-pthread -DHAVE_PTHREAD=1 -Wno-sign-compare")
endif()
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../third_party/protobuf-lite)
include_directories(builtin_pb)
else()
find_package(Protobuf REQUIRED)
include_directories(${Protobuf_INCLUDE_DIRS})
protobuf_generate_cpp(SPM_PROTO_SRCS SPM_PROTO_HDRS sentencepiece.proto)
protobuf_generate_cpp(SPM_MODEL_PROTO_SRCS SPM_MODEL_PROTO_HDRS sentencepiece_model.proto)
set(PROTOBUF_LITE_SRCS "")
include_directories(${PROTOBUF_INCLUDE_DIR})
endif()
include_directories(${CMAKE_CURRENT_BINARY_DIR})
include_directories(${PROTOBUF_INCLUDE_DIR})
set(SPM_SRCS
${PROTOBUF_LITE_SRCS}
${SPM_PROTO_HDRS}
${SPM_PROTO_SRCS}
${SPM_MODEL_PROTO_HDRS}
@ -106,7 +147,7 @@ set(SPM_TEST_SRCS
find_package(Threads REQUIRED)
set(SPM_LIBS ${PROTOBUF_LIBRARY} Threads::Threads)
set(SPM_LIBS ${PROTOBUF_LITE_LIBRARY} Threads::Threads)
if (SPM_ENABLE_NFKC_COMPILE)
find_package(ICU 4.4 COMPONENTS i18n data uc REQUIRED)
@ -175,6 +216,7 @@ if (NOT MSVC)
endif()
if (SPM_NO_THREADLOCAL)
add_definitions(-DSPM_NO_THREADLOCAL=1)
add_definitions(-DGOOGLE_PROTOBUF_NO_THREADLOCAL=1)
endif()
set_source_files_properties(
sentencepiece.pb.cc sentencepiece_model.pb.cc

View File

@ -173,8 +173,6 @@ void Trainer::UpdateActiveSymbols() {
util::Status Trainer::Train() {
RETURN_IF_ERROR(status());
LOG(INFO) << "Starts training with : \n" << trainer_spec_.Utf8DebugString();
CHECK_OR_RETURN(normalizer_spec_.escape_whitespaces());
CHECK_EQ_OR_RETURN(TrainerSpec::BPE, trainer_spec_.model_type());

View File

@ -0,0 +1,953 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: sentencepiece.proto
#include "sentencepiece.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/io/zero_copy_stream_impl_lite.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 protobuf_sentencepiece_2eproto {
extern PROTOBUF_INTERNAL_EXPORT_protobuf_sentencepiece_2eproto ::google::protobuf::internal::SCCInfo<0> scc_info_SentencePieceText_SentencePiece;
extern PROTOBUF_INTERNAL_EXPORT_protobuf_sentencepiece_2eproto ::google::protobuf::internal::SCCInfo<1> scc_info_SentencePieceText;
} // namespace protobuf_sentencepiece_2eproto
namespace sentencepiece {
class SentencePieceText_SentencePieceDefaultTypeInternal {
public:
::google::protobuf::internal::ExplicitlyConstructed<SentencePieceText_SentencePiece>
_instance;
} _SentencePieceText_SentencePiece_default_instance_;
class SentencePieceTextDefaultTypeInternal {
public:
::google::protobuf::internal::ExplicitlyConstructed<SentencePieceText>
_instance;
} _SentencePieceText_default_instance_;
class NBestSentencePieceTextDefaultTypeInternal {
public:
::google::protobuf::internal::ExplicitlyConstructed<NBestSentencePieceText>
_instance;
} _NBestSentencePieceText_default_instance_;
} // namespace sentencepiece
namespace protobuf_sentencepiece_2eproto {
static void InitDefaultsSentencePieceText_SentencePiece() {
GOOGLE_PROTOBUF_VERIFY_VERSION;
{
void* ptr = &::sentencepiece::_SentencePieceText_SentencePiece_default_instance_;
new (ptr) ::sentencepiece::SentencePieceText_SentencePiece();
::google::protobuf::internal::OnShutdownDestroyMessage(ptr);
}
::sentencepiece::SentencePieceText_SentencePiece::InitAsDefaultInstance();
}
::google::protobuf::internal::SCCInfo<0> scc_info_SentencePieceText_SentencePiece =
{{ATOMIC_VAR_INIT(::google::protobuf::internal::SCCInfoBase::kUninitialized), 0, InitDefaultsSentencePieceText_SentencePiece}, {}};
static void InitDefaultsSentencePieceText() {
GOOGLE_PROTOBUF_VERIFY_VERSION;
{
void* ptr = &::sentencepiece::_SentencePieceText_default_instance_;
new (ptr) ::sentencepiece::SentencePieceText();
::google::protobuf::internal::OnShutdownDestroyMessage(ptr);
}
::sentencepiece::SentencePieceText::InitAsDefaultInstance();
}
::google::protobuf::internal::SCCInfo<1> scc_info_SentencePieceText =
{{ATOMIC_VAR_INIT(::google::protobuf::internal::SCCInfoBase::kUninitialized), 1, InitDefaultsSentencePieceText}, {
&protobuf_sentencepiece_2eproto::scc_info_SentencePieceText_SentencePiece.base,}};
static void InitDefaultsNBestSentencePieceText() {
GOOGLE_PROTOBUF_VERIFY_VERSION;
{
void* ptr = &::sentencepiece::_NBestSentencePieceText_default_instance_;
new (ptr) ::sentencepiece::NBestSentencePieceText();
::google::protobuf::internal::OnShutdownDestroyMessage(ptr);
}
::sentencepiece::NBestSentencePieceText::InitAsDefaultInstance();
}
::google::protobuf::internal::SCCInfo<1> scc_info_NBestSentencePieceText =
{{ATOMIC_VAR_INIT(::google::protobuf::internal::SCCInfoBase::kUninitialized), 1, InitDefaultsNBestSentencePieceText}, {
&protobuf_sentencepiece_2eproto::scc_info_SentencePieceText.base,}};
void InitDefaults() {
::google::protobuf::internal::InitSCC(&scc_info_SentencePieceText_SentencePiece.base);
::google::protobuf::internal::InitSCC(&scc_info_SentencePieceText.base);
::google::protobuf::internal::InitSCC(&scc_info_NBestSentencePieceText.base);
}
} // namespace protobuf_sentencepiece_2eproto
namespace sentencepiece {
// ===================================================================
void SentencePieceText_SentencePiece::InitAsDefaultInstance() {
}
#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int SentencePieceText_SentencePiece::kPieceFieldNumber;
const int SentencePieceText_SentencePiece::kIdFieldNumber;
const int SentencePieceText_SentencePiece::kSurfaceFieldNumber;
const int SentencePieceText_SentencePiece::kBeginFieldNumber;
const int SentencePieceText_SentencePiece::kEndFieldNumber;
#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
SentencePieceText_SentencePiece::SentencePieceText_SentencePiece()
: ::google::protobuf::MessageLite(), _internal_metadata_(NULL) {
::google::protobuf::internal::InitSCC(
&protobuf_sentencepiece_2eproto::scc_info_SentencePieceText_SentencePiece.base);
SharedCtor();
// @@protoc_insertion_point(constructor:sentencepiece.SentencePieceText.SentencePiece)
}
SentencePieceText_SentencePiece::SentencePieceText_SentencePiece(const SentencePieceText_SentencePiece& from)
: ::google::protobuf::MessageLite(),
_internal_metadata_(NULL),
_has_bits_(from._has_bits_) {
_internal_metadata_.MergeFrom(from._internal_metadata_);
_extensions_.MergeFrom(from._extensions_);
piece_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
if (from.has_piece()) {
piece_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.piece_);
}
surface_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
if (from.has_surface()) {
surface_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.surface_);
}
::memcpy(&id_, &from.id_,
static_cast<size_t>(reinterpret_cast<char*>(&end_) -
reinterpret_cast<char*>(&id_)) + sizeof(end_));
// @@protoc_insertion_point(copy_constructor:sentencepiece.SentencePieceText.SentencePiece)
}
void SentencePieceText_SentencePiece::SharedCtor() {
piece_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
surface_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
::memset(&id_, 0, static_cast<size_t>(
reinterpret_cast<char*>(&end_) -
reinterpret_cast<char*>(&id_)) + sizeof(end_));
}
SentencePieceText_SentencePiece::~SentencePieceText_SentencePiece() {
// @@protoc_insertion_point(destructor:sentencepiece.SentencePieceText.SentencePiece)
SharedDtor();
}
void SentencePieceText_SentencePiece::SharedDtor() {
piece_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
surface_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
void SentencePieceText_SentencePiece::SetCachedSize(int size) const {
_cached_size_.Set(size);
}
const SentencePieceText_SentencePiece& SentencePieceText_SentencePiece::default_instance() {
::google::protobuf::internal::InitSCC(&protobuf_sentencepiece_2eproto::scc_info_SentencePieceText_SentencePiece.base);
return *internal_default_instance();
}
void SentencePieceText_SentencePiece::Clear() {
// @@protoc_insertion_point(message_clear_start:sentencepiece.SentencePieceText.SentencePiece)
::google::protobuf::uint32 cached_has_bits = 0;
// Prevent compiler warnings about cached_has_bits being unused
(void) cached_has_bits;
_extensions_.Clear();
cached_has_bits = _has_bits_[0];
if (cached_has_bits & 3u) {
if (cached_has_bits & 0x00000001u) {
piece_.ClearNonDefaultToEmptyNoArena();
}
if (cached_has_bits & 0x00000002u) {
surface_.ClearNonDefaultToEmptyNoArena();
}
}
if (cached_has_bits & 28u) {
::memset(&id_, 0, static_cast<size_t>(
reinterpret_cast<char*>(&end_) -
reinterpret_cast<char*>(&id_)) + sizeof(end_));
}
_has_bits_.Clear();
_internal_metadata_.Clear();
}
bool SentencePieceText_SentencePiece::MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input) {
#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
::google::protobuf::uint32 tag;
::google::protobuf::internal::LiteUnknownFieldSetter unknown_fields_setter(
&_internal_metadata_);
::google::protobuf::io::StringOutputStream unknown_fields_output(
unknown_fields_setter.buffer());
::google::protobuf::io::CodedOutputStream unknown_fields_stream(
&unknown_fields_output, false);
// @@protoc_insertion_point(parse_start:sentencepiece.SentencePieceText.SentencePiece)
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)) {
// optional string piece = 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_piece()));
} else {
goto handle_unusual;
}
break;
}
// optional uint32 id = 2;
case 2: {
if (static_cast< ::google::protobuf::uint8>(tag) ==
static_cast< ::google::protobuf::uint8>(16u /* 16 & 0xFF */)) {
set_has_id();
DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
input, &id_)));
} else {
goto handle_unusual;
}
break;
}
// optional string surface = 3;
case 3: {
if (static_cast< ::google::protobuf::uint8>(tag) ==
static_cast< ::google::protobuf::uint8>(26u /* 26 & 0xFF */)) {
DO_(::google::protobuf::internal::WireFormatLite::ReadString(
input, this->mutable_surface()));
} else {
goto handle_unusual;
}
break;
}
// optional uint32 begin = 4;
case 4: {
if (static_cast< ::google::protobuf::uint8>(tag) ==
static_cast< ::google::protobuf::uint8>(32u /* 32 & 0xFF */)) {
set_has_begin();
DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
input, &begin_)));
} else {
goto handle_unusual;
}
break;
}
// optional uint32 end = 5;
case 5: {
if (static_cast< ::google::protobuf::uint8>(tag) ==
static_cast< ::google::protobuf::uint8>(40u /* 40 & 0xFF */)) {
set_has_end();
DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
input, &end_)));
} else {
goto handle_unusual;
}
break;
}
default: {
handle_unusual:
if (tag == 0) {
goto success;
}
if ((1600u <= tag)) {
DO_(_extensions_.ParseField(tag, input,
internal_default_instance(),
&unknown_fields_stream));
continue;
}
DO_(::google::protobuf::internal::WireFormatLite::SkipField(
input, tag, &unknown_fields_stream));
break;
}
}
}
success:
// @@protoc_insertion_point(parse_success:sentencepiece.SentencePieceText.SentencePiece)
return true;
failure:
// @@protoc_insertion_point(parse_failure:sentencepiece.SentencePieceText.SentencePiece)
return false;
#undef DO_
}
void SentencePieceText_SentencePiece::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
// @@protoc_insertion_point(serialize_start:sentencepiece.SentencePieceText.SentencePiece)
::google::protobuf::uint32 cached_has_bits = 0;
(void) cached_has_bits;
cached_has_bits = _has_bits_[0];
// optional string piece = 1;
if (cached_has_bits & 0x00000001u) {
::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
1, this->piece(), output);
}
// optional uint32 id = 2;
if (cached_has_bits & 0x00000004u) {
::google::protobuf::internal::WireFormatLite::WriteUInt32(2, this->id(), output);
}
// optional string surface = 3;
if (cached_has_bits & 0x00000002u) {
::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
3, this->surface(), output);
}
// optional uint32 begin = 4;
if (cached_has_bits & 0x00000008u) {
::google::protobuf::internal::WireFormatLite::WriteUInt32(4, this->begin(), output);
}
// optional uint32 end = 5;
if (cached_has_bits & 0x00000010u) {
::google::protobuf::internal::WireFormatLite::WriteUInt32(5, this->end(), output);
}
// Extension range [200, 536870912)
_extensions_.SerializeWithCachedSizes(
200, 536870912, output);
output->WriteRaw(_internal_metadata_.unknown_fields().data(),
static_cast<int>(_internal_metadata_.unknown_fields().size()));
// @@protoc_insertion_point(serialize_end:sentencepiece.SentencePieceText.SentencePiece)
}
size_t SentencePieceText_SentencePiece::ByteSizeLong() const {
// @@protoc_insertion_point(message_byte_size_start:sentencepiece.SentencePieceText.SentencePiece)
size_t total_size = 0;
total_size += _extensions_.ByteSize();
total_size += _internal_metadata_.unknown_fields().size();
if (_has_bits_[0 / 32] & 31u) {
// optional string piece = 1;
if (has_piece()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->piece());
}
// optional string surface = 3;
if (has_surface()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->surface());
}
// optional uint32 id = 2;
if (has_id()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::UInt32Size(
this->id());
}
// optional uint32 begin = 4;
if (has_begin()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::UInt32Size(
this->begin());
}
// optional uint32 end = 5;
if (has_end()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::UInt32Size(
this->end());
}
}
int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
SetCachedSize(cached_size);
return total_size;
}
void SentencePieceText_SentencePiece::CheckTypeAndMergeFrom(
const ::google::protobuf::MessageLite& from) {
MergeFrom(*::google::protobuf::down_cast<const SentencePieceText_SentencePiece*>(&from));
}
void SentencePieceText_SentencePiece::MergeFrom(const SentencePieceText_SentencePiece& from) {
// @@protoc_insertion_point(class_specific_merge_from_start:sentencepiece.SentencePieceText.SentencePiece)
GOOGLE_DCHECK_NE(&from, this);
_extensions_.MergeFrom(from._extensions_);
_internal_metadata_.MergeFrom(from._internal_metadata_);
::google::protobuf::uint32 cached_has_bits = 0;
(void) cached_has_bits;
cached_has_bits = from._has_bits_[0];
if (cached_has_bits & 31u) {
if (cached_has_bits & 0x00000001u) {
set_has_piece();
piece_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.piece_);
}
if (cached_has_bits & 0x00000002u) {
set_has_surface();
surface_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.surface_);
}
if (cached_has_bits & 0x00000004u) {
id_ = from.id_;
}
if (cached_has_bits & 0x00000008u) {
begin_ = from.begin_;
}
if (cached_has_bits & 0x00000010u) {
end_ = from.end_;
}
_has_bits_[0] |= cached_has_bits;
}
}
void SentencePieceText_SentencePiece::CopyFrom(const SentencePieceText_SentencePiece& from) {
// @@protoc_insertion_point(class_specific_copy_from_start:sentencepiece.SentencePieceText.SentencePiece)
if (&from == this) return;
Clear();
MergeFrom(from);
}
bool SentencePieceText_SentencePiece::IsInitialized() const {
if (!_extensions_.IsInitialized()) {
return false;
}
return true;
}
void SentencePieceText_SentencePiece::Swap(SentencePieceText_SentencePiece* other) {
if (other == this) return;
InternalSwap(other);
}
void SentencePieceText_SentencePiece::InternalSwap(SentencePieceText_SentencePiece* other) {
using std::swap;
piece_.Swap(&other->piece_, &::google::protobuf::internal::GetEmptyStringAlreadyInited(),
GetArenaNoVirtual());
surface_.Swap(&other->surface_, &::google::protobuf::internal::GetEmptyStringAlreadyInited(),
GetArenaNoVirtual());
swap(id_, other->id_);
swap(begin_, other->begin_);
swap(end_, other->end_);
swap(_has_bits_[0], other->_has_bits_[0]);
_internal_metadata_.Swap(&other->_internal_metadata_);
_extensions_.Swap(&other->_extensions_);
}
::std::string SentencePieceText_SentencePiece::GetTypeName() const {
return "sentencepiece.SentencePieceText.SentencePiece";
}
// ===================================================================
void SentencePieceText::InitAsDefaultInstance() {
}
#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int SentencePieceText::kTextFieldNumber;
const int SentencePieceText::kPiecesFieldNumber;
const int SentencePieceText::kScoreFieldNumber;
#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
SentencePieceText::SentencePieceText()
: ::google::protobuf::MessageLite(), _internal_metadata_(NULL) {
::google::protobuf::internal::InitSCC(
&protobuf_sentencepiece_2eproto::scc_info_SentencePieceText.base);
SharedCtor();
// @@protoc_insertion_point(constructor:sentencepiece.SentencePieceText)
}
SentencePieceText::SentencePieceText(const SentencePieceText& from)
: ::google::protobuf::MessageLite(),
_internal_metadata_(NULL),
_has_bits_(from._has_bits_),
pieces_(from.pieces_) {
_internal_metadata_.MergeFrom(from._internal_metadata_);
_extensions_.MergeFrom(from._extensions_);
text_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
if (from.has_text()) {
text_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.text_);
}
score_ = from.score_;
// @@protoc_insertion_point(copy_constructor:sentencepiece.SentencePieceText)
}
void SentencePieceText::SharedCtor() {
text_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
score_ = 0;
}
SentencePieceText::~SentencePieceText() {
// @@protoc_insertion_point(destructor:sentencepiece.SentencePieceText)
SharedDtor();
}
void SentencePieceText::SharedDtor() {
text_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
void SentencePieceText::SetCachedSize(int size) const {
_cached_size_.Set(size);
}
const SentencePieceText& SentencePieceText::default_instance() {
::google::protobuf::internal::InitSCC(&protobuf_sentencepiece_2eproto::scc_info_SentencePieceText.base);
return *internal_default_instance();
}
void SentencePieceText::Clear() {
// @@protoc_insertion_point(message_clear_start:sentencepiece.SentencePieceText)
::google::protobuf::uint32 cached_has_bits = 0;
// Prevent compiler warnings about cached_has_bits being unused
(void) cached_has_bits;
_extensions_.Clear();
pieces_.Clear();
cached_has_bits = _has_bits_[0];
if (cached_has_bits & 0x00000001u) {
text_.ClearNonDefaultToEmptyNoArena();
}
score_ = 0;
_has_bits_.Clear();
_internal_metadata_.Clear();
}
bool SentencePieceText::MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input) {
#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
::google::protobuf::uint32 tag;
::google::protobuf::internal::LiteUnknownFieldSetter unknown_fields_setter(
&_internal_metadata_);
::google::protobuf::io::StringOutputStream unknown_fields_output(
unknown_fields_setter.buffer());
::google::protobuf::io::CodedOutputStream unknown_fields_stream(
&unknown_fields_output, false);
// @@protoc_insertion_point(parse_start:sentencepiece.SentencePieceText)
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)) {
// optional string text = 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_text()));
} else {
goto handle_unusual;
}
break;
}
// repeated .sentencepiece.SentencePieceText.SentencePiece pieces = 2;
case 2: {
if (static_cast< ::google::protobuf::uint8>(tag) ==
static_cast< ::google::protobuf::uint8>(18u /* 18 & 0xFF */)) {
DO_(::google::protobuf::internal::WireFormatLite::ReadMessage(
input, add_pieces()));
} else {
goto handle_unusual;
}
break;
}
// optional float score = 3;
case 3: {
if (static_cast< ::google::protobuf::uint8>(tag) ==
static_cast< ::google::protobuf::uint8>(29u /* 29 & 0xFF */)) {
set_has_score();
DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
input, &score_)));
} else {
goto handle_unusual;
}
break;
}
default: {
handle_unusual:
if (tag == 0) {
goto success;
}
if ((1600u <= tag)) {
DO_(_extensions_.ParseField(tag, input,
internal_default_instance(),
&unknown_fields_stream));
continue;
}
DO_(::google::protobuf::internal::WireFormatLite::SkipField(
input, tag, &unknown_fields_stream));
break;
}
}
}
success:
// @@protoc_insertion_point(parse_success:sentencepiece.SentencePieceText)
return true;
failure:
// @@protoc_insertion_point(parse_failure:sentencepiece.SentencePieceText)
return false;
#undef DO_
}
void SentencePieceText::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
// @@protoc_insertion_point(serialize_start:sentencepiece.SentencePieceText)
::google::protobuf::uint32 cached_has_bits = 0;
(void) cached_has_bits;
cached_has_bits = _has_bits_[0];
// optional string text = 1;
if (cached_has_bits & 0x00000001u) {
::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
1, this->text(), output);
}
// repeated .sentencepiece.SentencePieceText.SentencePiece pieces = 2;
for (unsigned int i = 0,
n = static_cast<unsigned int>(this->pieces_size()); i < n; i++) {
::google::protobuf::internal::WireFormatLite::WriteMessage(
2,
this->pieces(static_cast<int>(i)),
output);
}
// optional float score = 3;
if (cached_has_bits & 0x00000002u) {
::google::protobuf::internal::WireFormatLite::WriteFloat(3, this->score(), output);
}
// Extension range [200, 536870912)
_extensions_.SerializeWithCachedSizes(
200, 536870912, output);
output->WriteRaw(_internal_metadata_.unknown_fields().data(),
static_cast<int>(_internal_metadata_.unknown_fields().size()));
// @@protoc_insertion_point(serialize_end:sentencepiece.SentencePieceText)
}
size_t SentencePieceText::ByteSizeLong() const {
// @@protoc_insertion_point(message_byte_size_start:sentencepiece.SentencePieceText)
size_t total_size = 0;
total_size += _extensions_.ByteSize();
total_size += _internal_metadata_.unknown_fields().size();
// repeated .sentencepiece.SentencePieceText.SentencePiece pieces = 2;
{
unsigned int count = static_cast<unsigned int>(this->pieces_size());
total_size += 1UL * count;
for (unsigned int i = 0; i < count; i++) {
total_size +=
::google::protobuf::internal::WireFormatLite::MessageSize(
this->pieces(static_cast<int>(i)));
}
}
if (_has_bits_[0 / 32] & 3u) {
// optional string text = 1;
if (has_text()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->text());
}
// optional float score = 3;
if (has_score()) {
total_size += 1 + 4;
}
}
int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
SetCachedSize(cached_size);
return total_size;
}
void SentencePieceText::CheckTypeAndMergeFrom(
const ::google::protobuf::MessageLite& from) {
MergeFrom(*::google::protobuf::down_cast<const SentencePieceText*>(&from));
}
void SentencePieceText::MergeFrom(const SentencePieceText& from) {
// @@protoc_insertion_point(class_specific_merge_from_start:sentencepiece.SentencePieceText)
GOOGLE_DCHECK_NE(&from, this);
_extensions_.MergeFrom(from._extensions_);
_internal_metadata_.MergeFrom(from._internal_metadata_);
::google::protobuf::uint32 cached_has_bits = 0;
(void) cached_has_bits;
pieces_.MergeFrom(from.pieces_);
cached_has_bits = from._has_bits_[0];
if (cached_has_bits & 3u) {
if (cached_has_bits & 0x00000001u) {
set_has_text();
text_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.text_);
}
if (cached_has_bits & 0x00000002u) {
score_ = from.score_;
}
_has_bits_[0] |= cached_has_bits;
}
}
void SentencePieceText::CopyFrom(const SentencePieceText& from) {
// @@protoc_insertion_point(class_specific_copy_from_start:sentencepiece.SentencePieceText)
if (&from == this) return;
Clear();
MergeFrom(from);
}
bool SentencePieceText::IsInitialized() const {
if (!_extensions_.IsInitialized()) {
return false;
}
if (!::google::protobuf::internal::AllAreInitialized(this->pieces())) return false;
return true;
}
void SentencePieceText::Swap(SentencePieceText* other) {
if (other == this) return;
InternalSwap(other);
}
void SentencePieceText::InternalSwap(SentencePieceText* other) {
using std::swap;
CastToBase(&pieces_)->InternalSwap(CastToBase(&other->pieces_));
text_.Swap(&other->text_, &::google::protobuf::internal::GetEmptyStringAlreadyInited(),
GetArenaNoVirtual());
swap(score_, other->score_);
swap(_has_bits_[0], other->_has_bits_[0]);
_internal_metadata_.Swap(&other->_internal_metadata_);
_extensions_.Swap(&other->_extensions_);
}
::std::string SentencePieceText::GetTypeName() const {
return "sentencepiece.SentencePieceText";
}
// ===================================================================
void NBestSentencePieceText::InitAsDefaultInstance() {
}
#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int NBestSentencePieceText::kNbestsFieldNumber;
#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
NBestSentencePieceText::NBestSentencePieceText()
: ::google::protobuf::MessageLite(), _internal_metadata_(NULL) {
::google::protobuf::internal::InitSCC(
&protobuf_sentencepiece_2eproto::scc_info_NBestSentencePieceText.base);
SharedCtor();
// @@protoc_insertion_point(constructor:sentencepiece.NBestSentencePieceText)
}
NBestSentencePieceText::NBestSentencePieceText(const NBestSentencePieceText& from)
: ::google::protobuf::MessageLite(),
_internal_metadata_(NULL),
_has_bits_(from._has_bits_),
nbests_(from.nbests_) {
_internal_metadata_.MergeFrom(from._internal_metadata_);
// @@protoc_insertion_point(copy_constructor:sentencepiece.NBestSentencePieceText)
}
void NBestSentencePieceText::SharedCtor() {
}
NBestSentencePieceText::~NBestSentencePieceText() {
// @@protoc_insertion_point(destructor:sentencepiece.NBestSentencePieceText)
SharedDtor();
}
void NBestSentencePieceText::SharedDtor() {
}
void NBestSentencePieceText::SetCachedSize(int size) const {
_cached_size_.Set(size);
}
const NBestSentencePieceText& NBestSentencePieceText::default_instance() {
::google::protobuf::internal::InitSCC(&protobuf_sentencepiece_2eproto::scc_info_NBestSentencePieceText.base);
return *internal_default_instance();
}
void NBestSentencePieceText::Clear() {
// @@protoc_insertion_point(message_clear_start:sentencepiece.NBestSentencePieceText)
::google::protobuf::uint32 cached_has_bits = 0;
// Prevent compiler warnings about cached_has_bits being unused
(void) cached_has_bits;
nbests_.Clear();
_has_bits_.Clear();
_internal_metadata_.Clear();
}
bool NBestSentencePieceText::MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input) {
#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
::google::protobuf::uint32 tag;
::google::protobuf::internal::LiteUnknownFieldSetter unknown_fields_setter(
&_internal_metadata_);
::google::protobuf::io::StringOutputStream unknown_fields_output(
unknown_fields_setter.buffer());
::google::protobuf::io::CodedOutputStream unknown_fields_stream(
&unknown_fields_output, false);
// @@protoc_insertion_point(parse_start:sentencepiece.NBestSentencePieceText)
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 .sentencepiece.SentencePieceText nbests = 1;
case 1: {
if (static_cast< ::google::protobuf::uint8>(tag) ==
static_cast< ::google::protobuf::uint8>(10u /* 10 & 0xFF */)) {
DO_(::google::protobuf::internal::WireFormatLite::ReadMessage(
input, add_nbests()));
} else {
goto handle_unusual;
}
break;
}
default: {
handle_unusual:
if (tag == 0) {
goto success;
}
DO_(::google::protobuf::internal::WireFormatLite::SkipField(
input, tag, &unknown_fields_stream));
break;
}
}
}
success:
// @@protoc_insertion_point(parse_success:sentencepiece.NBestSentencePieceText)
return true;
failure:
// @@protoc_insertion_point(parse_failure:sentencepiece.NBestSentencePieceText)
return false;
#undef DO_
}
void NBestSentencePieceText::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
// @@protoc_insertion_point(serialize_start:sentencepiece.NBestSentencePieceText)
::google::protobuf::uint32 cached_has_bits = 0;
(void) cached_has_bits;
// repeated .sentencepiece.SentencePieceText nbests = 1;
for (unsigned int i = 0,
n = static_cast<unsigned int>(this->nbests_size()); i < n; i++) {
::google::protobuf::internal::WireFormatLite::WriteMessage(
1,
this->nbests(static_cast<int>(i)),
output);
}
output->WriteRaw(_internal_metadata_.unknown_fields().data(),
static_cast<int>(_internal_metadata_.unknown_fields().size()));
// @@protoc_insertion_point(serialize_end:sentencepiece.NBestSentencePieceText)
}
size_t NBestSentencePieceText::ByteSizeLong() const {
// @@protoc_insertion_point(message_byte_size_start:sentencepiece.NBestSentencePieceText)
size_t total_size = 0;
total_size += _internal_metadata_.unknown_fields().size();
// repeated .sentencepiece.SentencePieceText nbests = 1;
{
unsigned int count = static_cast<unsigned int>(this->nbests_size());
total_size += 1UL * count;
for (unsigned int i = 0; i < count; i++) {
total_size +=
::google::protobuf::internal::WireFormatLite::MessageSize(
this->nbests(static_cast<int>(i)));
}
}
int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
SetCachedSize(cached_size);
return total_size;
}
void NBestSentencePieceText::CheckTypeAndMergeFrom(
const ::google::protobuf::MessageLite& from) {
MergeFrom(*::google::protobuf::down_cast<const NBestSentencePieceText*>(&from));
}
void NBestSentencePieceText::MergeFrom(const NBestSentencePieceText& from) {
// @@protoc_insertion_point(class_specific_merge_from_start:sentencepiece.NBestSentencePieceText)
GOOGLE_DCHECK_NE(&from, this);
_internal_metadata_.MergeFrom(from._internal_metadata_);
::google::protobuf::uint32 cached_has_bits = 0;
(void) cached_has_bits;
nbests_.MergeFrom(from.nbests_);
}
void NBestSentencePieceText::CopyFrom(const NBestSentencePieceText& from) {
// @@protoc_insertion_point(class_specific_copy_from_start:sentencepiece.NBestSentencePieceText)
if (&from == this) return;
Clear();
MergeFrom(from);
}
bool NBestSentencePieceText::IsInitialized() const {
if (!::google::protobuf::internal::AllAreInitialized(this->nbests())) return false;
return true;
}
void NBestSentencePieceText::Swap(NBestSentencePieceText* other) {
if (other == this) return;
InternalSwap(other);
}
void NBestSentencePieceText::InternalSwap(NBestSentencePieceText* other) {
using std::swap;
CastToBase(&nbests_)->InternalSwap(CastToBase(&other->nbests_));
swap(_has_bits_[0], other->_has_bits_[0]);
_internal_metadata_.Swap(&other->_internal_metadata_);
}
::std::string NBestSentencePieceText::GetTypeName() const {
return "sentencepiece.NBestSentencePieceText";
}
// @@protoc_insertion_point(namespace_scope)
} // namespace sentencepiece
namespace google {
namespace protobuf {
template<> GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE ::sentencepiece::SentencePieceText_SentencePiece* Arena::CreateMaybeMessage< ::sentencepiece::SentencePieceText_SentencePiece >(Arena* arena) {
return Arena::CreateInternal< ::sentencepiece::SentencePieceText_SentencePiece >(arena);
}
template<> GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE ::sentencepiece::SentencePieceText* Arena::CreateMaybeMessage< ::sentencepiece::SentencePieceText >(Arena* arena) {
return Arena::CreateInternal< ::sentencepiece::SentencePieceText >(arena);
}
template<> GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE ::sentencepiece::NBestSentencePieceText* Arena::CreateMaybeMessage< ::sentencepiece::NBestSentencePieceText >(Arena* arena) {
return Arena::CreateInternal< ::sentencepiece::NBestSentencePieceText >(arena);
}
} // namespace protobuf
} // namespace google
// @@protoc_insertion_point(global_scope)

View File

@ -0,0 +1,887 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: sentencepiece.proto
#ifndef PROTOBUF_INCLUDED_sentencepiece_2eproto
#define PROTOBUF_INCLUDED_sentencepiece_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_lite.h>
#include <google/protobuf/message_lite.h>
#include <google/protobuf/repeated_field.h> // IWYU pragma: export
#include <google/protobuf/extension_set.h> // IWYU pragma: export
// @@protoc_insertion_point(includes)
#define PROTOBUF_INTERNAL_EXPORT_protobuf_sentencepiece_2eproto
namespace protobuf_sentencepiece_2eproto {
// Internal implementation detail -- do not use these members.
struct TableStruct {
static const ::google::protobuf::internal::ParseTableField entries[];
static const ::google::protobuf::internal::AuxillaryParseTableField aux[];
static const ::google::protobuf::internal::ParseTable schema[3];
static const ::google::protobuf::internal::FieldMetadata field_metadata[];
static const ::google::protobuf::internal::SerializationTable serialization_table[];
static const ::google::protobuf::uint32 offsets[];
};
} // namespace protobuf_sentencepiece_2eproto
namespace sentencepiece {
class NBestSentencePieceText;
class NBestSentencePieceTextDefaultTypeInternal;
extern NBestSentencePieceTextDefaultTypeInternal _NBestSentencePieceText_default_instance_;
class SentencePieceText;
class SentencePieceTextDefaultTypeInternal;
extern SentencePieceTextDefaultTypeInternal _SentencePieceText_default_instance_;
class SentencePieceText_SentencePiece;
class SentencePieceText_SentencePieceDefaultTypeInternal;
extern SentencePieceText_SentencePieceDefaultTypeInternal _SentencePieceText_SentencePiece_default_instance_;
} // namespace sentencepiece
namespace google {
namespace protobuf {
template<> ::sentencepiece::NBestSentencePieceText* Arena::CreateMaybeMessage<::sentencepiece::NBestSentencePieceText>(Arena*);
template<> ::sentencepiece::SentencePieceText* Arena::CreateMaybeMessage<::sentencepiece::SentencePieceText>(Arena*);
template<> ::sentencepiece::SentencePieceText_SentencePiece* Arena::CreateMaybeMessage<::sentencepiece::SentencePieceText_SentencePiece>(Arena*);
} // namespace protobuf
} // namespace google
namespace sentencepiece {
// ===================================================================
class SentencePieceText_SentencePiece : public ::google::protobuf::MessageLite /* @@protoc_insertion_point(class_definition:sentencepiece.SentencePieceText.SentencePiece) */ {
public:
SentencePieceText_SentencePiece();
virtual ~SentencePieceText_SentencePiece();
SentencePieceText_SentencePiece(const SentencePieceText_SentencePiece& from);
inline SentencePieceText_SentencePiece& operator=(const SentencePieceText_SentencePiece& from) {
CopyFrom(from);
return *this;
}
#if LANG_CXX11
SentencePieceText_SentencePiece(SentencePieceText_SentencePiece&& from) noexcept
: SentencePieceText_SentencePiece() {
*this = ::std::move(from);
}
inline SentencePieceText_SentencePiece& operator=(SentencePieceText_SentencePiece&& from) noexcept {
if (GetArenaNoVirtual() == from.GetArenaNoVirtual()) {
if (this != &from) InternalSwap(&from);
} else {
CopyFrom(from);
}
return *this;
}
#endif
inline const ::std::string& unknown_fields() const {
return _internal_metadata_.unknown_fields();
}
inline ::std::string* mutable_unknown_fields() {
return _internal_metadata_.mutable_unknown_fields();
}
static const SentencePieceText_SentencePiece& default_instance();
static void InitAsDefaultInstance(); // FOR INTERNAL USE ONLY
static inline const SentencePieceText_SentencePiece* internal_default_instance() {
return reinterpret_cast<const SentencePieceText_SentencePiece*>(
&_SentencePieceText_SentencePiece_default_instance_);
}
static constexpr int kIndexInFileMessages =
0;
void Swap(SentencePieceText_SentencePiece* other);
friend void swap(SentencePieceText_SentencePiece& a, SentencePieceText_SentencePiece& b) {
a.Swap(&b);
}
// implements Message ----------------------------------------------
inline SentencePieceText_SentencePiece* New() const final {
return CreateMaybeMessage<SentencePieceText_SentencePiece>(NULL);
}
SentencePieceText_SentencePiece* New(::google::protobuf::Arena* arena) const final {
return CreateMaybeMessage<SentencePieceText_SentencePiece>(arena);
}
void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from)
final;
void CopyFrom(const SentencePieceText_SentencePiece& from);
void MergeFrom(const SentencePieceText_SentencePiece& 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;
void DiscardUnknownFields();
int GetCachedSize() const final { return _cached_size_.Get(); }
private:
void SharedCtor();
void SharedDtor();
void SetCachedSize(int size) const;
void InternalSwap(SentencePieceText_SentencePiece* other);
private:
inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
return NULL;
}
inline void* MaybeArenaPtr() const {
return NULL;
}
public:
::std::string GetTypeName() const final;
// nested types ----------------------------------------------------
// accessors -------------------------------------------------------
// optional string piece = 1;
bool has_piece() const;
void clear_piece();
static const int kPieceFieldNumber = 1;
const ::std::string& piece() const;
void set_piece(const ::std::string& value);
#if LANG_CXX11
void set_piece(::std::string&& value);
#endif
void set_piece(const char* value);
void set_piece(const char* value, size_t size);
::std::string* mutable_piece();
::std::string* release_piece();
void set_allocated_piece(::std::string* piece);
// optional string surface = 3;
bool has_surface() const;
void clear_surface();
static const int kSurfaceFieldNumber = 3;
const ::std::string& surface() const;
void set_surface(const ::std::string& value);
#if LANG_CXX11
void set_surface(::std::string&& value);
#endif
void set_surface(const char* value);
void set_surface(const char* value, size_t size);
::std::string* mutable_surface();
::std::string* release_surface();
void set_allocated_surface(::std::string* surface);
// optional uint32 id = 2;
bool has_id() const;
void clear_id();
static const int kIdFieldNumber = 2;
::google::protobuf::uint32 id() const;
void set_id(::google::protobuf::uint32 value);
// optional uint32 begin = 4;
bool has_begin() const;
void clear_begin();
static const int kBeginFieldNumber = 4;
::google::protobuf::uint32 begin() const;
void set_begin(::google::protobuf::uint32 value);
// optional uint32 end = 5;
bool has_end() const;
void clear_end();
static const int kEndFieldNumber = 5;
::google::protobuf::uint32 end() const;
void set_end(::google::protobuf::uint32 value);
GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(SentencePieceText_SentencePiece)
// @@protoc_insertion_point(class_scope:sentencepiece.SentencePieceText.SentencePiece)
private:
void set_has_piece();
void clear_has_piece();
void set_has_id();
void clear_has_id();
void set_has_surface();
void clear_has_surface();
void set_has_begin();
void clear_has_begin();
void set_has_end();
void clear_has_end();
::google::protobuf::internal::ExtensionSet _extensions_;
::google::protobuf::internal::InternalMetadataWithArenaLite _internal_metadata_;
::google::protobuf::internal::HasBits<1> _has_bits_;
mutable ::google::protobuf::internal::CachedSize _cached_size_;
::google::protobuf::internal::ArenaStringPtr piece_;
::google::protobuf::internal::ArenaStringPtr surface_;
::google::protobuf::uint32 id_;
::google::protobuf::uint32 begin_;
::google::protobuf::uint32 end_;
friend struct ::protobuf_sentencepiece_2eproto::TableStruct;
};
// -------------------------------------------------------------------
class SentencePieceText : public ::google::protobuf::MessageLite /* @@protoc_insertion_point(class_definition:sentencepiece.SentencePieceText) */ {
public:
SentencePieceText();
virtual ~SentencePieceText();
SentencePieceText(const SentencePieceText& from);
inline SentencePieceText& operator=(const SentencePieceText& from) {
CopyFrom(from);
return *this;
}
#if LANG_CXX11
SentencePieceText(SentencePieceText&& from) noexcept
: SentencePieceText() {
*this = ::std::move(from);
}
inline SentencePieceText& operator=(SentencePieceText&& from) noexcept {
if (GetArenaNoVirtual() == from.GetArenaNoVirtual()) {
if (this != &from) InternalSwap(&from);
} else {
CopyFrom(from);
}
return *this;
}
#endif
inline const ::std::string& unknown_fields() const {
return _internal_metadata_.unknown_fields();
}
inline ::std::string* mutable_unknown_fields() {
return _internal_metadata_.mutable_unknown_fields();
}
static const SentencePieceText& default_instance();
static void InitAsDefaultInstance(); // FOR INTERNAL USE ONLY
static inline const SentencePieceText* internal_default_instance() {
return reinterpret_cast<const SentencePieceText*>(
&_SentencePieceText_default_instance_);
}
static constexpr int kIndexInFileMessages =
1;
void Swap(SentencePieceText* other);
friend void swap(SentencePieceText& a, SentencePieceText& b) {
a.Swap(&b);
}
// implements Message ----------------------------------------------
inline SentencePieceText* New() const final {
return CreateMaybeMessage<SentencePieceText>(NULL);
}
SentencePieceText* New(::google::protobuf::Arena* arena) const final {
return CreateMaybeMessage<SentencePieceText>(arena);
}
void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from)
final;
void CopyFrom(const SentencePieceText& from);
void MergeFrom(const SentencePieceText& 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;
void DiscardUnknownFields();
int GetCachedSize() const final { return _cached_size_.Get(); }
private:
void SharedCtor();
void SharedDtor();
void SetCachedSize(int size) const;
void InternalSwap(SentencePieceText* other);
private:
inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
return NULL;
}
inline void* MaybeArenaPtr() const {
return NULL;
}
public:
::std::string GetTypeName() const final;
// nested types ----------------------------------------------------
typedef SentencePieceText_SentencePiece SentencePiece;
// accessors -------------------------------------------------------
// repeated .sentencepiece.SentencePieceText.SentencePiece pieces = 2;
int pieces_size() const;
void clear_pieces();
static const int kPiecesFieldNumber = 2;
::sentencepiece::SentencePieceText_SentencePiece* mutable_pieces(int index);
::google::protobuf::RepeatedPtrField< ::sentencepiece::SentencePieceText_SentencePiece >*
mutable_pieces();
const ::sentencepiece::SentencePieceText_SentencePiece& pieces(int index) const;
::sentencepiece::SentencePieceText_SentencePiece* add_pieces();
const ::google::protobuf::RepeatedPtrField< ::sentencepiece::SentencePieceText_SentencePiece >&
pieces() const;
// optional string text = 1;
bool has_text() const;
void clear_text();
static const int kTextFieldNumber = 1;
const ::std::string& text() const;
void set_text(const ::std::string& value);
#if LANG_CXX11
void set_text(::std::string&& value);
#endif
void set_text(const char* value);
void set_text(const char* value, size_t size);
::std::string* mutable_text();
::std::string* release_text();
void set_allocated_text(::std::string* text);
// optional float score = 3;
bool has_score() const;
void clear_score();
static const int kScoreFieldNumber = 3;
float score() const;
void set_score(float value);
GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(SentencePieceText)
// @@protoc_insertion_point(class_scope:sentencepiece.SentencePieceText)
private:
void set_has_text();
void clear_has_text();
void set_has_score();
void clear_has_score();
::google::protobuf::internal::ExtensionSet _extensions_;
::google::protobuf::internal::InternalMetadataWithArenaLite _internal_metadata_;
::google::protobuf::internal::HasBits<1> _has_bits_;
mutable ::google::protobuf::internal::CachedSize _cached_size_;
::google::protobuf::RepeatedPtrField< ::sentencepiece::SentencePieceText_SentencePiece > pieces_;
::google::protobuf::internal::ArenaStringPtr text_;
float score_;
friend struct ::protobuf_sentencepiece_2eproto::TableStruct;
};
// -------------------------------------------------------------------
class NBestSentencePieceText : public ::google::protobuf::MessageLite /* @@protoc_insertion_point(class_definition:sentencepiece.NBestSentencePieceText) */ {
public:
NBestSentencePieceText();
virtual ~NBestSentencePieceText();
NBestSentencePieceText(const NBestSentencePieceText& from);
inline NBestSentencePieceText& operator=(const NBestSentencePieceText& from) {
CopyFrom(from);
return *this;
}
#if LANG_CXX11
NBestSentencePieceText(NBestSentencePieceText&& from) noexcept
: NBestSentencePieceText() {
*this = ::std::move(from);
}
inline NBestSentencePieceText& operator=(NBestSentencePieceText&& from) noexcept {
if (GetArenaNoVirtual() == from.GetArenaNoVirtual()) {
if (this != &from) InternalSwap(&from);
} else {
CopyFrom(from);
}
return *this;
}
#endif
inline const ::std::string& unknown_fields() const {
return _internal_metadata_.unknown_fields();
}
inline ::std::string* mutable_unknown_fields() {
return _internal_metadata_.mutable_unknown_fields();
}
static const NBestSentencePieceText& default_instance();
static void InitAsDefaultInstance(); // FOR INTERNAL USE ONLY
static inline const NBestSentencePieceText* internal_default_instance() {
return reinterpret_cast<const NBestSentencePieceText*>(
&_NBestSentencePieceText_default_instance_);
}
static constexpr int kIndexInFileMessages =
2;
void Swap(NBestSentencePieceText* other);
friend void swap(NBestSentencePieceText& a, NBestSentencePieceText& b) {
a.Swap(&b);
}
// implements Message ----------------------------------------------
inline NBestSentencePieceText* New() const final {
return CreateMaybeMessage<NBestSentencePieceText>(NULL);
}
NBestSentencePieceText* New(::google::protobuf::Arena* arena) const final {
return CreateMaybeMessage<NBestSentencePieceText>(arena);
}
void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from)
final;
void CopyFrom(const NBestSentencePieceText& from);
void MergeFrom(const NBestSentencePieceText& 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;
void DiscardUnknownFields();
int GetCachedSize() const final { return _cached_size_.Get(); }
private:
void SharedCtor();
void SharedDtor();
void SetCachedSize(int size) const;
void InternalSwap(NBestSentencePieceText* other);
private:
inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
return NULL;
}
inline void* MaybeArenaPtr() const {
return NULL;
}
public:
::std::string GetTypeName() const final;
// nested types ----------------------------------------------------
// accessors -------------------------------------------------------
// repeated .sentencepiece.SentencePieceText nbests = 1;
int nbests_size() const;
void clear_nbests();
static const int kNbestsFieldNumber = 1;
::sentencepiece::SentencePieceText* mutable_nbests(int index);
::google::protobuf::RepeatedPtrField< ::sentencepiece::SentencePieceText >*
mutable_nbests();
const ::sentencepiece::SentencePieceText& nbests(int index) const;
::sentencepiece::SentencePieceText* add_nbests();
const ::google::protobuf::RepeatedPtrField< ::sentencepiece::SentencePieceText >&
nbests() const;
// @@protoc_insertion_point(class_scope:sentencepiece.NBestSentencePieceText)
private:
::google::protobuf::internal::InternalMetadataWithArenaLite _internal_metadata_;
::google::protobuf::internal::HasBits<1> _has_bits_;
mutable ::google::protobuf::internal::CachedSize _cached_size_;
::google::protobuf::RepeatedPtrField< ::sentencepiece::SentencePieceText > nbests_;
friend struct ::protobuf_sentencepiece_2eproto::TableStruct;
};
// ===================================================================
// ===================================================================
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif // __GNUC__
// SentencePieceText_SentencePiece
// optional string piece = 1;
inline bool SentencePieceText_SentencePiece::has_piece() const {
return (_has_bits_[0] & 0x00000001u) != 0;
}
inline void SentencePieceText_SentencePiece::set_has_piece() {
_has_bits_[0] |= 0x00000001u;
}
inline void SentencePieceText_SentencePiece::clear_has_piece() {
_has_bits_[0] &= ~0x00000001u;
}
inline void SentencePieceText_SentencePiece::clear_piece() {
piece_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
clear_has_piece();
}
inline const ::std::string& SentencePieceText_SentencePiece::piece() const {
// @@protoc_insertion_point(field_get:sentencepiece.SentencePieceText.SentencePiece.piece)
return piece_.GetNoArena();
}
inline void SentencePieceText_SentencePiece::set_piece(const ::std::string& value) {
set_has_piece();
piece_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
// @@protoc_insertion_point(field_set:sentencepiece.SentencePieceText.SentencePiece.piece)
}
#if LANG_CXX11
inline void SentencePieceText_SentencePiece::set_piece(::std::string&& value) {
set_has_piece();
piece_.SetNoArena(
&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::move(value));
// @@protoc_insertion_point(field_set_rvalue:sentencepiece.SentencePieceText.SentencePiece.piece)
}
#endif
inline void SentencePieceText_SentencePiece::set_piece(const char* value) {
GOOGLE_DCHECK(value != NULL);
set_has_piece();
piece_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
// @@protoc_insertion_point(field_set_char:sentencepiece.SentencePieceText.SentencePiece.piece)
}
inline void SentencePieceText_SentencePiece::set_piece(const char* value, size_t size) {
set_has_piece();
piece_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
::std::string(reinterpret_cast<const char*>(value), size));
// @@protoc_insertion_point(field_set_pointer:sentencepiece.SentencePieceText.SentencePiece.piece)
}
inline ::std::string* SentencePieceText_SentencePiece::mutable_piece() {
set_has_piece();
// @@protoc_insertion_point(field_mutable:sentencepiece.SentencePieceText.SentencePiece.piece)
return piece_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline ::std::string* SentencePieceText_SentencePiece::release_piece() {
// @@protoc_insertion_point(field_release:sentencepiece.SentencePieceText.SentencePiece.piece)
if (!has_piece()) {
return NULL;
}
clear_has_piece();
return piece_.ReleaseNonDefaultNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline void SentencePieceText_SentencePiece::set_allocated_piece(::std::string* piece) {
if (piece != NULL) {
set_has_piece();
} else {
clear_has_piece();
}
piece_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), piece);
// @@protoc_insertion_point(field_set_allocated:sentencepiece.SentencePieceText.SentencePiece.piece)
}
// optional uint32 id = 2;
inline bool SentencePieceText_SentencePiece::has_id() const {
return (_has_bits_[0] & 0x00000004u) != 0;
}
inline void SentencePieceText_SentencePiece::set_has_id() {
_has_bits_[0] |= 0x00000004u;
}
inline void SentencePieceText_SentencePiece::clear_has_id() {
_has_bits_[0] &= ~0x00000004u;
}
inline void SentencePieceText_SentencePiece::clear_id() {
id_ = 0u;
clear_has_id();
}
inline ::google::protobuf::uint32 SentencePieceText_SentencePiece::id() const {
// @@protoc_insertion_point(field_get:sentencepiece.SentencePieceText.SentencePiece.id)
return id_;
}
inline void SentencePieceText_SentencePiece::set_id(::google::protobuf::uint32 value) {
set_has_id();
id_ = value;
// @@protoc_insertion_point(field_set:sentencepiece.SentencePieceText.SentencePiece.id)
}
// optional string surface = 3;
inline bool SentencePieceText_SentencePiece::has_surface() const {
return (_has_bits_[0] & 0x00000002u) != 0;
}
inline void SentencePieceText_SentencePiece::set_has_surface() {
_has_bits_[0] |= 0x00000002u;
}
inline void SentencePieceText_SentencePiece::clear_has_surface() {
_has_bits_[0] &= ~0x00000002u;
}
inline void SentencePieceText_SentencePiece::clear_surface() {
surface_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
clear_has_surface();
}
inline const ::std::string& SentencePieceText_SentencePiece::surface() const {
// @@protoc_insertion_point(field_get:sentencepiece.SentencePieceText.SentencePiece.surface)
return surface_.GetNoArena();
}
inline void SentencePieceText_SentencePiece::set_surface(const ::std::string& value) {
set_has_surface();
surface_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
// @@protoc_insertion_point(field_set:sentencepiece.SentencePieceText.SentencePiece.surface)
}
#if LANG_CXX11
inline void SentencePieceText_SentencePiece::set_surface(::std::string&& value) {
set_has_surface();
surface_.SetNoArena(
&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::move(value));
// @@protoc_insertion_point(field_set_rvalue:sentencepiece.SentencePieceText.SentencePiece.surface)
}
#endif
inline void SentencePieceText_SentencePiece::set_surface(const char* value) {
GOOGLE_DCHECK(value != NULL);
set_has_surface();
surface_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
// @@protoc_insertion_point(field_set_char:sentencepiece.SentencePieceText.SentencePiece.surface)
}
inline void SentencePieceText_SentencePiece::set_surface(const char* value, size_t size) {
set_has_surface();
surface_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
::std::string(reinterpret_cast<const char*>(value), size));
// @@protoc_insertion_point(field_set_pointer:sentencepiece.SentencePieceText.SentencePiece.surface)
}
inline ::std::string* SentencePieceText_SentencePiece::mutable_surface() {
set_has_surface();
// @@protoc_insertion_point(field_mutable:sentencepiece.SentencePieceText.SentencePiece.surface)
return surface_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline ::std::string* SentencePieceText_SentencePiece::release_surface() {
// @@protoc_insertion_point(field_release:sentencepiece.SentencePieceText.SentencePiece.surface)
if (!has_surface()) {
return NULL;
}
clear_has_surface();
return surface_.ReleaseNonDefaultNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline void SentencePieceText_SentencePiece::set_allocated_surface(::std::string* surface) {
if (surface != NULL) {
set_has_surface();
} else {
clear_has_surface();
}
surface_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), surface);
// @@protoc_insertion_point(field_set_allocated:sentencepiece.SentencePieceText.SentencePiece.surface)
}
// optional uint32 begin = 4;
inline bool SentencePieceText_SentencePiece::has_begin() const {
return (_has_bits_[0] & 0x00000008u) != 0;
}
inline void SentencePieceText_SentencePiece::set_has_begin() {
_has_bits_[0] |= 0x00000008u;
}
inline void SentencePieceText_SentencePiece::clear_has_begin() {
_has_bits_[0] &= ~0x00000008u;
}
inline void SentencePieceText_SentencePiece::clear_begin() {
begin_ = 0u;
clear_has_begin();
}
inline ::google::protobuf::uint32 SentencePieceText_SentencePiece::begin() const {
// @@protoc_insertion_point(field_get:sentencepiece.SentencePieceText.SentencePiece.begin)
return begin_;
}
inline void SentencePieceText_SentencePiece::set_begin(::google::protobuf::uint32 value) {
set_has_begin();
begin_ = value;
// @@protoc_insertion_point(field_set:sentencepiece.SentencePieceText.SentencePiece.begin)
}
// optional uint32 end = 5;
inline bool SentencePieceText_SentencePiece::has_end() const {
return (_has_bits_[0] & 0x00000010u) != 0;
}
inline void SentencePieceText_SentencePiece::set_has_end() {
_has_bits_[0] |= 0x00000010u;
}
inline void SentencePieceText_SentencePiece::clear_has_end() {
_has_bits_[0] &= ~0x00000010u;
}
inline void SentencePieceText_SentencePiece::clear_end() {
end_ = 0u;
clear_has_end();
}
inline ::google::protobuf::uint32 SentencePieceText_SentencePiece::end() const {
// @@protoc_insertion_point(field_get:sentencepiece.SentencePieceText.SentencePiece.end)
return end_;
}
inline void SentencePieceText_SentencePiece::set_end(::google::protobuf::uint32 value) {
set_has_end();
end_ = value;
// @@protoc_insertion_point(field_set:sentencepiece.SentencePieceText.SentencePiece.end)
}
// -------------------------------------------------------------------
// SentencePieceText
// optional string text = 1;
inline bool SentencePieceText::has_text() const {
return (_has_bits_[0] & 0x00000001u) != 0;
}
inline void SentencePieceText::set_has_text() {
_has_bits_[0] |= 0x00000001u;
}
inline void SentencePieceText::clear_has_text() {
_has_bits_[0] &= ~0x00000001u;
}
inline void SentencePieceText::clear_text() {
text_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
clear_has_text();
}
inline const ::std::string& SentencePieceText::text() const {
// @@protoc_insertion_point(field_get:sentencepiece.SentencePieceText.text)
return text_.GetNoArena();
}
inline void SentencePieceText::set_text(const ::std::string& value) {
set_has_text();
text_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
// @@protoc_insertion_point(field_set:sentencepiece.SentencePieceText.text)
}
#if LANG_CXX11
inline void SentencePieceText::set_text(::std::string&& value) {
set_has_text();
text_.SetNoArena(
&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::move(value));
// @@protoc_insertion_point(field_set_rvalue:sentencepiece.SentencePieceText.text)
}
#endif
inline void SentencePieceText::set_text(const char* value) {
GOOGLE_DCHECK(value != NULL);
set_has_text();
text_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
// @@protoc_insertion_point(field_set_char:sentencepiece.SentencePieceText.text)
}
inline void SentencePieceText::set_text(const char* value, size_t size) {
set_has_text();
text_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
::std::string(reinterpret_cast<const char*>(value), size));
// @@protoc_insertion_point(field_set_pointer:sentencepiece.SentencePieceText.text)
}
inline ::std::string* SentencePieceText::mutable_text() {
set_has_text();
// @@protoc_insertion_point(field_mutable:sentencepiece.SentencePieceText.text)
return text_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline ::std::string* SentencePieceText::release_text() {
// @@protoc_insertion_point(field_release:sentencepiece.SentencePieceText.text)
if (!has_text()) {
return NULL;
}
clear_has_text();
return text_.ReleaseNonDefaultNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline void SentencePieceText::set_allocated_text(::std::string* text) {
if (text != NULL) {
set_has_text();
} else {
clear_has_text();
}
text_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), text);
// @@protoc_insertion_point(field_set_allocated:sentencepiece.SentencePieceText.text)
}
// repeated .sentencepiece.SentencePieceText.SentencePiece pieces = 2;
inline int SentencePieceText::pieces_size() const {
return pieces_.size();
}
inline void SentencePieceText::clear_pieces() {
pieces_.Clear();
}
inline ::sentencepiece::SentencePieceText_SentencePiece* SentencePieceText::mutable_pieces(int index) {
// @@protoc_insertion_point(field_mutable:sentencepiece.SentencePieceText.pieces)
return pieces_.Mutable(index);
}
inline ::google::protobuf::RepeatedPtrField< ::sentencepiece::SentencePieceText_SentencePiece >*
SentencePieceText::mutable_pieces() {
// @@protoc_insertion_point(field_mutable_list:sentencepiece.SentencePieceText.pieces)
return &pieces_;
}
inline const ::sentencepiece::SentencePieceText_SentencePiece& SentencePieceText::pieces(int index) const {
// @@protoc_insertion_point(field_get:sentencepiece.SentencePieceText.pieces)
return pieces_.Get(index);
}
inline ::sentencepiece::SentencePieceText_SentencePiece* SentencePieceText::add_pieces() {
// @@protoc_insertion_point(field_add:sentencepiece.SentencePieceText.pieces)
return pieces_.Add();
}
inline const ::google::protobuf::RepeatedPtrField< ::sentencepiece::SentencePieceText_SentencePiece >&
SentencePieceText::pieces() const {
// @@protoc_insertion_point(field_list:sentencepiece.SentencePieceText.pieces)
return pieces_;
}
// optional float score = 3;
inline bool SentencePieceText::has_score() const {
return (_has_bits_[0] & 0x00000002u) != 0;
}
inline void SentencePieceText::set_has_score() {
_has_bits_[0] |= 0x00000002u;
}
inline void SentencePieceText::clear_has_score() {
_has_bits_[0] &= ~0x00000002u;
}
inline void SentencePieceText::clear_score() {
score_ = 0;
clear_has_score();
}
inline float SentencePieceText::score() const {
// @@protoc_insertion_point(field_get:sentencepiece.SentencePieceText.score)
return score_;
}
inline void SentencePieceText::set_score(float value) {
set_has_score();
score_ = value;
// @@protoc_insertion_point(field_set:sentencepiece.SentencePieceText.score)
}
// -------------------------------------------------------------------
// NBestSentencePieceText
// repeated .sentencepiece.SentencePieceText nbests = 1;
inline int NBestSentencePieceText::nbests_size() const {
return nbests_.size();
}
inline void NBestSentencePieceText::clear_nbests() {
nbests_.Clear();
}
inline ::sentencepiece::SentencePieceText* NBestSentencePieceText::mutable_nbests(int index) {
// @@protoc_insertion_point(field_mutable:sentencepiece.NBestSentencePieceText.nbests)
return nbests_.Mutable(index);
}
inline ::google::protobuf::RepeatedPtrField< ::sentencepiece::SentencePieceText >*
NBestSentencePieceText::mutable_nbests() {
// @@protoc_insertion_point(field_mutable_list:sentencepiece.NBestSentencePieceText.nbests)
return &nbests_;
}
inline const ::sentencepiece::SentencePieceText& NBestSentencePieceText::nbests(int index) const {
// @@protoc_insertion_point(field_get:sentencepiece.NBestSentencePieceText.nbests)
return nbests_.Get(index);
}
inline ::sentencepiece::SentencePieceText* NBestSentencePieceText::add_nbests() {
// @@protoc_insertion_point(field_add:sentencepiece.NBestSentencePieceText.nbests)
return nbests_.Add();
}
inline const ::google::protobuf::RepeatedPtrField< ::sentencepiece::SentencePieceText >&
NBestSentencePieceText::nbests() const {
// @@protoc_insertion_point(field_list:sentencepiece.NBestSentencePieceText.nbests)
return nbests_;
}
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif // __GNUC__
// -------------------------------------------------------------------
// -------------------------------------------------------------------
// @@protoc_insertion_point(namespace_scope)
} // namespace sentencepiece
// @@protoc_insertion_point(global_scope)
#endif // PROTOBUF_INCLUDED_sentencepiece_2eproto

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -25,8 +25,6 @@ namespace character {
util::Status Trainer::Train() {
RETURN_IF_ERROR(status());
LOG(INFO) << "Starts training with : \n" << trainer_spec_.Utf8DebugString();
CHECK_OR_RETURN(normalizer_spec_.escape_whitespaces());
CHECK_EQ_OR_RETURN(TrainerSpec::CHAR, trainer_spec_.model_type());
@ -56,8 +54,6 @@ util::Status Trainer::Train() {
trainer_spec_.set_vocab_size(final_pieces_.size() + meta_pieces_.size());
}
LOG(INFO) << trainer_spec_.Utf8DebugString();
return Save();
}
} // namespace character

View File

@ -13,6 +13,7 @@
// limitations under the License.!
syntax = "proto2";
option optimize_for = LITE_RUNTIME;
package sentencepiece;

View File

@ -13,6 +13,7 @@
// limitations under the License.!
syntax = "proto2";
option optimize_for = LITE_RUNTIME;
package sentencepiece;

View File

@ -902,7 +902,8 @@ TEST(SentencePieceProcessorTest, EndToEndTest) {
EXPECT_NOT_OK(sp.SetDecodeExtraOptions("foo"));
auto RunTest = [&model_proto](const SentencePieceProcessor &sp) {
EXPECT_EQ(model_proto.DebugString(), sp.model_proto().DebugString());
EXPECT_EQ(model_proto.SerializeAsString(),
sp.model_proto().SerializeAsString());
EXPECT_EQ(8, sp.GetPieceSize());
EXPECT_EQ(0, sp.PieceToId("<unk>"));

View File

@ -30,6 +30,9 @@ namespace {
static constexpr char kDefaultNormalizerName[] = "nmt_nfkc";
} // namespace
// this header is automatically generated.
#include "spec_parser.h"
// static
util::Status SentencePieceTrainer::Train(const TrainerSpec &trainer_spec) {
NormalizerSpec normalizer_spec;
@ -42,6 +45,10 @@ util::Status SentencePieceTrainer::Train(
auto copied_normalizer_spec = normalizer_spec;
RETURN_IF_ERROR(PopulateNormalizerSpec(&copied_normalizer_spec));
auto trainer = TrainerFactory::Create(trainer_spec, copied_normalizer_spec);
LOG(INFO) << "Starts training with : \n"
<< PrintProto(trainer_spec) << PrintProto(copied_normalizer_spec);
return trainer->Train();
}
@ -55,82 +62,6 @@ NormalizerSpec SentencePieceTrainer::GetNormalizerSpec(
return spec;
}
// static
util::Status SentencePieceTrainer::SetProtoField(
util::min_string_view _field_name, util::min_string_view _value,
google::protobuf::Message *message) {
const absl::string_view field_name(_field_name.data(), _field_name.size());
const absl::string_view value(_value.data(), _value.size());
const auto *descriptor = message->GetDescriptor();
const auto *reflection = message->GetReflection();
CHECK_OR_RETURN(descriptor != nullptr && reflection != nullptr)
<< "reflection is not supported.";
const auto *field = descriptor->FindFieldByName(
std::string(field_name.data(), field_name.size()));
if (field == nullptr) {
return util::StatusBuilder(util::error::NOT_FOUND)
<< "unknown field name \"" << field_name << "\" in\n"
<< descriptor->DebugString();
}
std::vector<std::string> values = {std::string(value)};
if (field->is_repeated())
values = string_util::Split(std::string(value), ",");
#define SET_FIELD(METHOD_TYPE, v) \
if (field->is_repeated()) \
reflection->Add##METHOD_TYPE(message, field, v); \
else \
reflection->Set##METHOD_TYPE(message, field, v);
#define DEFINE_SET_FIELD(PROTO_TYPE, CPP_TYPE, FUNC_PREFIX, METHOD_TYPE, \
EMPTY) \
case google::protobuf::FieldDescriptor::CPPTYPE_##PROTO_TYPE: { \
CPP_TYPE v; \
if (!string_util::lexical_cast(value.empty() ? EMPTY : value, &v)) \
return util::StatusBuilder(util::error::INVALID_ARGUMENT) \
<< "cannot parse \"" << value << "\" as \"" << field->type_name() \
<< "\"."; \
SET_FIELD(METHOD_TYPE, v); \
break; \
}
for (const auto &value : values) {
switch (field->cpp_type()) {
DEFINE_SET_FIELD(INT32, int32, i, Int32, "");
DEFINE_SET_FIELD(INT64, int64, i, Int64, "");
DEFINE_SET_FIELD(UINT32, uint32, i, UInt32, "");
DEFINE_SET_FIELD(UINT64, uint64, i, UInt64, "");
DEFINE_SET_FIELD(DOUBLE, double, d, Double, "");
DEFINE_SET_FIELD(FLOAT, float, f, Float, "");
DEFINE_SET_FIELD(BOOL, bool, b, Bool, "true");
case google::protobuf::FieldDescriptor::CPPTYPE_STRING:
SET_FIELD(String, value);
break;
case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: {
const auto *enum_value =
field->enum_type()->FindValueByName(string_util::ToUpper(value));
if (enum_value == nullptr)
return util::StatusBuilder(util::error::INVALID_ARGUMENT)
<< "unknown enumeration value of \"" << value
<< "\" for field \"" << field->name() << "\".";
SET_FIELD(Enum, enum_value);
break;
}
default:
return util::StatusBuilder(util::error::UNIMPLEMENTED)
<< "proto type \"" << field->cpp_type_name()
<< "\" is not supported.";
}
}
return util::OkStatus();
}
// static
util::Status SentencePieceTrainer::MergeSpecsFromArgs(
util::min_string_view _args, TrainerSpec *trainer_spec,

View File

@ -18,12 +18,6 @@
#include <string>
#include "sentencepiece_processor.h"
namespace google {
namespace protobuf {
class Message;
} // namespace protobuf
} // namespace google
namespace sentencepiece {
class TrainerSpec;
@ -63,9 +57,15 @@ class SentencePieceTrainer {
// Helper function to set `field_name=value` in `message`.
// When `field_name` is repeated, multiple values can be passed
// with comma-separated values. `field_name` must not be a nested message.
static util::Status SetProtoField(util::min_string_view field_name,
util::min_string_view value,
google::protobuf::Message *message);
// The body of these functions are automatically generated with
// data/gen_spec_parser.pl
static util::Status SetProtoField(const std::string &name,
const std::string &value,
TrainerSpec *message);
static util::Status SetProtoField(const std::string &name,
const std::string &value,
NormalizerSpec *message);
SentencePieceTrainer() = delete;
~SentencePieceTrainer() = delete;

View File

@ -96,47 +96,60 @@ TEST(SentencePieceTrainerTest, TrainTest) {
}
TEST(SentencePieceTrainerTest, SetProtoFieldTest) {
TrainerSpec spec;
{
TrainerSpec spec;
EXPECT_NOT_OK(SentencePieceTrainer::SetProtoField("dummy", "1000", &spec));
EXPECT_NOT_OK(SentencePieceTrainer::SetProtoField("dummy", "1000", &spec));
EXPECT_OK(SentencePieceTrainer::SetProtoField("vocab_size", "1000", &spec));
EXPECT_EQ(1000, spec.vocab_size());
EXPECT_NOT_OK(
SentencePieceTrainer::SetProtoField("vocab_size", "UNK", &spec));
EXPECT_OK(SentencePieceTrainer::SetProtoField("vocab_size", "1000", &spec));
EXPECT_EQ(1000, spec.vocab_size());
EXPECT_NOT_OK(
SentencePieceTrainer::SetProtoField("vocab_size", "UNK", &spec));
EXPECT_OK(SentencePieceTrainer::SetProtoField("input_format", "TSV", &spec));
EXPECT_EQ("TSV", spec.input_format());
EXPECT_OK(SentencePieceTrainer::SetProtoField("input_format", "123", &spec));
EXPECT_EQ("123", spec.input_format());
EXPECT_OK(
SentencePieceTrainer::SetProtoField("input_format", "TSV", &spec));
EXPECT_EQ("TSV", spec.input_format());
EXPECT_OK(
SentencePieceTrainer::SetProtoField("input_format", "123", &spec));
EXPECT_EQ("123", spec.input_format());
EXPECT_OK(SentencePieceTrainer::SetProtoField("split_by_whitespace", "false",
&spec));
EXPECT_FALSE(spec.split_by_whitespace());
EXPECT_OK(
SentencePieceTrainer::SetProtoField("split_by_whitespace", "", &spec));
EXPECT_TRUE(spec.split_by_whitespace());
EXPECT_OK(SentencePieceTrainer::SetProtoField("split_by_whitespace",
"false", &spec));
EXPECT_FALSE(spec.split_by_whitespace());
EXPECT_OK(
SentencePieceTrainer::SetProtoField("split_by_whitespace", "", &spec));
EXPECT_TRUE(spec.split_by_whitespace());
EXPECT_OK(
SentencePieceTrainer::SetProtoField("character_coverage", "0.5", &spec));
EXPECT_NEAR(spec.character_coverage(), 0.5, 0.001);
EXPECT_NOT_OK(
SentencePieceTrainer::SetProtoField("character_coverage", "UNK", &spec));
EXPECT_OK(SentencePieceTrainer::SetProtoField("character_coverage", "0.5",
&spec));
EXPECT_NEAR(spec.character_coverage(), 0.5, 0.001);
EXPECT_NOT_OK(SentencePieceTrainer::SetProtoField("character_coverage",
"UNK", &spec));
EXPECT_OK(SentencePieceTrainer::SetProtoField("input", "foo,bar,buz", &spec));
EXPECT_EQ(3, spec.input_size());
EXPECT_EQ("foo", spec.input(0));
EXPECT_EQ("bar", spec.input(1));
EXPECT_EQ("buz", spec.input(2));
EXPECT_OK(
SentencePieceTrainer::SetProtoField("input", "foo,bar,buz", &spec));
EXPECT_EQ(3, spec.input_size());
EXPECT_EQ("foo", spec.input(0));
EXPECT_EQ("bar", spec.input(1));
EXPECT_EQ("buz", spec.input(2));
EXPECT_OK(SentencePieceTrainer::SetProtoField("model_type", "BPE", &spec));
EXPECT_NOT_OK(
SentencePieceTrainer::SetProtoField("model_type", "UNK", &spec));
EXPECT_OK(SentencePieceTrainer::SetProtoField("model_type", "BPE", &spec));
EXPECT_NOT_OK(
SentencePieceTrainer::SetProtoField("model_type", "UNK", &spec));
}
// Nested message is not supported.
ModelProto proto;
EXPECT_NOT_OK(
SentencePieceTrainer::SetProtoField("trainer_spec", "UNK", &proto));
{
NormalizerSpec spec;
EXPECT_OK(SentencePieceTrainer::SetProtoField("add_dummy_prefix", "false",
&spec));
EXPECT_FALSE(spec.add_dummy_prefix());
EXPECT_OK(SentencePieceTrainer::SetProtoField("escape_whitespaces", "false",
&spec));
EXPECT_FALSE(spec.escape_whitespaces());
EXPECT_NOT_OK(SentencePieceTrainer::SetProtoField("dummy", "1000", &spec));
}
}
TEST(SentencePieceTrainerTest, MergeSpecsFromArgs) {

409
src/spec_parser.h Normal file
View File

@ -0,0 +1,409 @@
namespace {
inline std::string PrintProto(const TrainerSpec &message) {
std::ostringstream os;
os << "TrainerSpec {\n";
for (const auto &v : message.input())
os << " input: " << v << "\n";
os << " input_format: " << message.input_format() << "\n";
os << " model_prefix: " << message.model_prefix() << "\n";
static const std::map<TrainerSpec::ModelType, std::string> kModelType_Map = { {TrainerSpec::UNIGRAM, "UNIGRAM"}, {TrainerSpec::BPE, "BPE"}, {TrainerSpec::WORD, "WORD"}, {TrainerSpec::CHAR, "CHAR"}, };
{
const auto it = kModelType_Map.find(message.model_type());
if (it == kModelType_Map.end())
os << " model_type: unknown\n";
else
os << " model_type: " << it->second << "\n";
}
os << " vocab_size: " << message.vocab_size() << "\n";
for (const auto &v : message.accept_language())
os << " accept_language: " << v << "\n";
os << " self_test_sample_size: " << message.self_test_sample_size() << "\n";
os << " character_coverage: " << message.character_coverage() << "\n";
os << " input_sentence_size: " << message.input_sentence_size() << "\n";
os << " shuffle_input_sentence: " << message.shuffle_input_sentence() << "\n";
os << " mining_sentence_size: " << message.mining_sentence_size() << "\n";
os << " training_sentence_size: " << message.training_sentence_size() << "\n";
os << " seed_sentencepiece_size: " << message.seed_sentencepiece_size() << "\n";
os << " shrinking_factor: " << message.shrinking_factor() << "\n";
os << " max_sentence_length: " << message.max_sentence_length() << "\n";
os << " num_threads: " << message.num_threads() << "\n";
os << " num_sub_iterations: " << message.num_sub_iterations() << "\n";
os << " max_sentencepiece_length: " << message.max_sentencepiece_length() << "\n";
os << " split_by_unicode_script: " << message.split_by_unicode_script() << "\n";
os << " split_by_number: " << message.split_by_number() << "\n";
os << " split_by_whitespace: " << message.split_by_whitespace() << "\n";
for (const auto &v : message.control_symbols())
os << " control_symbols: " << v << "\n";
for (const auto &v : message.user_defined_symbols())
os << " user_defined_symbols: " << v << "\n";
os << " hard_vocab_limit: " << message.hard_vocab_limit() << "\n";
os << " use_all_vocab: " << message.use_all_vocab() << "\n";
os << " unk_id: " << message.unk_id() << "\n";
os << " bos_id: " << message.bos_id() << "\n";
os << " eos_id: " << message.eos_id() << "\n";
os << " pad_id: " << message.pad_id() << "\n";
os << " unk_piece: " << message.unk_piece() << "\n";
os << " bos_piece: " << message.bos_piece() << "\n";
os << " eos_piece: " << message.eos_piece() << "\n";
os << " pad_piece: " << message.pad_piece() << "\n";
os << " unk_surface: " << message.unk_surface() << "\n";
os << "}\n";
return os.str();
}
inline std::string PrintProto(const NormalizerSpec &message) {
std::ostringstream os;
os << "NormalizerSpec {\n";
os << " name: " << message.name() << "\n";
os << " add_dummy_prefix: " << message.add_dummy_prefix() << "\n";
os << " remove_extra_whitespaces: " << message.remove_extra_whitespaces() << "\n";
os << " escape_whitespaces: " << message.escape_whitespaces() << "\n";
os << " normalization_rule_tsv: " << message.normalization_rule_tsv() << "\n";
os << "}\n";
return os.str();
}
} // namespace
util::Status SentencePieceTrainer::SetProtoField(const std::string& name, const std::string& value, TrainerSpec *message) {
CHECK_OR_RETURN(message);
if (name == "input") {
for (const auto &val : string_util::Split(value, ",")) {
message->add_input(val);
}
return util::OkStatus();
}
if (name == "input_format") {
const auto &val = value;
message->set_input_format(val);
return util::OkStatus();
}
if (name == "model_prefix") {
const auto &val = value;
message->set_model_prefix(val);
return util::OkStatus();
}
static const std::map <std::string, TrainerSpec::ModelType> kModelType_Map = { {"UNIGRAM", TrainerSpec::UNIGRAM}, {"BPE", TrainerSpec::BPE}, {"WORD", TrainerSpec::WORD}, {"CHAR", TrainerSpec::CHAR}, };
if (name == "model_type") {
const auto &val = value;
const auto it = kModelType_Map.find(string_util::ToUpper(val));
if (it == kModelType_Map.end())
return util::StatusBuilder(util::error::INVALID_ARGUMENT) << "unknown enumeration value of \"" << val << "\" as ModelType.";
message->set_model_type(it->second);
return util::OkStatus();
}
if (name == "vocab_size") {
const auto &val = value;
int32 v;
if (!string_util::lexical_cast(val.empty() ? "" : val, &v))
return util::StatusBuilder(util::error::INVALID_ARGUMENT) << "cannot parse \"" << val << "\" as int32.";
message->set_vocab_size(v);
return util::OkStatus();
}
if (name == "accept_language") {
for (const auto &val : string_util::Split(value, ",")) {
message->add_accept_language(val);
}
return util::OkStatus();
}
if (name == "self_test_sample_size") {
const auto &val = value;
int32 v;
if (!string_util::lexical_cast(val.empty() ? "" : val, &v))
return util::StatusBuilder(util::error::INVALID_ARGUMENT) << "cannot parse \"" << val << "\" as int32.";
message->set_self_test_sample_size(v);
return util::OkStatus();
}
if (name == "character_coverage") {
const auto &val = value;
float v;
if (!string_util::lexical_cast(val.empty() ? "" : val, &v))
return util::StatusBuilder(util::error::INVALID_ARGUMENT) << "cannot parse \"" << val << "\" as float.";
message->set_character_coverage(v);
return util::OkStatus();
}
if (name == "input_sentence_size") {
const auto &val = value;
int32 v;
if (!string_util::lexical_cast(val.empty() ? "" : val, &v))
return util::StatusBuilder(util::error::INVALID_ARGUMENT) << "cannot parse \"" << val << "\" as int32.";
message->set_input_sentence_size(v);
return util::OkStatus();
}
if (name == "shuffle_input_sentence") {
const auto &val = value;
bool v;
if (!string_util::lexical_cast(val.empty() ? "true" : val, &v))
return util::StatusBuilder(util::error::INVALID_ARGUMENT) << "cannot parse \"" << val << "\" as bool.";
message->set_shuffle_input_sentence(v);
return util::OkStatus();
}
if (name == "mining_sentence_size") {
const auto &val = value;
int32 v;
if (!string_util::lexical_cast(val.empty() ? "" : val, &v))
return util::StatusBuilder(util::error::INVALID_ARGUMENT) << "cannot parse \"" << val << "\" as int32.";
message->set_mining_sentence_size(v);
return util::OkStatus();
}
if (name == "training_sentence_size") {
const auto &val = value;
int32 v;
if (!string_util::lexical_cast(val.empty() ? "" : val, &v))
return util::StatusBuilder(util::error::INVALID_ARGUMENT) << "cannot parse \"" << val << "\" as int32.";
message->set_training_sentence_size(v);
return util::OkStatus();
}
if (name == "seed_sentencepiece_size") {
const auto &val = value;
int32 v;
if (!string_util::lexical_cast(val.empty() ? "" : val, &v))
return util::StatusBuilder(util::error::INVALID_ARGUMENT) << "cannot parse \"" << val << "\" as int32.";
message->set_seed_sentencepiece_size(v);
return util::OkStatus();
}
if (name == "shrinking_factor") {
const auto &val = value;
float v;
if (!string_util::lexical_cast(val.empty() ? "" : val, &v))
return util::StatusBuilder(util::error::INVALID_ARGUMENT) << "cannot parse \"" << val << "\" as float.";
message->set_shrinking_factor(v);
return util::OkStatus();
}
if (name == "max_sentence_length") {
const auto &val = value;
int32 v;
if (!string_util::lexical_cast(val.empty() ? "" : val, &v))
return util::StatusBuilder(util::error::INVALID_ARGUMENT) << "cannot parse \"" << val << "\" as int32.";
message->set_max_sentence_length(v);
return util::OkStatus();
}
if (name == "num_threads") {
const auto &val = value;
int32 v;
if (!string_util::lexical_cast(val.empty() ? "" : val, &v))
return util::StatusBuilder(util::error::INVALID_ARGUMENT) << "cannot parse \"" << val << "\" as int32.";
message->set_num_threads(v);
return util::OkStatus();
}
if (name == "num_sub_iterations") {
const auto &val = value;
int32 v;
if (!string_util::lexical_cast(val.empty() ? "" : val, &v))
return util::StatusBuilder(util::error::INVALID_ARGUMENT) << "cannot parse \"" << val << "\" as int32.";
message->set_num_sub_iterations(v);
return util::OkStatus();
}
if (name == "max_sentencepiece_length") {
const auto &val = value;
int32 v;
if (!string_util::lexical_cast(val.empty() ? "" : val, &v))
return util::StatusBuilder(util::error::INVALID_ARGUMENT) << "cannot parse \"" << val << "\" as int32.";
message->set_max_sentencepiece_length(v);
return util::OkStatus();
}
if (name == "split_by_unicode_script") {
const auto &val = value;
bool v;
if (!string_util::lexical_cast(val.empty() ? "true" : val, &v))
return util::StatusBuilder(util::error::INVALID_ARGUMENT) << "cannot parse \"" << val << "\" as bool.";
message->set_split_by_unicode_script(v);
return util::OkStatus();
}
if (name == "split_by_number") {
const auto &val = value;
bool v;
if (!string_util::lexical_cast(val.empty() ? "true" : val, &v))
return util::StatusBuilder(util::error::INVALID_ARGUMENT) << "cannot parse \"" << val << "\" as bool.";
message->set_split_by_number(v);
return util::OkStatus();
}
if (name == "split_by_whitespace") {
const auto &val = value;
bool v;
if (!string_util::lexical_cast(val.empty() ? "true" : val, &v))
return util::StatusBuilder(util::error::INVALID_ARGUMENT) << "cannot parse \"" << val << "\" as bool.";
message->set_split_by_whitespace(v);
return util::OkStatus();
}
if (name == "control_symbols") {
for (const auto &val : string_util::Split(value, ",")) {
message->add_control_symbols(val);
}
return util::OkStatus();
}
if (name == "user_defined_symbols") {
for (const auto &val : string_util::Split(value, ",")) {
message->add_user_defined_symbols(val);
}
return util::OkStatus();
}
if (name == "hard_vocab_limit") {
const auto &val = value;
bool v;
if (!string_util::lexical_cast(val.empty() ? "true" : val, &v))
return util::StatusBuilder(util::error::INVALID_ARGUMENT) << "cannot parse \"" << val << "\" as bool.";
message->set_hard_vocab_limit(v);
return util::OkStatus();
}
if (name == "use_all_vocab") {
const auto &val = value;
bool v;
if (!string_util::lexical_cast(val.empty() ? "true" : val, &v))
return util::StatusBuilder(util::error::INVALID_ARGUMENT) << "cannot parse \"" << val << "\" as bool.";
message->set_use_all_vocab(v);
return util::OkStatus();
}
if (name == "unk_id") {
const auto &val = value;
int32 v;
if (!string_util::lexical_cast(val.empty() ? "" : val, &v))
return util::StatusBuilder(util::error::INVALID_ARGUMENT) << "cannot parse \"" << val << "\" as int32.";
message->set_unk_id(v);
return util::OkStatus();
}
if (name == "bos_id") {
const auto &val = value;
int32 v;
if (!string_util::lexical_cast(val.empty() ? "" : val, &v))
return util::StatusBuilder(util::error::INVALID_ARGUMENT) << "cannot parse \"" << val << "\" as int32.";
message->set_bos_id(v);
return util::OkStatus();
}
if (name == "eos_id") {
const auto &val = value;
int32 v;
if (!string_util::lexical_cast(val.empty() ? "" : val, &v))
return util::StatusBuilder(util::error::INVALID_ARGUMENT) << "cannot parse \"" << val << "\" as int32.";
message->set_eos_id(v);
return util::OkStatus();
}
if (name == "pad_id") {
const auto &val = value;
int32 v;
if (!string_util::lexical_cast(val.empty() ? "" : val, &v))
return util::StatusBuilder(util::error::INVALID_ARGUMENT) << "cannot parse \"" << val << "\" as int32.";
message->set_pad_id(v);
return util::OkStatus();
}
if (name == "unk_piece") {
const auto &val = value;
message->set_unk_piece(val);
return util::OkStatus();
}
if (name == "bos_piece") {
const auto &val = value;
message->set_bos_piece(val);
return util::OkStatus();
}
if (name == "eos_piece") {
const auto &val = value;
message->set_eos_piece(val);
return util::OkStatus();
}
if (name == "pad_piece") {
const auto &val = value;
message->set_pad_piece(val);
return util::OkStatus();
}
if (name == "unk_surface") {
const auto &val = value;
message->set_unk_surface(val);
return util::OkStatus();
}
return util::StatusBuilder(util::error::NOT_FOUND)
<< "unknown field name \"" << name << "\" in TrainerSpec.";
}
util::Status SentencePieceTrainer::SetProtoField(const std::string& name, const std::string& value, NormalizerSpec *message) {
CHECK_OR_RETURN(message);
if (name == "name") {
const auto &val = value;
message->set_name(val);
return util::OkStatus();
}
if (name == "precompiled_charsmap") {
const auto &val = value;
message->set_precompiled_charsmap(val.data(), val.size());
return util::OkStatus();
}
if (name == "add_dummy_prefix") {
const auto &val = value;
bool v;
if (!string_util::lexical_cast(val.empty() ? "true" : val, &v))
return util::StatusBuilder(util::error::INVALID_ARGUMENT) << "cannot parse \"" << val << "\" as bool.";
message->set_add_dummy_prefix(v);
return util::OkStatus();
}
if (name == "remove_extra_whitespaces") {
const auto &val = value;
bool v;
if (!string_util::lexical_cast(val.empty() ? "true" : val, &v))
return util::StatusBuilder(util::error::INVALID_ARGUMENT) << "cannot parse \"" << val << "\" as bool.";
message->set_remove_extra_whitespaces(v);
return util::OkStatus();
}
if (name == "escape_whitespaces") {
const auto &val = value;
bool v;
if (!string_util::lexical_cast(val.empty() ? "true" : val, &v))
return util::StatusBuilder(util::error::INVALID_ARGUMENT) << "cannot parse \"" << val << "\" as bool.";
message->set_escape_whitespaces(v);
return util::OkStatus();
}
if (name == "normalization_rule_tsv") {
const auto &val = value;
message->set_normalization_rule_tsv(val);
return util::OkStatus();
}
return util::StatusBuilder(util::error::NOT_FOUND)
<< "unknown field name \"" << name << "\" in NormalizerSpec.";
}

View File

@ -65,7 +65,7 @@ int main(int argc, char *argv[]) {
} else if (FLAGS_output_format == "proto") {
process = [&](const std::vector<std::string> &pieces) {
CHECK_OK(sp.Decode(pieces, &spt));
output->WriteLine(spt.Utf8DebugString());
// output->WriteLine(spt.Utf8DebugString());
};
} else {
LOG(FATAL) << "Unknown output format: " << FLAGS_output_format;
@ -79,7 +79,7 @@ int main(int argc, char *argv[]) {
} else if (FLAGS_output_format == "proto") {
process = [&](const std::vector<std::string> &pieces) {
CHECK_OK(sp.Decode(ToIds(pieces), &spt));
output->WriteLine(spt.Utf8DebugString());
// output->WriteLine(spt.Utf8DebugString());
};
} else {
LOG(FATAL) << "Unknown output format: " << FLAGS_output_format;

View File

@ -94,7 +94,7 @@ int main(int argc, char *argv[]) {
} else if (FLAGS_output_format == "proto") {
process = [&](const std::string &line) {
CHECK_OK(sp.Encode(line, &spt));
output->WriteLine(spt.Utf8DebugString());
// output->WriteLine(spt.Utf8DebugString());
};
} else if (FLAGS_output_format == "sample_piece") {
process = [&](const std::string &line) {
@ -109,7 +109,7 @@ int main(int argc, char *argv[]) {
} else if (FLAGS_output_format == "sample_proto") {
process = [&](const std::string &line) {
CHECK_OK(sp.SampleEncode(line, FLAGS_nbest_size, FLAGS_alpha, &spt));
output->WriteLine(spt.Utf8DebugString());
// output->WriteLine(spt.Utf8DebugString());
};
} else if (FLAGS_output_format == "nbest_piece") {
process = [&](const std::string &line) {
@ -128,7 +128,7 @@ int main(int argc, char *argv[]) {
} else if (FLAGS_output_format == "nbest_proto") {
process = [&](const std::string &line) {
CHECK_OK(sp.NBestEncode(line, FLAGS_nbest_size, &nbest_spt));
output->WriteLine(nbest_spt.Utf8DebugString());
// output->WriteLine(nbest_spt.Utf8DebugString());
};
} else {
LOG(FATAL) << "Unknown output format: " << FLAGS_output_format;

View File

@ -1,3 +1,5 @@
// Copyright 2016 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
@ -37,7 +39,7 @@ int main(int argc, char *argv[]) {
output->WriteLine(os.str());
}
} else if (FLAGS_output_format == "proto") {
output->Write(sp.model_proto().Utf8DebugString());
// output->Write(sp.model_proto().Utf8DebugString());
}
return 0;

View File

@ -102,7 +102,7 @@ class SentenceSelector {
} else {
LOG(INFO)
<< "First " << spec_->input_sentence_size()
<< " sentences are select. Remaining sentences are discarded.";
<< " sentences are selected. Remaining sentences are discarded.";
}
}
}

View File

@ -452,8 +452,6 @@ TrainerModel::SentencePieces Trainer::FinalizeSentencePieces(
util::Status Trainer::Train() {
RETURN_IF_ERROR(status());
LOG(INFO) << "Starts training with : \n" << trainer_spec_.Utf8DebugString();
CHECK_EQ_OR_RETURN(TrainerSpec::UNIGRAM, trainer_spec_.model_type());
CHECK_OR_RETURN(normalizer_spec_.escape_whitespaces());

View File

@ -28,8 +28,6 @@ namespace word {
util::Status Trainer::Train() {
RETURN_IF_ERROR(status());
LOG(INFO) << "Starts training with : \n" << trainer_spec_.Utf8DebugString();
CHECK_OR_RETURN(normalizer_spec_.escape_whitespaces());
CHECK_EQ_OR_RETURN(TrainerSpec::WORD, trainer_spec_.model_type());

View File

@ -17,7 +17,6 @@
set -e # exit immediately on error
set -x # display all commands
PROTOBUF_VERSION=3.6.1
CMAKE_VERSION=3.12.0
run_docker() {
@ -47,7 +46,6 @@ build_tf_wrapper() {
-fPIC ${TF_CFLAGS[@]} -O2 \
-D_GLIBCXX_USE_CXX11_ABI=0 \
-Wl,--whole-archive \
/usr/local/lib/libprotobuf.a \
/usr/local/lib/libsentencepiece.a \
-Wl,--no-whole-archive \
sentencepiece_processor_ops.cc \
@ -66,16 +64,6 @@ build() {
apt-get update
apt-get install -y curl build-essential cmake git pkg-config python-pip python3-pip
# Install protobuf
curl -L -O https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/protobuf-cpp-${PROTOBUF_VERSION}.tar.gz
tar zxfv protobuf-cpp-${PROTOBUF_VERSION}.tar.gz
cd protobuf-${PROTOBUF_VERSION}
./configure --disable-shared --with-pic
make CXXFLAGS+="-std=c++11 -O3 -D_GLIBCXX_USE_CXX11_ABI=0" \
CFLAGS+="-std=c++11 -O3 -D_GLIBCXX_USE_CXX11_ABI=0" -j4
make install
cd ..
# Install sentencepiece
cmake ../.. -DSPM_ENABLE_SHARED=OFF -DSPM_ENABLE_TENSORFLOW_SHARED=ON
make -j4

View File

@ -17,8 +17,6 @@
set -e # exit immediately on error
set -x # display all commands
PROTOBUF_VERSION=3.6.1
build_tf_wrapper() {
if [ "$1" != "" ]; then
pkg_name="==$1"
@ -36,7 +34,6 @@ build_tf_wrapper() {
-fPIC ${TF_CFLAGS[@]} -O2 \
-D_GLIBCXX_USE_CXX11_ABI=0 \
-Wl,-all_load \
/usr/local/lib/libprotobuf.a \
/usr/local/lib/libsentencepiece.a \
-Wl,-noall_load \
sentencepiece_processor_ops.cc \
@ -52,16 +49,6 @@ build() {
mkdir -p build
cd build
# Install protobuf
curl -L -O https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/protobuf-cpp-${PROTOBUF_VERSION}.tar.gz
tar zxfv protobuf-cpp-${PROTOBUF_VERSION}.tar.gz
cd protobuf-${PROTOBUF_VERSION}
./configure --disable-shared --with-pic
make CXXFLAGS+="-std=c++11 -O3 -D_GLIBCXX_USE_CXX11_ABI=0" \
CFLAGS+="-std=c++11 -O3 -D_GLIBCXX_USE_CXX11_ABI=0" -j4
make install || true
cd ..
# Install sentencepiece
cmake ../.. -DSPM_ENABLE_SHARED=OFF -DSPM_ENABLE_TENSORFLOW_SHARED=ON
make -j4 VERBOSE=1

View File

@ -1,4 +1,3 @@
set PROTOBUF_VERSION=3.6.1
set PLATFORM=%1
if "%PLATFORM%"=="" set PLATFORM=x64
set PLATFORM_PREFIX=
@ -11,13 +10,6 @@ set LIBRARY_PATH=%CURRENT_PATH%build\root
mkdir build
cd build
curl -O -L https://github.com/google/protobuf/releases/download/v%PROTOBUF_VERSION%/protobuf-cpp-%PROTOBUF_VERSION%.zip
unzip protobuf-cpp-%PROTOBUF_VERSION%.zip
cd protobuf-%PROTOBUF_VERSION%\cmake
cmake . -A %PLATFORM% -DCMAKE_INSTALL_PREFIX=%LIBRARY_PATH% || goto :error
cmake --build . --config Release --target install || goto :error
cd ..\..
cmake .. -A %PLATFORM% -DSPM_BUILD_TEST=ON -DSPM_ENABLE_SHARED=OFF -DCMAKE_INSTALL_PREFIX=%LIBRARY_PATH%
cmake --build . --config Release --target install || goto :error
ctest -C Release || goto :error

View File

@ -19,8 +19,7 @@ set -x # display all commands
setup_ubuntu() {
apt-get update
apt-get install -y build-essential cmake git \
pkg-config libprotobuf-c++ protobuf-compiler libprotobuf-dev python-pip python3-pip
apt-get install -y build-essential cmake git pkg-config python-pip python3-pip
. /etc/os-release
if [ "${VERSION_ID}" = "14.04" ]; then
@ -34,7 +33,7 @@ setup_debian() {
setup_fedora() {
dnf update -y
dnf install -y rpm-build gcc-c++ make protobuf-devel cmake pkg-config python-pip python-devel
dnf install -y rpm-build gcc-c++ make cmake pkg-config python-pip python-devel
}
build_generic() {

View File

@ -1 +1,4 @@
include_directories(absl/strings darts_clone esaxx)
include_directories(absl/strings darts_clone esaxx protobuf-lite)

415
third_party/protobuf-lite/arena.cc vendored Normal file
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,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

196
third_party/protobuf-lite/bytestream.cc vendored Normal file
View File

@ -0,0 +1,196 @@
// 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/bytestream.h>
#include <string.h>
#include <algorithm>
namespace google {
namespace protobuf {
namespace strings {
void ByteSource::CopyTo(ByteSink* sink, size_t n) {
while (n > 0) {
StringPiece fragment = Peek();
if (fragment.empty()) {
GOOGLE_LOG(DFATAL) << "ByteSource::CopyTo() overran input.";
break;
}
std::size_t fragment_size = std::min<std::size_t>(n, fragment.size());
sink->Append(fragment.data(), fragment_size);
Skip(fragment_size);
n -= fragment_size;
}
}
void ByteSink::Flush() {}
void UncheckedArrayByteSink::Append(const char* data, size_t n) {
if (data != dest_) {
// Catch cases where the pointer returned by GetAppendBuffer() was modified.
GOOGLE_DCHECK(!(dest_ <= data && data < (dest_ + n)))
<< "Append() data[] overlaps with dest_[]";
memcpy(dest_, data, n);
}
dest_ += n;
}
CheckedArrayByteSink::CheckedArrayByteSink(char* outbuf, size_t capacity)
: outbuf_(outbuf), capacity_(capacity), size_(0), overflowed_(false) {
}
void CheckedArrayByteSink::Append(const char* bytes, size_t n) {
size_t available = capacity_ - size_;
if (n > available) {
n = available;
overflowed_ = true;
}
if (n > 0 && bytes != (outbuf_ + size_)) {
// Catch cases where the pointer returned by GetAppendBuffer() was modified.
GOOGLE_DCHECK(!(outbuf_ <= bytes && bytes < (outbuf_ + capacity_)))
<< "Append() bytes[] overlaps with outbuf_[]";
memcpy(outbuf_ + size_, bytes, n);
}
size_ += n;
}
GrowingArrayByteSink::GrowingArrayByteSink(size_t estimated_size)
: capacity_(estimated_size),
buf_(new char[estimated_size]),
size_(0) {
}
GrowingArrayByteSink::~GrowingArrayByteSink() {
delete[] buf_; // Just in case the user didn't call GetBuffer.
}
void GrowingArrayByteSink::Append(const char* bytes, size_t n) {
size_t available = capacity_ - size_;
if (bytes != (buf_ + size_)) {
// Catch cases where the pointer returned by GetAppendBuffer() was modified.
// We need to test for this before calling Expand() which may reallocate.
GOOGLE_DCHECK(!(buf_ <= bytes && bytes < (buf_ + capacity_)))
<< "Append() bytes[] overlaps with buf_[]";
}
if (n > available) {
Expand(n - available);
}
if (n > 0 && bytes != (buf_ + size_)) {
memcpy(buf_ + size_, bytes, n);
}
size_ += n;
}
char* GrowingArrayByteSink::GetBuffer(size_t* nbytes) {
ShrinkToFit();
char* b = buf_;
*nbytes = size_;
buf_ = NULL;
size_ = capacity_ = 0;
return b;
}
void GrowingArrayByteSink::Expand(size_t amount) { // Expand by at least 50%.
size_t new_capacity = std::max(capacity_ + amount, (3 * capacity_) / 2);
char* bigger = new char[new_capacity];
memcpy(bigger, buf_, size_);
delete[] buf_;
buf_ = bigger;
capacity_ = new_capacity;
}
void GrowingArrayByteSink::ShrinkToFit() {
// Shrink only if the buffer is large and size_ is less than 3/4
// of capacity_.
if (capacity_ > 256 && size_ < (3 * capacity_) / 4) {
char* just_enough = new char[size_];
memcpy(just_enough, buf_, size_);
delete[] buf_;
buf_ = just_enough;
capacity_ = size_;
}
}
void StringByteSink::Append(const char* data, size_t n) {
dest_->append(data, n);
}
size_t ArrayByteSource::Available() const {
return input_.size();
}
StringPiece ArrayByteSource::Peek() {
return input_;
}
void ArrayByteSource::Skip(size_t n) {
GOOGLE_DCHECK_LE(n, input_.size());
input_.remove_prefix(n);
}
LimitByteSource::LimitByteSource(ByteSource *source, size_t limit)
: source_(source),
limit_(limit) {
}
size_t LimitByteSource::Available() const {
size_t available = source_->Available();
if (available > limit_) {
available = limit_;
}
return available;
}
StringPiece LimitByteSource::Peek() {
StringPiece piece(source_->Peek());
if (piece.size() > limit_) {
piece.set(piece.data(), limit_);
}
return piece;
}
void LimitByteSource::Skip(size_t n) {
GOOGLE_DCHECK_LE(n, limit_);
source_->Skip(n);
limit_ -= n;
}
void LimitByteSource::CopyTo(ByteSink *sink, size_t n) {
GOOGLE_DCHECK_LE(n, limit_);
source_->CopyTo(sink, n);
limit_ -= n;
}
} // namespace strings
} // namespace protobuf
} // namespace google

View File

@ -0,0 +1,780 @@
// 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 implementation is heavily optimized to make reads and writes
// of small values (especially varints) as fast as possible. In
// particular, we optimize for the common case that a read or a write
// will not cross the end of the buffer, since we can avoid a lot
// of branching in this case.
#include <google/protobuf/io/coded_stream_inl.h>
#include <algorithm>
#include <utility>
#include <limits.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/arena.h>
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/stl_util.h>
namespace google {
namespace protobuf {
namespace io {
namespace {
static const int kMaxVarintBytes = 10;
static const int kMaxVarint32Bytes = 5;
inline bool NextNonEmpty(ZeroCopyInputStream* input,
const void** data, int* size) {
bool success;
do {
success = input->Next(data, size);
} while (success && *size == 0);
return success;
}
} // namespace
// CodedInputStream ==================================================
CodedInputStream::~CodedInputStream() {
if (input_ != NULL) {
BackUpInputToCurrentPosition();
}
}
// Static.
int CodedInputStream::default_recursion_limit_ = 100;
void CodedOutputStream::EnableAliasing(bool enabled) {
aliasing_enabled_ = enabled && output_->AllowsAliasing();
}
void CodedInputStream::BackUpInputToCurrentPosition() {
int backup_bytes = BufferSize() + buffer_size_after_limit_ + overflow_bytes_;
if (backup_bytes > 0) {
input_->BackUp(backup_bytes);
// total_bytes_read_ doesn't include overflow_bytes_.
total_bytes_read_ -= BufferSize() + buffer_size_after_limit_;
buffer_end_ = buffer_;
buffer_size_after_limit_ = 0;
overflow_bytes_ = 0;
}
}
inline void CodedInputStream::RecomputeBufferLimits() {
buffer_end_ += buffer_size_after_limit_;
int closest_limit = std::min(current_limit_, total_bytes_limit_);
if (closest_limit < total_bytes_read_) {
// The limit position is in the current buffer. We must adjust
// the buffer size accordingly.
buffer_size_after_limit_ = total_bytes_read_ - closest_limit;
buffer_end_ -= buffer_size_after_limit_;
} else {
buffer_size_after_limit_ = 0;
}
}
CodedInputStream::Limit CodedInputStream::PushLimit(int byte_limit) {
// Current position relative to the beginning of the stream.
int current_position = CurrentPosition();
Limit old_limit = current_limit_;
// security: byte_limit is possibly evil, so check for negative values
// and overflow. Also check that the new requested limit is before the
// previous limit; otherwise we continue to enforce the previous limit.
if (GOOGLE_PREDICT_TRUE(byte_limit >= 0 &&
byte_limit <= INT_MAX - current_position &&
byte_limit < current_limit_ - current_position)) {
current_limit_ = current_position + byte_limit;
RecomputeBufferLimits();
}
return old_limit;
}
void CodedInputStream::PopLimit(Limit limit) {
// The limit passed in is actually the *old* limit, which we returned from
// PushLimit().
current_limit_ = limit;
RecomputeBufferLimits();
// We may no longer be at a legitimate message end. ReadTag() needs to be
// called again to find out.
legitimate_message_end_ = false;
}
std::pair<CodedInputStream::Limit, int>
CodedInputStream::IncrementRecursionDepthAndPushLimit(int byte_limit) {
return std::make_pair(PushLimit(byte_limit), --recursion_budget_);
}
CodedInputStream::Limit CodedInputStream::ReadLengthAndPushLimit() {
uint32 length;
return PushLimit(ReadVarint32(&length) ? length : 0);
}
bool CodedInputStream::DecrementRecursionDepthAndPopLimit(Limit limit) {
bool result = ConsumedEntireMessage();
PopLimit(limit);
GOOGLE_DCHECK_LT(recursion_budget_, recursion_limit_);
++recursion_budget_;
return result;
}
bool CodedInputStream::CheckEntireMessageConsumedAndPopLimit(Limit limit) {
bool result = ConsumedEntireMessage();
PopLimit(limit);
return result;
}
int CodedInputStream::BytesUntilLimit() const {
if (current_limit_ == INT_MAX) return -1;
int current_position = CurrentPosition();
return current_limit_ - current_position;
}
void CodedInputStream::SetTotalBytesLimit(int total_bytes_limit) {
// Make sure the limit isn't already past, since this could confuse other
// code.
int current_position = CurrentPosition();
total_bytes_limit_ = std::max(current_position, total_bytes_limit);
RecomputeBufferLimits();
}
int CodedInputStream::BytesUntilTotalBytesLimit() const {
if (total_bytes_limit_ == INT_MAX) return -1;
return total_bytes_limit_ - CurrentPosition();
}
void CodedInputStream::PrintTotalBytesLimitError() {
GOOGLE_LOG(ERROR) << "A protocol message was rejected because it was too "
"big (more than " << total_bytes_limit_
<< " bytes). To increase the limit (or to disable these "
"warnings), see CodedInputStream::SetTotalBytesLimit() "
"in google/protobuf/io/coded_stream.h.";
}
bool CodedInputStream::SkipFallback(int count, int original_buffer_size) {
if (buffer_size_after_limit_ > 0) {
// We hit a limit inside this buffer. Advance to the limit and fail.
Advance(original_buffer_size);
return false;
}
count -= original_buffer_size;
buffer_ = NULL;
buffer_end_ = buffer_;
// Make sure this skip doesn't try to skip past the current limit.
int closest_limit = std::min(current_limit_, total_bytes_limit_);
int bytes_until_limit = closest_limit - total_bytes_read_;
if (bytes_until_limit < count) {
// We hit the limit. Skip up to it then fail.
if (bytes_until_limit > 0) {
total_bytes_read_ = closest_limit;
input_->Skip(bytes_until_limit);
}
return false;
}
if (!input_->Skip(count)) {
total_bytes_read_ = input_->ByteCount();
return false;
}
total_bytes_read_ += count;
return true;
}
bool CodedInputStream::GetDirectBufferPointer(const void** data, int* size) {
if (BufferSize() == 0 && !Refresh()) return false;
*data = buffer_;
*size = BufferSize();
return true;
}
bool CodedInputStream::ReadRaw(void* buffer, int size) {
return InternalReadRawInline(buffer, size);
}
bool CodedInputStream::ReadString(string* buffer, int size) {
if (size < 0) return false; // security: size is often user-supplied
return InternalReadStringInline(buffer, size);
}
bool CodedInputStream::ReadStringFallback(string* buffer, int size) {
if (!buffer->empty()) {
buffer->clear();
}
int closest_limit = std::min(current_limit_, total_bytes_limit_);
if (closest_limit != INT_MAX) {
int bytes_to_limit = closest_limit - CurrentPosition();
if (bytes_to_limit > 0 && size > 0 && size <= bytes_to_limit) {
buffer->reserve(size);
}
}
int current_buffer_size;
while ((current_buffer_size = BufferSize()) < size) {
// Some STL implementations "helpfully" crash on buffer->append(NULL, 0).
if (current_buffer_size != 0) {
// Note: string1.append(string2) is O(string2.size()) (as opposed to
// O(string1.size() + string2.size()), which would be bad).
buffer->append(reinterpret_cast<const char*>(buffer_),
current_buffer_size);
}
size -= current_buffer_size;
Advance(current_buffer_size);
if (!Refresh()) return false;
}
buffer->append(reinterpret_cast<const char*>(buffer_), size);
Advance(size);
return true;
}
bool CodedInputStream::ReadLittleEndian32Fallback(uint32* value) {
uint8 bytes[sizeof(*value)];
const uint8* ptr;
if (BufferSize() >= sizeof(*value)) {
// Fast path: Enough bytes in the buffer to read directly.
ptr = buffer_;
Advance(sizeof(*value));
} else {
// Slow path: Had to read past the end of the buffer.
if (!ReadRaw(bytes, sizeof(*value))) return false;
ptr = bytes;
}
ReadLittleEndian32FromArray(ptr, value);
return true;
}
bool CodedInputStream::ReadLittleEndian64Fallback(uint64* value) {
uint8 bytes[sizeof(*value)];
const uint8* ptr;
if (BufferSize() >= sizeof(*value)) {
// Fast path: Enough bytes in the buffer to read directly.
ptr = buffer_;
Advance(sizeof(*value));
} else {
// Slow path: Had to read past the end of the buffer.
if (!ReadRaw(bytes, sizeof(*value))) return false;
ptr = bytes;
}
ReadLittleEndian64FromArray(ptr, value);
return true;
}
namespace {
// Read a varint from the given buffer, write it to *value, and return a pair.
// The first part of the pair is true iff the read was successful. The second
// part is buffer + (number of bytes read). This function is always inlined,
// so returning a pair is costless.
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
::std::pair<bool, const uint8*> ReadVarint32FromArray(
uint32 first_byte, const uint8* buffer,
uint32* value);
inline ::std::pair<bool, const uint8*> ReadVarint32FromArray(
uint32 first_byte, const uint8* buffer, uint32* value) {
// Fast path: We have enough bytes left in the buffer to guarantee that
// this read won't cross the end, so we can skip the checks.
GOOGLE_DCHECK_EQ(*buffer, first_byte);
GOOGLE_DCHECK_EQ(first_byte & 0x80, 0x80) << first_byte;
const uint8* ptr = buffer;
uint32 b;
uint32 result = first_byte - 0x80;
++ptr; // We just processed the first byte. Move on to the second.
b = *(ptr++); result += b << 7; if (!(b & 0x80)) goto done;
result -= 0x80 << 7;
b = *(ptr++); result += b << 14; if (!(b & 0x80)) goto done;
result -= 0x80 << 14;
b = *(ptr++); result += b << 21; if (!(b & 0x80)) goto done;
result -= 0x80 << 21;
b = *(ptr++); result += b << 28; if (!(b & 0x80)) goto done;
// "result -= 0x80 << 28" is irrevelant.
// If the input is larger than 32 bits, we still need to read it all
// and discard the high-order bits.
for (int i = 0; i < kMaxVarintBytes - kMaxVarint32Bytes; i++) {
b = *(ptr++); if (!(b & 0x80)) goto done;
}
// We have overrun the maximum size of a varint (10 bytes). Assume
// the data is corrupt.
return std::make_pair(false, ptr);
done:
*value = result;
return std::make_pair(true, ptr);
}
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE::std::pair<bool, const uint8*>
ReadVarint64FromArray(const uint8* buffer, uint64* value);
inline ::std::pair<bool, const uint8*> ReadVarint64FromArray(
const uint8* buffer, uint64* value) {
const uint8* ptr = buffer;
uint32 b;
// Splitting into 32-bit pieces gives better performance on 32-bit
// processors.
uint32 part0 = 0, part1 = 0, part2 = 0;
b = *(ptr++); part0 = b ; if (!(b & 0x80)) goto done;
part0 -= 0x80;
b = *(ptr++); part0 += b << 7; if (!(b & 0x80)) goto done;
part0 -= 0x80 << 7;
b = *(ptr++); part0 += b << 14; if (!(b & 0x80)) goto done;
part0 -= 0x80 << 14;
b = *(ptr++); part0 += b << 21; if (!(b & 0x80)) goto done;
part0 -= 0x80 << 21;
b = *(ptr++); part1 = b ; if (!(b & 0x80)) goto done;
part1 -= 0x80;
b = *(ptr++); part1 += b << 7; if (!(b & 0x80)) goto done;
part1 -= 0x80 << 7;
b = *(ptr++); part1 += b << 14; if (!(b & 0x80)) goto done;
part1 -= 0x80 << 14;
b = *(ptr++); part1 += b << 21; if (!(b & 0x80)) goto done;
part1 -= 0x80 << 21;
b = *(ptr++); part2 = b ; if (!(b & 0x80)) goto done;
part2 -= 0x80;
b = *(ptr++); part2 += b << 7; if (!(b & 0x80)) goto done;
// "part2 -= 0x80 << 7" is irrelevant because (0x80 << 7) << 56 is 0.
// We have overrun the maximum size of a varint (10 bytes). Assume
// the data is corrupt.
return std::make_pair(false, ptr);
done:
*value = (static_cast<uint64>(part0)) |
(static_cast<uint64>(part1) << 28) |
(static_cast<uint64>(part2) << 56);
return std::make_pair(true, ptr);
}
} // namespace
bool CodedInputStream::ReadVarint32Slow(uint32* value) {
// Directly invoke ReadVarint64Fallback, since we already tried to optimize
// for one-byte varints.
std::pair<uint64, bool> p = ReadVarint64Fallback();
*value = static_cast<uint32>(p.first);
return p.second;
}
int64 CodedInputStream::ReadVarint32Fallback(uint32 first_byte_or_zero) {
if (BufferSize() >= kMaxVarintBytes ||
// Optimization: We're also safe if the buffer is non-empty and it ends
// with a byte that would terminate a varint.
(buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
GOOGLE_DCHECK_NE(first_byte_or_zero, 0)
<< "Caller should provide us with *buffer_ when buffer is non-empty";
uint32 temp;
::std::pair<bool, const uint8*> p =
ReadVarint32FromArray(first_byte_or_zero, buffer_, &temp);
if (!p.first) return -1;
buffer_ = p.second;
return temp;
} else {
// Really slow case: we will incur the cost of an extra function call here,
// but moving this out of line reduces the size of this function, which
// improves the common case. In micro benchmarks, this is worth about 10-15%
uint32 temp;
return ReadVarint32Slow(&temp) ? static_cast<int64>(temp) : -1;
}
}
int CodedInputStream::ReadVarintSizeAsIntSlow() {
// Directly invoke ReadVarint64Fallback, since we already tried to optimize
// for one-byte varints.
std::pair<uint64, bool> p = ReadVarint64Fallback();
if (!p.second || p.first > static_cast<uint64>(INT_MAX)) return -1;
return p.first;
}
int CodedInputStream::ReadVarintSizeAsIntFallback() {
if (BufferSize() >= kMaxVarintBytes ||
// Optimization: We're also safe if the buffer is non-empty and it ends
// with a byte that would terminate a varint.
(buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
uint64 temp;
::std::pair<bool, const uint8*> p = ReadVarint64FromArray(buffer_, &temp);
if (!p.first || temp > static_cast<uint64>(INT_MAX)) return -1;
buffer_ = p.second;
return temp;
} else {
// Really slow case: we will incur the cost of an extra function call here,
// but moving this out of line reduces the size of this function, which
// improves the common case. In micro benchmarks, this is worth about 10-15%
return ReadVarintSizeAsIntSlow();
}
}
uint32 CodedInputStream::ReadTagSlow() {
if (buffer_ == buffer_end_) {
// Call refresh.
if (!Refresh()) {
// Refresh failed. Make sure that it failed due to EOF, not because
// we hit total_bytes_limit_, which, unlike normal limits, is not a
// valid place to end a message.
int current_position = total_bytes_read_ - buffer_size_after_limit_;
if (current_position >= total_bytes_limit_) {
// Hit total_bytes_limit_. But if we also hit the normal limit,
// we're still OK.
legitimate_message_end_ = current_limit_ == total_bytes_limit_;
} else {
legitimate_message_end_ = true;
}
return 0;
}
}
// For the slow path, just do a 64-bit read. Try to optimize for one-byte tags
// again, since we have now refreshed the buffer.
uint64 result = 0;
if (!ReadVarint64(&result)) return 0;
return static_cast<uint32>(result);
}
uint32 CodedInputStream::ReadTagFallback(uint32 first_byte_or_zero) {
const int buf_size = BufferSize();
if (buf_size >= kMaxVarintBytes ||
// Optimization: We're also safe if the buffer is non-empty and it ends
// with a byte that would terminate a varint.
(buf_size > 0 && !(buffer_end_[-1] & 0x80))) {
GOOGLE_DCHECK_EQ(first_byte_or_zero, buffer_[0]);
if (first_byte_or_zero == 0) {
++buffer_;
return 0;
}
uint32 tag;
::std::pair<bool, const uint8*> p =
ReadVarint32FromArray(first_byte_or_zero, buffer_, &tag);
if (!p.first) {
return 0;
}
buffer_ = p.second;
return tag;
} else {
// We are commonly at a limit when attempting to read tags. Try to quickly
// detect this case without making another function call.
if ((buf_size == 0) &&
((buffer_size_after_limit_ > 0) ||
(total_bytes_read_ == current_limit_)) &&
// Make sure that the limit we hit is not total_bytes_limit_, since
// in that case we still need to call Refresh() so that it prints an
// error.
total_bytes_read_ - buffer_size_after_limit_ < total_bytes_limit_) {
// We hit a byte limit.
legitimate_message_end_ = true;
return 0;
}
return ReadTagSlow();
}
}
bool CodedInputStream::ReadVarint64Slow(uint64* value) {
// Slow path: This read might cross the end of the buffer, so we
// need to check and refresh the buffer if and when it does.
uint64 result = 0;
int count = 0;
uint32 b;
do {
if (count == kMaxVarintBytes) {
*value = 0;
return false;
}
while (buffer_ == buffer_end_) {
if (!Refresh()) {
*value = 0;
return false;
}
}
b = *buffer_;
result |= static_cast<uint64>(b & 0x7F) << (7 * count);
Advance(1);
++count;
} while (b & 0x80);
*value = result;
return true;
}
std::pair<uint64, bool> CodedInputStream::ReadVarint64Fallback() {
if (BufferSize() >= kMaxVarintBytes ||
// Optimization: We're also safe if the buffer is non-empty and it ends
// with a byte that would terminate a varint.
(buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
uint64 temp;
::std::pair<bool, const uint8*> p = ReadVarint64FromArray(buffer_, &temp);
if (!p.first) {
return std::make_pair(0, false);
}
buffer_ = p.second;
return std::make_pair(temp, true);
} else {
uint64 temp;
bool success = ReadVarint64Slow(&temp);
return std::make_pair(temp, success);
}
}
bool CodedInputStream::Refresh() {
GOOGLE_DCHECK_EQ(0, BufferSize());
if (buffer_size_after_limit_ > 0 || overflow_bytes_ > 0 ||
total_bytes_read_ == current_limit_) {
// We've hit a limit. Stop.
int current_position = total_bytes_read_ - buffer_size_after_limit_;
if (current_position >= total_bytes_limit_ &&
total_bytes_limit_ != current_limit_) {
// Hit total_bytes_limit_.
PrintTotalBytesLimitError();
}
return false;
}
const void* void_buffer;
int buffer_size;
if (NextNonEmpty(input_, &void_buffer, &buffer_size)) {
buffer_ = reinterpret_cast<const uint8*>(void_buffer);
buffer_end_ = buffer_ + buffer_size;
GOOGLE_CHECK_GE(buffer_size, 0);
if (total_bytes_read_ <= INT_MAX - buffer_size) {
total_bytes_read_ += buffer_size;
} else {
// Overflow. Reset buffer_end_ to not include the bytes beyond INT_MAX.
// We can't get that far anyway, because total_bytes_limit_ is guaranteed
// to be less than it. We need to keep track of the number of bytes
// we discarded, though, so that we can call input_->BackUp() to back
// up over them on destruction.
// The following line is equivalent to:
// overflow_bytes_ = total_bytes_read_ + buffer_size - INT_MAX;
// except that it avoids overflows. Signed integer overflow has
// undefined results according to the C standard.
overflow_bytes_ = total_bytes_read_ - (INT_MAX - buffer_size);
buffer_end_ -= overflow_bytes_;
total_bytes_read_ = INT_MAX;
}
RecomputeBufferLimits();
return true;
} else {
buffer_ = NULL;
buffer_end_ = NULL;
return false;
}
}
// CodedOutputStream =================================================
std::atomic<bool> CodedOutputStream::default_serialization_deterministic_{
false};
CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* output)
: CodedOutputStream(output, true) {}
CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* output,
bool do_eager_refresh)
: output_(output),
buffer_(NULL),
buffer_size_(0),
total_bytes_(0),
had_error_(false),
aliasing_enabled_(false),
is_serialization_deterministic_(IsDefaultSerializationDeterministic()) {
if (do_eager_refresh) {
// Eagerly Refresh() so buffer space is immediately available.
Refresh();
// The Refresh() may have failed. If the client doesn't write any data,
// though, don't consider this an error. If the client does write data, then
// another Refresh() will be attempted and it will set the error once again.
had_error_ = false;
}
}
CodedOutputStream::~CodedOutputStream() {
Trim();
}
void CodedOutputStream::Trim() {
if (buffer_size_ > 0) {
output_->BackUp(buffer_size_);
total_bytes_ -= buffer_size_;
buffer_size_ = 0;
buffer_ = NULL;
}
}
bool CodedOutputStream::Skip(int count) {
if (count < 0) return false;
while (count > buffer_size_) {
count -= buffer_size_;
if (!Refresh()) return false;
}
Advance(count);
return true;
}
bool CodedOutputStream::GetDirectBufferPointer(void** data, int* size) {
if (buffer_size_ == 0 && !Refresh()) return false;
*data = buffer_;
*size = buffer_size_;
return true;
}
void CodedOutputStream::WriteRaw(const void* data, int size) {
while (buffer_size_ < size) {
memcpy(buffer_, data, buffer_size_);
size -= buffer_size_;
data = reinterpret_cast<const uint8*>(data) + buffer_size_;
if (!Refresh()) return;
}
memcpy(buffer_, data, size);
Advance(size);
}
uint8* CodedOutputStream::WriteRawToArray(
const void* data, int size, uint8* target) {
memcpy(target, data, size);
return target + size;
}
void CodedOutputStream::WriteAliasedRaw(const void* data, int size) {
if (size < buffer_size_
) {
WriteRaw(data, size);
} else {
Trim();
total_bytes_ += size;
had_error_ |= !output_->WriteAliasedRaw(data, size);
}
}
void CodedOutputStream::WriteLittleEndian32(uint32 value) {
uint8 bytes[sizeof(value)];
bool use_fast = buffer_size_ >= sizeof(value);
uint8* ptr = use_fast ? buffer_ : bytes;
WriteLittleEndian32ToArray(value, ptr);
if (use_fast) {
Advance(sizeof(value));
} else {
WriteRaw(bytes, sizeof(value));
}
}
void CodedOutputStream::WriteLittleEndian64(uint64 value) {
uint8 bytes[sizeof(value)];
bool use_fast = buffer_size_ >= sizeof(value);
uint8* ptr = use_fast ? buffer_ : bytes;
WriteLittleEndian64ToArray(value, ptr);
if (use_fast) {
Advance(sizeof(value));
} else {
WriteRaw(bytes, sizeof(value));
}
}
void CodedOutputStream::WriteVarint32SlowPath(uint32 value) {
uint8 bytes[kMaxVarint32Bytes];
uint8* target = &bytes[0];
uint8* end = WriteVarint32ToArray(value, target);
int size = end - target;
WriteRaw(bytes, size);
}
void CodedOutputStream::WriteVarint64SlowPath(uint64 value) {
uint8 bytes[kMaxVarintBytes];
uint8* target = &bytes[0];
uint8* end = WriteVarint64ToArray(value, target);
int size = end - target;
WriteRaw(bytes, size);
}
bool CodedOutputStream::Refresh() {
void* void_buffer;
if (output_->Next(&void_buffer, &buffer_size_)) {
buffer_ = reinterpret_cast<uint8*>(void_buffer);
total_bytes_ += buffer_size_;
return true;
} else {
buffer_ = NULL;
buffer_size_ = 0;
had_error_ = true;
return false;
}
}
uint8* CodedOutputStream::WriteStringWithSizeToArray(const string& str,
uint8* target) {
GOOGLE_DCHECK_LE(str.size(), kuint32max);
target = WriteVarint32ToArray(str.size(), target);
return WriteStringToArray(str, target);
}
} // namespace io
} // namespace protobuf
} // namespace google

389
third_party/protobuf-lite/common.cc vendored Normal file
View File

@ -0,0 +1,389 @@
// 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)
#include <google/protobuf/message_lite.h> // TODO(gerbens) ideally remove this.
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/once.h>
#include <google/protobuf/stubs/status.h>
#include <google/protobuf/stubs/stringpiece.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/int128.h>
#include <errno.h>
#include <sstream>
#include <stdio.h>
#include <vector>
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN // We only need minimal includes
#include <windows.h>
#define snprintf _snprintf // see comment in strutil.cc
#elif defined(HAVE_PTHREAD)
#include <pthread.h>
#else
#error "No suitable threading library available."
#endif
#if defined(__ANDROID__)
#include <android/log.h>
#endif
namespace google {
namespace protobuf {
namespace internal {
void VerifyVersion(int headerVersion,
int minLibraryVersion,
const char* filename) {
if (GOOGLE_PROTOBUF_VERSION < minLibraryVersion) {
// Library is too old for headers.
GOOGLE_LOG(FATAL)
<< "This program requires version " << VersionString(minLibraryVersion)
<< " of the Protocol Buffer runtime library, but the installed version "
"is " << VersionString(GOOGLE_PROTOBUF_VERSION) << ". Please update "
"your library. If you compiled the program yourself, make sure that "
"your headers are from the same version of Protocol Buffers as your "
"link-time library. (Version verification failed in \""
<< filename << "\".)";
}
if (headerVersion < kMinHeaderVersionForLibrary) {
// Headers are too old for library.
GOOGLE_LOG(FATAL)
<< "This program was compiled against version "
<< VersionString(headerVersion) << " of the Protocol Buffer runtime "
"library, which is not compatible with the installed version ("
<< VersionString(GOOGLE_PROTOBUF_VERSION) << "). Contact the program "
"author for an update. If you compiled the program yourself, make "
"sure that your headers are from the same version of Protocol Buffers "
"as your link-time library. (Version verification failed in \""
<< filename << "\".)";
}
}
string VersionString(int version) {
int major = version / 1000000;
int minor = (version / 1000) % 1000;
int micro = version % 1000;
// 128 bytes should always be enough, but we use snprintf() anyway to be
// safe.
char buffer[128];
snprintf(buffer, sizeof(buffer), "%d.%d.%d", major, minor, micro);
// Guard against broken MSVC snprintf().
buffer[sizeof(buffer)-1] = '\0';
return buffer;
}
} // namespace internal
// ===================================================================
// emulates google3/base/logging.cc
// If the minimum logging level is not set, we default to logging messages for
// all levels.
#ifndef GOOGLE_PROTOBUF_MIN_LOG_LEVEL
#define GOOGLE_PROTOBUF_MIN_LOG_LEVEL LOGLEVEL_INFO
#endif
namespace internal {
#if defined(__ANDROID__)
inline void DefaultLogHandler(LogLevel level, const char* filename, int line,
const string& message) {
if (level < GOOGLE_PROTOBUF_MIN_LOG_LEVEL) {
return;
}
static const char* level_names[] = {"INFO", "WARNING", "ERROR", "FATAL"};
static const int android_log_levels[] = {
ANDROID_LOG_INFO, // LOG(INFO),
ANDROID_LOG_WARN, // LOG(WARNING)
ANDROID_LOG_ERROR, // LOG(ERROR)
ANDROID_LOG_FATAL, // LOG(FATAL)
};
// Bound the logging level.
const int android_log_level = android_log_levels[level];
::std::ostringstream ostr;
ostr << "[libprotobuf " << level_names[level] << " " << filename << ":"
<< line << "] " << message.c_str();
// Output the log string the Android log at the appropriate level.
__android_log_write(android_log_level, "libprotobuf-native",
ostr.str().c_str());
// Also output to std::cerr.
fprintf(stderr, "%s", ostr.str().c_str());
fflush(stderr);
// Indicate termination if needed.
if (android_log_level == ANDROID_LOG_FATAL) {
__android_log_write(ANDROID_LOG_FATAL, "libprotobuf-native",
"terminating.\n");
}
}
#else
void DefaultLogHandler(LogLevel level, const char* filename, int line,
const string& message) {
if (level < GOOGLE_PROTOBUF_MIN_LOG_LEVEL) {
return;
}
static const char* level_names[] = { "INFO", "WARNING", "ERROR", "FATAL" };
// We use fprintf() instead of cerr because we want this to work at static
// initialization time.
fprintf(stderr, "[libprotobuf %s %s:%d] %s\n",
level_names[level], filename, line, message.c_str());
fflush(stderr); // Needed on MSVC.
}
#endif
void NullLogHandler(LogLevel /* level */, const char* /* filename */,
int /* line */, const string& /* message */) {
// Nothing.
}
static LogHandler* log_handler_ = &DefaultLogHandler;
static int log_silencer_count_ = 0;
static Mutex* log_silencer_count_mutex_ = NULL;
GOOGLE_PROTOBUF_DECLARE_ONCE(log_silencer_count_init_);
void DeleteLogSilencerCount() {
delete log_silencer_count_mutex_;
log_silencer_count_mutex_ = NULL;
}
void InitLogSilencerCount() {
log_silencer_count_mutex_ = new Mutex;
OnShutdown(&DeleteLogSilencerCount);
}
void InitLogSilencerCountOnce() {
GoogleOnceInit(&log_silencer_count_init_, &InitLogSilencerCount);
}
LogMessage& LogMessage::operator<<(const string& value) {
message_ += value;
return *this;
}
LogMessage& LogMessage::operator<<(const char* value) {
message_ += value;
return *this;
}
LogMessage& LogMessage::operator<<(const StringPiece& value) {
message_ += value.ToString();
return *this;
}
LogMessage& LogMessage::operator<<(
const ::google::protobuf::util::Status& status) {
message_ += status.ToString();
return *this;
}
LogMessage& LogMessage::operator<<(const uint128& value) {
std::ostringstream str;
str << value;
message_ += str.str();
return *this;
}
// Since this is just for logging, we don't care if the current locale changes
// the results -- in fact, we probably prefer that. So we use snprintf()
// instead of Simple*toa().
#undef DECLARE_STREAM_OPERATOR
#define DECLARE_STREAM_OPERATOR(TYPE, FORMAT) \
LogMessage& LogMessage::operator<<(TYPE value) { \
/* 128 bytes should be big enough for any of the primitive */ \
/* values which we print with this, but well use snprintf() */ \
/* anyway to be extra safe. */ \
char buffer[128]; \
snprintf(buffer, sizeof(buffer), FORMAT, value); \
/* Guard against broken MSVC snprintf(). */ \
buffer[sizeof(buffer)-1] = '\0'; \
message_ += buffer; \
return *this; \
}
DECLARE_STREAM_OPERATOR(char , "%c" )
DECLARE_STREAM_OPERATOR(int , "%d" )
DECLARE_STREAM_OPERATOR(unsigned int , "%u" )
DECLARE_STREAM_OPERATOR(long , "%ld")
DECLARE_STREAM_OPERATOR(unsigned long, "%lu")
DECLARE_STREAM_OPERATOR(double , "%g" )
DECLARE_STREAM_OPERATOR(void* , "%p" )
DECLARE_STREAM_OPERATOR(long long , "%" GOOGLE_LL_FORMAT "d")
DECLARE_STREAM_OPERATOR(unsigned long long, "%" GOOGLE_LL_FORMAT "u")
#undef DECLARE_STREAM_OPERATOR
LogMessage::LogMessage(LogLevel level, const char* filename, int line)
: level_(level), filename_(filename), line_(line) {}
LogMessage::~LogMessage() {}
void LogMessage::Finish() {
bool suppress = false;
if (level_ != LOGLEVEL_FATAL) {
InitLogSilencerCountOnce();
MutexLock lock(log_silencer_count_mutex_);
suppress = log_silencer_count_ > 0;
}
if (!suppress) {
log_handler_(level_, filename_, line_, message_);
}
if (level_ == LOGLEVEL_FATAL) {
#if PROTOBUF_USE_EXCEPTIONS
throw FatalException(filename_, line_, message_);
#else
abort();
#endif
}
}
void LogFinisher::operator=(LogMessage& other) {
other.Finish();
}
} // namespace internal
LogHandler* SetLogHandler(LogHandler* new_func) {
LogHandler* old = internal::log_handler_;
if (old == &internal::NullLogHandler) {
old = NULL;
}
if (new_func == NULL) {
internal::log_handler_ = &internal::NullLogHandler;
} else {
internal::log_handler_ = new_func;
}
return old;
}
LogSilencer::LogSilencer() {
internal::InitLogSilencerCountOnce();
MutexLock lock(internal::log_silencer_count_mutex_);
++internal::log_silencer_count_;
};
LogSilencer::~LogSilencer() {
internal::InitLogSilencerCountOnce();
MutexLock lock(internal::log_silencer_count_mutex_);
--internal::log_silencer_count_;
};
// ===================================================================
// emulates google3/base/callback.cc
Closure::~Closure() {}
namespace internal { FunctionClosure0::~FunctionClosure0() {} }
void DoNothing() {}
// ===================================================================
// emulates google3/util/endian/endian.h
//
// TODO(xiaofeng): PROTOBUF_LITTLE_ENDIAN is unfortunately defined in
// google/protobuf/io/coded_stream.h and therefore can not be used here.
// Maybe move that macro definition here in the furture.
uint32 ghtonl(uint32 x) {
union {
uint32 result;
uint8 result_array[4];
};
result_array[0] = static_cast<uint8>(x >> 24);
result_array[1] = static_cast<uint8>((x >> 16) & 0xFF);
result_array[2] = static_cast<uint8>((x >> 8) & 0xFF);
result_array[3] = static_cast<uint8>(x & 0xFF);
return result;
}
// ===================================================================
// Shutdown support.
namespace internal {
typedef void OnShutdownFunc();
struct ShutdownData {
~ShutdownData() {
std::reverse(functions.begin(), functions.end());
for (auto pair : functions) pair.first(pair.second);
}
static ShutdownData* get() {
static auto* data = new ShutdownData;
return data;
}
std::vector<std::pair<void (*)(const void*), const void*>> functions;
Mutex mutex;
};
static void RunZeroArgFunc(const void* arg) {
reinterpret_cast<void (*)()>(const_cast<void*>(arg))();
}
void OnShutdown(void (*func)()) {
OnShutdownRun(RunZeroArgFunc, reinterpret_cast<void*>(func));
}
void OnShutdownRun(void (*f)(const void*), const void* arg) {
auto shutdown_data = ShutdownData::get();
MutexLock lock(&shutdown_data->mutex);
shutdown_data->functions.push_back(std::make_pair(f, arg));
}
} // namespace internal
void ShutdownProtobufLibrary() {
// This function should be called only once, but accepts multiple calls.
static bool is_shutdown = false;
if (!is_shutdown) {
delete internal::ShutdownData::get();
is_shutdown = true;
}
}
#if PROTOBUF_USE_EXCEPTIONS
FatalException::~FatalException() throw() {}
const char* FatalException::what() const throw() {
return message_.c_str();
}
#endif
} // namespace protobuf
} // namespace google

1916
third_party/protobuf-lite/extension_set.cc vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,109 @@
// 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/generated_message_table_driven_lite.h>
#include <type_traits>
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
#include <google/protobuf/metadata_lite.h>
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/wire_format_lite.h>
#include <google/protobuf/wire_format_lite_inl.h>
namespace google {
namespace protobuf {
namespace internal {
namespace {
string* MutableUnknownFields(MessageLite* msg, int64 arena_offset) {
return Raw<InternalMetadataWithArenaLite>(msg, arena_offset)
->mutable_unknown_fields();
}
struct UnknownFieldHandlerLite {
static bool Skip(MessageLite* msg, const ParseTable& table,
io::CodedInputStream* input,
int tag) {
GOOGLE_DCHECK(!table.unknown_field_set);
::google::protobuf::io::StringOutputStream unknown_fields_string(
MutableUnknownFields(msg, table.arena_offset));
::google::protobuf::io::CodedOutputStream unknown_fields_stream(
&unknown_fields_string, false);
return ::google::protobuf::internal::WireFormatLite::SkipField(
input, tag, &unknown_fields_stream);
}
static void Varint(MessageLite* msg, const ParseTable& table,
int tag, int value) {
GOOGLE_DCHECK(!table.unknown_field_set);
::google::protobuf::io::StringOutputStream unknown_fields_string(
MutableUnknownFields(msg, table.arena_offset));
::google::protobuf::io::CodedOutputStream unknown_fields_stream(
&unknown_fields_string, false);
unknown_fields_stream.WriteVarint32(tag);
unknown_fields_stream.WriteVarint32(value);
}
static bool ParseExtension(
MessageLite* msg, const ParseTable& table,
io::CodedInputStream* input, int tag) {
ExtensionSet* extensions = GetExtensionSet(msg, table.extension_offset);
if (extensions == NULL) {
return false;
}
const MessageLite* prototype = table.default_instance();
GOOGLE_DCHECK(!table.unknown_field_set);
::google::protobuf::io::StringOutputStream unknown_fields_string(
MutableUnknownFields(msg, table.arena_offset));
::google::protobuf::io::CodedOutputStream unknown_fields_stream(
&unknown_fields_string, false);
return extensions->ParseField(
tag, input, prototype, &unknown_fields_stream);
}
};
} // namespace
bool MergePartialFromCodedStreamLite(
MessageLite* msg, const ParseTable& table, io::CodedInputStream* input) {
return MergePartialFromCodedStreamImpl<UnknownFieldHandlerLite,
InternalMetadataWithArenaLite>(
msg, table, input);
}
} // namespace internal
} // namespace protobuf
} // namespace google

View File

@ -0,0 +1,814 @@
// 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/generated_message_util.h>
#include <limits>
// We're only using this as a standard way for getting the thread id.
// We're not using any thread functionality.
#include <thread> // NOLINT
#include <vector>
#include <google/protobuf/io/coded_stream_inl.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/arenastring.h>
#include <google/protobuf/extension_set.h>
#include <google/protobuf/message_lite.h>
#include <google/protobuf/metadata_lite.h>
#include <google/protobuf/stubs/mutex.h>
#include <google/protobuf/stubs/port.h>
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/wire_format_lite.h>
#include <google/protobuf/wire_format_lite_inl.h>
namespace google {
namespace protobuf {
namespace internal {
void DestroyMessage(const void* message) {
static_cast<const MessageLite*>(message)->~MessageLite();
}
void DestroyString(const void* s) { static_cast<const string*>(s)->~string(); }
ExplicitlyConstructed<std::string> fixed_address_empty_string;
double Infinity() {
return std::numeric_limits<double>::infinity();
}
double NaN() {
return std::numeric_limits<double>::quiet_NaN();
}
static bool InitProtobufDefaultsImpl() {
fixed_address_empty_string.DefaultConstruct();
OnShutdownDestroyString(fixed_address_empty_string.get_mutable());
return true;
}
void InitProtobufDefaults() {
static bool is_inited = InitProtobufDefaultsImpl();
(void)is_inited;
}
size_t StringSpaceUsedExcludingSelfLong(const string& str) {
const void* start = &str;
const void* end = &str + 1;
if (start <= str.data() && str.data() < end) {
// The string's data is stored inside the string object itself.
return 0;
} else {
return str.capacity();
}
}
template <typename T>
const T& Get(const void* ptr) {
return *static_cast<const T*>(ptr);
}
// PrimitiveTypeHelper is a wrapper around the interface of WireFormatLite.
// WireFormatLite has a very inconvenient interface with respect to template
// meta-programming. This class wraps the different named functions into
// a single Serialize / SerializeToArray interface.
template <int type>
struct PrimitiveTypeHelper;
template <>
struct PrimitiveTypeHelper<WireFormatLite::TYPE_BOOL> {
typedef bool Type;
static void Serialize(const void* ptr,
::google::protobuf::io::CodedOutputStream* output) {
WireFormatLite::WriteBoolNoTag(Get<bool>(ptr), output);
}
static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
return WireFormatLite::WriteBoolNoTagToArray(Get<Type>(ptr), buffer);
}
};
template <>
struct PrimitiveTypeHelper<WireFormatLite::TYPE_INT32> {
typedef int32 Type;
static void Serialize(const void* ptr,
::google::protobuf::io::CodedOutputStream* output) {
WireFormatLite::WriteInt32NoTag(Get<int32>(ptr), output);
}
static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
return WireFormatLite::WriteInt32NoTagToArray(Get<Type>(ptr), buffer);
}
};
template <>
struct PrimitiveTypeHelper<WireFormatLite::TYPE_SINT32> {
typedef int32 Type;
static void Serialize(const void* ptr,
::google::protobuf::io::CodedOutputStream* output) {
WireFormatLite::WriteSInt32NoTag(Get<int32>(ptr), output);
}
static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
return WireFormatLite::WriteSInt32NoTagToArray(Get<Type>(ptr), buffer);
}
};
template <>
struct PrimitiveTypeHelper<WireFormatLite::TYPE_UINT32> {
typedef uint32 Type;
static void Serialize(const void* ptr,
::google::protobuf::io::CodedOutputStream* output) {
WireFormatLite::WriteUInt32NoTag(Get<uint32>(ptr), output);
}
static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
return WireFormatLite::WriteUInt32NoTagToArray(Get<Type>(ptr), buffer);
}
};
template <>
struct PrimitiveTypeHelper<WireFormatLite::TYPE_INT64> {
typedef int64 Type;
static void Serialize(const void* ptr,
::google::protobuf::io::CodedOutputStream* output) {
WireFormatLite::WriteInt64NoTag(Get<int64>(ptr), output);
}
static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
return WireFormatLite::WriteInt64NoTagToArray(Get<Type>(ptr), buffer);
}
};
template <>
struct PrimitiveTypeHelper<WireFormatLite::TYPE_SINT64> {
typedef int64 Type;
static void Serialize(const void* ptr,
::google::protobuf::io::CodedOutputStream* output) {
WireFormatLite::WriteSInt64NoTag(Get<int64>(ptr), output);
}
static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
return WireFormatLite::WriteSInt64NoTagToArray(Get<Type>(ptr), buffer);
}
};
template <>
struct PrimitiveTypeHelper<WireFormatLite::TYPE_UINT64> {
typedef uint64 Type;
static void Serialize(const void* ptr,
::google::protobuf::io::CodedOutputStream* output) {
WireFormatLite::WriteUInt64NoTag(Get<uint64>(ptr), output);
}
static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
return WireFormatLite::WriteUInt64NoTagToArray(Get<Type>(ptr), buffer);
}
};
template <>
struct PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED32> {
typedef uint32 Type;
static void Serialize(const void* ptr,
::google::protobuf::io::CodedOutputStream* output) {
WireFormatLite::WriteFixed32NoTag(Get<uint32>(ptr), output);
}
static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
return WireFormatLite::WriteFixed32NoTagToArray(Get<Type>(ptr), buffer);
}
};
template <>
struct PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED64> {
typedef uint64 Type;
static void Serialize(const void* ptr,
::google::protobuf::io::CodedOutputStream* output) {
WireFormatLite::WriteFixed64NoTag(Get<uint64>(ptr), output);
}
static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
return WireFormatLite::WriteFixed64NoTagToArray(Get<Type>(ptr), buffer);
}
};
template <>
struct PrimitiveTypeHelper<WireFormatLite::TYPE_ENUM>
: PrimitiveTypeHelper<WireFormatLite::TYPE_INT32> {};
template <>
struct PrimitiveTypeHelper<WireFormatLite::TYPE_SFIXED32>
: PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED32> {
typedef int32 Type;
};
template <>
struct PrimitiveTypeHelper<WireFormatLite::TYPE_SFIXED64>
: PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED64> {
typedef int64 Type;
};
template <>
struct PrimitiveTypeHelper<WireFormatLite::TYPE_FLOAT>
: PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED32> {
typedef float Type;
};
template <>
struct PrimitiveTypeHelper<WireFormatLite::TYPE_DOUBLE>
: PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED64> {
typedef double Type;
};
template <>
struct PrimitiveTypeHelper<WireFormatLite::TYPE_STRING> {
typedef string Type;
static void Serialize(const void* ptr,
::google::protobuf::io::CodedOutputStream* output) {
const Type& value = *static_cast<const Type*>(ptr);
output->WriteVarint32(value.size());
output->WriteRawMaybeAliased(value.data(), value.size());
}
static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
const Type& value = *static_cast<const Type*>(ptr);
return io::CodedOutputStream::WriteStringWithSizeToArray(value, buffer);
}
};
template <>
struct PrimitiveTypeHelper<WireFormatLite::TYPE_BYTES>
: PrimitiveTypeHelper<WireFormatLite::TYPE_STRING> {};
template <>
struct PrimitiveTypeHelper<FieldMetadata::kInlinedType>
: PrimitiveTypeHelper<WireFormatLite::TYPE_STRING> {};
// We want to serialize to both CodedOutputStream and directly into byte arrays
// without duplicating the code. In fact we might want extra output channels in
// the future.
template <typename O, int type>
struct OutputHelper;
template <int type, typename O>
void SerializeTo(const void* ptr, O* output) {
OutputHelper<O, type>::Serialize(ptr, output);
}
template <typename O>
void WriteTagTo(uint32 tag, O* output) {
SerializeTo<WireFormatLite::TYPE_UINT32>(&tag, output);
}
template <typename O>
void WriteLengthTo(uint32 length, O* output) {
SerializeTo<WireFormatLite::TYPE_UINT32>(&length, output);
}
// Specialization for coded output stream
template <int type>
struct OutputHelper<::google::protobuf::io::CodedOutputStream, type> {
static void Serialize(const void* ptr,
::google::protobuf::io::CodedOutputStream* output) {
PrimitiveTypeHelper<type>::Serialize(ptr, output);
}
};
// Specialization for writing into a plain array
struct ArrayOutput {
uint8* ptr;
bool is_deterministic;
};
template <int type>
struct OutputHelper<ArrayOutput, type> {
static void Serialize(const void* ptr, ArrayOutput* output) {
output->ptr = PrimitiveTypeHelper<type>::SerializeToArray(ptr, output->ptr);
}
};
void SerializeMessageNoTable(const MessageLite* msg,
::google::protobuf::io::CodedOutputStream* output) {
msg->SerializeWithCachedSizes(output);
}
void SerializeMessageNoTable(const MessageLite* msg, ArrayOutput* output) {
output->ptr = msg->InternalSerializeWithCachedSizesToArray(
output->is_deterministic, output->ptr);
}
// Helper to branch to fast path if possible
void SerializeMessageDispatch(const ::google::protobuf::MessageLite& msg,
const FieldMetadata* field_table, int num_fields,
int32 cached_size,
::google::protobuf::io::CodedOutputStream* output) {
const uint8* base = reinterpret_cast<const uint8*>(&msg);
// Try the fast path
uint8* ptr = output->GetDirectBufferForNBytesAndAdvance(cached_size);
if (ptr) {
// We use virtual dispatch to enable dedicated generated code for the
// fast path.
msg.InternalSerializeWithCachedSizesToArray(
output->IsSerializationDeterministic(), ptr);
return;
}
SerializeInternal(base, field_table, num_fields, output);
}
// Helper to branch to fast path if possible
void SerializeMessageDispatch(const ::google::protobuf::MessageLite& msg,
const FieldMetadata* field_table, int num_fields,
int32 cached_size, ArrayOutput* output) {
const uint8* base = reinterpret_cast<const uint8*>(&msg);
output->ptr = SerializeInternalToArray(base, field_table, num_fields,
output->is_deterministic, output->ptr);
}
// Serializing messages is special as it's not a primitive type and needs an
// explicit overload for each output type.
template <typename O>
void SerializeMessageTo(const MessageLite* msg, const void* table_ptr,
O* output) {
const SerializationTable* table =
static_cast<const SerializationTable*>(table_ptr);
if (!table) {
// Proto1
WriteLengthTo(msg->GetCachedSize(), output);
SerializeMessageNoTable(msg, output);
return;
}
const FieldMetadata* field_table = table->field_table;
const uint8* base = reinterpret_cast<const uint8*>(msg);
int cached_size = *reinterpret_cast<const int32*>(base + field_table->offset);
WriteLengthTo(cached_size, output);
int num_fields = table->num_fields - 1;
SerializeMessageDispatch(*msg, field_table + 1, num_fields, cached_size,
output);
}
// Almost the same as above only it doesn't output the length field.
template <typename O>
void SerializeGroupTo(const MessageLite* msg, const void* table_ptr,
O* output) {
const SerializationTable* table =
static_cast<const SerializationTable*>(table_ptr);
if (!table) {
// Proto1
SerializeMessageNoTable(msg, output);
return;
}
const FieldMetadata* field_table = table->field_table;
const uint8* base = reinterpret_cast<const uint8*>(msg);
int cached_size = *reinterpret_cast<const int32*>(base + field_table->offset);
int num_fields = table->num_fields - 1;
SerializeMessageDispatch(*msg, field_table + 1, num_fields, cached_size,
output);
}
template <int type>
struct SingularFieldHelper {
template <typename O>
static void Serialize(const void* field, const FieldMetadata& md, O* output) {
WriteTagTo(md.tag, output);
SerializeTo<type>(field, output);
}
};
template <>
struct SingularFieldHelper<WireFormatLite::TYPE_STRING> {
template <typename O>
static void Serialize(const void* field, const FieldMetadata& md, O* output) {
WriteTagTo(md.tag, output);
SerializeTo<WireFormatLite::TYPE_STRING>(&Get<ArenaStringPtr>(field).Get(),
output);
}
};
template <>
struct SingularFieldHelper<WireFormatLite::TYPE_BYTES>
: SingularFieldHelper<WireFormatLite::TYPE_STRING> {};
template <>
struct SingularFieldHelper<WireFormatLite::TYPE_GROUP> {
template <typename O>
static void Serialize(const void* field, const FieldMetadata& md, O* output) {
WriteTagTo(md.tag, output);
SerializeGroupTo(Get<const MessageLite*>(field),
static_cast<const SerializationTable*>(md.ptr), output);
WriteTagTo(md.tag + 1, output);
}
};
template <>
struct SingularFieldHelper<WireFormatLite::TYPE_MESSAGE> {
template <typename O>
static void Serialize(const void* field, const FieldMetadata& md, O* output) {
WriteTagTo(md.tag, output);
SerializeMessageTo(Get<const MessageLite*>(field),
static_cast<const SerializationTable*>(md.ptr), output);
}
};
template <>
struct SingularFieldHelper<FieldMetadata::kInlinedType> {
template <typename O>
static void Serialize(const void* field, const FieldMetadata& md, O* output) {
WriteTagTo(md.tag, output);
SerializeTo<FieldMetadata::kInlinedType>(&Get<::std::string>(field), output);
}
};
template <int type>
struct RepeatedFieldHelper {
template <typename O>
static void Serialize(const void* field, const FieldMetadata& md, O* output) {
typedef typename PrimitiveTypeHelper<type>::Type T;
const RepeatedField<T>& array = Get<RepeatedField<T> >(field);
for (int i = 0; i < array.size(); i++) {
WriteTagTo(md.tag, output);
SerializeTo<type>(&array[i], output);
}
}
};
// We need to use a helper class to get access to the private members
class AccessorHelper {
public:
static int Size(const RepeatedPtrFieldBase& x) { return x.size(); }
static void const* Get(const RepeatedPtrFieldBase& x, int idx) {
return x.raw_data()[idx];
}
};
template <>
struct RepeatedFieldHelper<WireFormatLite::TYPE_STRING> {
template <typename O>
static void Serialize(const void* field, const FieldMetadata& md, O* output) {
const internal::RepeatedPtrFieldBase& array =
Get<internal::RepeatedPtrFieldBase>(field);
for (int i = 0; i < AccessorHelper::Size(array); i++) {
WriteTagTo(md.tag, output);
SerializeTo<WireFormatLite::TYPE_STRING>(AccessorHelper::Get(array, i),
output);
}
}
};
template <>
struct RepeatedFieldHelper<WireFormatLite::TYPE_BYTES>
: RepeatedFieldHelper<WireFormatLite::TYPE_STRING> {};
template <>
struct RepeatedFieldHelper<WireFormatLite::TYPE_GROUP> {
template <typename O>
static void Serialize(const void* field, const FieldMetadata& md, O* output) {
const internal::RepeatedPtrFieldBase& array =
Get<internal::RepeatedPtrFieldBase>(field);
for (int i = 0; i < AccessorHelper::Size(array); i++) {
WriteTagTo(md.tag, output);
SerializeGroupTo(
static_cast<const MessageLite*>(AccessorHelper::Get(array, i)),
static_cast<const SerializationTable*>(md.ptr), output);
WriteTagTo(md.tag + 1, output);
}
}
};
template <>
struct RepeatedFieldHelper<WireFormatLite::TYPE_MESSAGE> {
template <typename O>
static void Serialize(const void* field, const FieldMetadata& md, O* output) {
const internal::RepeatedPtrFieldBase& array =
Get<internal::RepeatedPtrFieldBase>(field);
for (int i = 0; i < AccessorHelper::Size(array); i++) {
WriteTagTo(md.tag, output);
SerializeMessageTo(
static_cast<const MessageLite*>(AccessorHelper::Get(array, i)), md.ptr,
output);
}
}
};
template <>
struct RepeatedFieldHelper<FieldMetadata::kInlinedType>
: RepeatedFieldHelper<WireFormatLite::TYPE_STRING> {};
template <int type>
struct PackedFieldHelper {
template <typename O>
static void Serialize(const void* field, const FieldMetadata& md, O* output) {
typedef typename PrimitiveTypeHelper<type>::Type T;
const RepeatedField<T>& array = Get<RepeatedField<T> >(field);
if (array.empty()) return;
WriteTagTo(md.tag, output);
int cached_size =
Get<int>(static_cast<const uint8*>(field) + sizeof(RepeatedField<T>));
WriteLengthTo(cached_size, output);
for (int i = 0; i < array.size(); i++) {
SerializeTo<type>(&array[i], output);
}
}
};
template <>
struct PackedFieldHelper<WireFormatLite::TYPE_STRING> {
template <typename O>
static void Serialize(const void* field, const FieldMetadata& md, O* output) {
GOOGLE_LOG(FATAL) << "Not implemented field number " << md.tag << " with type "
<< md.type;
}
};
template <>
struct PackedFieldHelper<WireFormatLite::TYPE_BYTES>
: PackedFieldHelper<WireFormatLite::TYPE_STRING> {};
template <>
struct PackedFieldHelper<WireFormatLite::TYPE_GROUP>
: PackedFieldHelper<WireFormatLite::TYPE_STRING> {};
template <>
struct PackedFieldHelper<WireFormatLite::TYPE_MESSAGE>
: PackedFieldHelper<WireFormatLite::TYPE_STRING> {};
template <>
struct PackedFieldHelper<FieldMetadata::kInlinedType>
: PackedFieldHelper<WireFormatLite::TYPE_STRING> {};
template <int type>
struct OneOfFieldHelper {
template <typename O>
static void Serialize(const void* field, const FieldMetadata& md, O* output) {
SingularFieldHelper<type>::Serialize(field, md, output);
}
};
template <>
struct OneOfFieldHelper<FieldMetadata::kInlinedType> {
template <typename O>
static void Serialize(const void* field, const FieldMetadata& md, O* output) {
SingularFieldHelper<FieldMetadata::kInlinedType>::Serialize(
Get<const ::std::string*>(field), md, output);
}
};
void SerializeNotImplemented(int field) {
GOOGLE_LOG(FATAL) << "Not implemented field number " << field;
}
// When switching to c++11 we should make these constexpr functions
#define SERIALIZE_TABLE_OP(type, type_class) \
((type - 1) + static_cast<int>(type_class) * FieldMetadata::kNumTypes)
int FieldMetadata::CalculateType(int type,
FieldMetadata::FieldTypeClass type_class) {
return SERIALIZE_TABLE_OP(type, type_class);
}
template <int type>
bool IsNull(const void* ptr) {
return *static_cast<const typename PrimitiveTypeHelper<type>::Type*>(ptr) ==
0;
}
template <>
bool IsNull<WireFormatLite::TYPE_STRING>(const void* ptr) {
return static_cast<const ArenaStringPtr*>(ptr)->Get().size() == 0;
}
template <>
bool IsNull<WireFormatLite::TYPE_BYTES>(const void* ptr) {
return static_cast<const ArenaStringPtr*>(ptr)->Get().size() == 0;
}
template <>
bool IsNull<WireFormatLite::TYPE_GROUP>(const void* ptr) {
return Get<const MessageLite*>(ptr) == NULL;
}
template <>
bool IsNull<WireFormatLite::TYPE_MESSAGE>(const void* ptr) {
return Get<const MessageLite*>(ptr) == NULL;
}
template <>
bool IsNull<FieldMetadata::kInlinedType>(const void* ptr) {
return static_cast<const ::std::string*>(ptr)->empty();
}
#define SERIALIZERS_FOR_TYPE(type) \
case SERIALIZE_TABLE_OP(type, FieldMetadata::kPresence): \
if (!IsPresent(base, field_metadata.has_offset)) continue; \
SingularFieldHelper<type>::Serialize(ptr, field_metadata, output); \
break; \
case SERIALIZE_TABLE_OP(type, FieldMetadata::kNoPresence): \
if (IsNull<type>(ptr)) continue; \
SingularFieldHelper<type>::Serialize(ptr, field_metadata, output); \
break; \
case SERIALIZE_TABLE_OP(type, FieldMetadata::kRepeated): \
RepeatedFieldHelper<type>::Serialize(ptr, field_metadata, output); \
break; \
case SERIALIZE_TABLE_OP(type, FieldMetadata::kPacked): \
PackedFieldHelper<type>::Serialize(ptr, field_metadata, output); \
break; \
case SERIALIZE_TABLE_OP(type, FieldMetadata::kOneOf): \
if (!IsOneofPresent(base, field_metadata.has_offset, field_metadata.tag)) \
continue; \
OneOfFieldHelper<type>::Serialize(ptr, field_metadata, output); \
break
void SerializeInternal(const uint8* base,
const FieldMetadata* field_metadata_table,
int32 num_fields,
::google::protobuf::io::CodedOutputStream* output) {
for (int i = 0; i < num_fields; i++) {
const FieldMetadata& field_metadata = field_metadata_table[i];
const uint8* ptr = base + field_metadata.offset;
switch (field_metadata.type) {
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_DOUBLE);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FLOAT);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_INT64);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_UINT64);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_INT32);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FIXED64);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FIXED32);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_BOOL);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_STRING);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_GROUP);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_MESSAGE);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_BYTES);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_UINT32);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_ENUM);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SFIXED32);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SFIXED64);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SINT32);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SINT64);
SERIALIZERS_FOR_TYPE(FieldMetadata::kInlinedType);
// Special cases
case FieldMetadata::kSpecial:
reinterpret_cast<SpecialSerializer>(
const_cast<void*>(field_metadata.ptr))(
base, field_metadata.offset, field_metadata.tag,
field_metadata.has_offset, output);
break;
default:
// __builtin_unreachable()
SerializeNotImplemented(field_metadata.type);
}
}
}
uint8* SerializeInternalToArray(const uint8* base,
const FieldMetadata* field_metadata_table,
int32 num_fields, bool is_deterministic,
uint8* buffer) {
ArrayOutput array_output = {buffer, is_deterministic};
ArrayOutput* output = &array_output;
for (int i = 0; i < num_fields; i++) {
const FieldMetadata& field_metadata = field_metadata_table[i];
const uint8* ptr = base + field_metadata.offset;
switch (field_metadata.type) {
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_DOUBLE);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FLOAT);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_INT64);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_UINT64);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_INT32);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FIXED64);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FIXED32);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_BOOL);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_STRING);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_GROUP);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_MESSAGE);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_BYTES);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_UINT32);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_ENUM);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SFIXED32);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SFIXED64);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SINT32);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SINT64);
SERIALIZERS_FOR_TYPE(FieldMetadata::kInlinedType);
// Special cases
case FieldMetadata::kSpecial: {
io::ArrayOutputStream array_stream(array_output.ptr, INT_MAX);
io::CodedOutputStream output(&array_stream);
output.SetSerializationDeterministic(is_deterministic);
reinterpret_cast<SpecialSerializer>(
const_cast<void*>(field_metadata.ptr))(
base, field_metadata.offset, field_metadata.tag,
field_metadata.has_offset, &output);
array_output.ptr += output.ByteCount();
} break;
default:
// __builtin_unreachable()
SerializeNotImplemented(field_metadata.type);
}
}
return array_output.ptr;
}
#undef SERIALIZERS_FOR_TYPE
void ExtensionSerializer(const uint8* ptr, uint32 offset, uint32 tag,
uint32 has_offset,
::google::protobuf::io::CodedOutputStream* output) {
reinterpret_cast<const ExtensionSet*>(ptr + offset)
->SerializeWithCachedSizes(tag, has_offset, output);
}
void UnknownFieldSerializerLite(const uint8* ptr, uint32 offset, uint32 tag,
uint32 has_offset,
::google::protobuf::io::CodedOutputStream* output) {
output->WriteString(
reinterpret_cast<const InternalMetadataWithArenaLite*>(ptr + offset)
->unknown_fields());
}
MessageLite* DuplicateIfNonNullInternal(MessageLite* message) {
if (message) {
MessageLite* ret = message->New();
ret->CheckTypeAndMergeFrom(*message);
return ret;
} else {
return NULL;
}
}
// Returns a message owned by this Arena. This may require Own()ing or
// duplicating the message.
MessageLite* GetOwnedMessageInternal(Arena* message_arena,
MessageLite* submessage,
Arena* submessage_arena) {
GOOGLE_DCHECK(submessage->GetArena() == submessage_arena);
GOOGLE_DCHECK(message_arena != submessage_arena);
if (message_arena != NULL && submessage_arena == NULL) {
message_arena->Own(submessage);
return submessage;
} else {
MessageLite* ret = submessage->New(message_arena);
ret->CheckTypeAndMergeFrom(*submessage);
return ret;
}
}
namespace {
void InitSCC_DFS(SCCInfoBase* scc) {
if (scc->visit_status.load(std::memory_order_relaxed) !=
SCCInfoBase::kUninitialized) return;
scc->visit_status.store(SCCInfoBase::kRunning, std::memory_order_relaxed);
// Each base is followed by an array of pointers to deps
auto deps = reinterpret_cast<SCCInfoBase* const*>(scc + 1);
for (int i = 0; i < scc->num_deps; i++) {
if (deps[i]) InitSCC_DFS(deps[i]);
}
scc->init_func();
// Mark done (note we use memory order release here), other threads could
// now see this as initialized and thus the initialization must have happened
// before.
scc->visit_status.store(SCCInfoBase::kInitialized, std::memory_order_release);
}
} // namespace
void InitSCCImpl(SCCInfoBase* scc) {
static WrappedMutex mu{GOOGLE_PROTOBUF_LINKER_INITIALIZED};
// Either the default in case no initialization is running or the id of the
// thread that is currently initializing.
static std::atomic<std::thread::id> runner;
auto me = std::this_thread::get_id();
// This will only happen because the constructor will call InitSCC while
// constructing the default instance.
if (runner.load(std::memory_order_relaxed) == me) {
// Because we're in the process of constructing the default instance.
// We can be assured that we're already exploring this SCC.
GOOGLE_CHECK_EQ(scc->visit_status.load(std::memory_order_relaxed),
SCCInfoBase::kRunning);
return;
}
InitProtobufDefaults();
mu.Lock();
runner.store(me, std::memory_order_relaxed);
InitSCC_DFS(scc);
runner.store(std::thread::id{}, std::memory_order_relaxed);
mu.Unlock();
}
} // namespace internal
} // 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,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__

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,46 @@
// 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_GENERATED_ENUM_UTIL_H__
#define GOOGLE_PROTOBUF_GENERATED_ENUM_UTIL_H__
#include <type_traits>
namespace google {
namespace protobuf {
// This type trait can be used to cause templates to only match proto2 enum
// types.
template <typename T> struct is_proto_enum : ::std::false_type {};
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_GENERATED_ENUM_UTIL_H__

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.
#ifndef GOOGLE_PROTOBUF_GENERATED_MESSAGE_TABLE_DRIVEN_H__
#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_TABLE_DRIVEN_H__
#include <google/protobuf/map.h>
#include <google/protobuf/map_entry_lite.h>
#include <google/protobuf/map_field_lite.h>
#include <google/protobuf/message_lite.h>
#include <google/protobuf/wire_format_lite.h>
#include <google/protobuf/wire_format_lite_inl.h>
// We require C++11 and Clang to use constexpr for variables, as GCC 4.8
// requires constexpr to be consistent between declarations of variables
// unnecessarily (see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58541).
// VS 2017 Update 3 also supports this usage of constexpr.
#if defined(__clang__) || (defined(_MSC_VER) && _MSC_VER >= 1911)
#define PROTOBUF_CONSTEXPR_VAR constexpr
#else // !__clang__
#define PROTOBUF_CONSTEXPR_VAR
#endif // !_clang
namespace google {
namespace protobuf {
namespace internal {
// Processing-type masks.
static constexpr const unsigned char kOneofMask = 0x40;
static constexpr const unsigned char kRepeatedMask = 0x20;
// Mask for the raw type: either a WireFormatLite::FieldType or one of the
// ProcessingTypes below, without the oneof or repeated flag.
static constexpr const unsigned char kTypeMask = 0x1f;
// Wire type masks.
static constexpr const unsigned char kNotPackedMask = 0x10;
static constexpr const unsigned char kInvalidMask = 0x20;
enum ProcessingTypes {
TYPE_STRING_INLINED = 23,
TYPE_BYTES_INLINED = 24,
TYPE_MAP = 25,
};
static_assert(TYPE_MAP < kRepeatedMask, "Invalid enum");
// TODO(ckennelly): Add a static assertion to ensure that these masks do not
// conflict with wiretypes.
// ParseTableField is kept small to help simplify instructions for computing
// offsets, as we will always need this information to parse a field.
// Additional data, needed for some types, is stored in
// AuxillaryParseTableField.
struct ParseTableField {
uint32 offset;
// The presence_index ordinarily represents a has_bit index, but for fields
// inside a oneof it represents the index in _oneof_case_.
uint32 presence_index;
unsigned char normal_wiretype;
unsigned char packed_wiretype;
// processing_type is given by:
// (FieldDescriptor->type() << 1) | FieldDescriptor->is_packed()
unsigned char processing_type;
unsigned char tag_size;
};
struct ParseTable;
union AuxillaryParseTableField {
typedef bool (*EnumValidator)(int);
// Enums
struct enum_aux {
EnumValidator validator;
};
enum_aux enums;
// Group, messages
struct message_aux {
// ExplicitlyInitialized<T> -> T requires a reinterpret_cast, which prevents
// the tables from being constructed as a constexpr. We use void to avoid
// the cast.
const void* default_message_void;
const MessageLite* default_message() const {
return static_cast<const MessageLite*>(default_message_void);
}
};
message_aux messages;
// Strings
struct string_aux {
const void* default_ptr;
const char* field_name;
};
string_aux strings;
struct map_aux {
bool (*parse_map)(io::CodedInputStream*, void*);
};
map_aux maps;
AuxillaryParseTableField() = default;
constexpr AuxillaryParseTableField(AuxillaryParseTableField::enum_aux e)
: enums(e) {}
constexpr AuxillaryParseTableField(AuxillaryParseTableField::message_aux m)
: messages(m) {}
constexpr AuxillaryParseTableField(AuxillaryParseTableField::string_aux s)
: strings(s) {}
constexpr AuxillaryParseTableField(AuxillaryParseTableField::map_aux m)
: maps(m) {}
};
struct ParseTable {
const ParseTableField* fields;
const AuxillaryParseTableField* aux;
int max_field_number;
// TODO(ckennelly): Do something with this padding.
// TODO(ckennelly): Vet these for sign extension.
int64 has_bits_offset;
int64 oneof_case_offset;
int64 extension_offset;
int64 arena_offset;
// ExplicitlyInitialized<T> -> T requires a reinterpret_cast, which prevents
// the tables from being constructed as a constexpr. We use void to avoid
// the cast.
const void* default_instance_void;
const MessageLite* default_instance() const {
return static_cast<const MessageLite*>(default_instance_void);
}
bool unknown_field_set;
};
static_assert(sizeof(ParseTableField) <= 16, "ParseTableField is too large");
// The tables must be composed of POD components to ensure link-time
// initialization.
static_assert(std::is_pod<ParseTableField>::value, "");
static_assert(std::is_pod<AuxillaryParseTableField::enum_aux>::value, "");
static_assert(std::is_pod<AuxillaryParseTableField::message_aux>::value, "");
static_assert(std::is_pod<AuxillaryParseTableField::string_aux>::value, "");
static_assert(std::is_pod<ParseTable>::value, "");
#ifndef __NVCC__ // This assertion currently fails under NVCC.
static_assert(std::is_pod<AuxillaryParseTableField>::value, "");
#endif
// TODO(ckennelly): Consolidate these implementations into a single one, using
// dynamic dispatch to the appropriate unknown field handler.
bool MergePartialFromCodedStream(MessageLite* msg, const ParseTable& table,
io::CodedInputStream* input);
bool MergePartialFromCodedStreamLite(MessageLite* msg, const ParseTable& table,
io::CodedInputStream* input);
template <typename Entry>
bool ParseMap(io::CodedInputStream* input, void* map_field) {
typedef typename MapEntryToMapField<Entry>::MapFieldType MapFieldType;
typedef google::protobuf::Map<typename Entry::EntryKeyType,
typename Entry::EntryValueType>
MapType;
typedef typename Entry::template Parser<MapFieldType, MapType> ParserType;
ParserType parser(static_cast<MapFieldType*>(map_field));
return ::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(input,
&parser);
}
} // namespace internal
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_GENERATED_MESSAGE_TABLE_DRIVEN_H__

View File

@ -0,0 +1,873 @@
// 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_GENERATED_MESSAGE_TABLE_DRIVEN_LITE_H__
#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_TABLE_DRIVEN_LITE_H__
#include <google/protobuf/generated_message_table_driven.h>
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
#include <google/protobuf/extension_set.h>
#include <google/protobuf/implicit_weak_message.h>
#include <google/protobuf/inlined_string_field.h>
#include <google/protobuf/metadata_lite.h>
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/wire_format_lite.h>
#include <google/protobuf/wire_format_lite_inl.h>
#include <type_traits>
namespace google {
namespace protobuf {
namespace internal {
enum StringType {
StringType_STRING = 0,
StringType_INLINED = 3
};
// Logically a superset of StringType, consisting of all field types that
// require special initialization.
enum ProcessingType {
ProcessingType_STRING = 0,
ProcessingType_CORD = 1,
ProcessingType_STRING_PIECE = 2,
ProcessingType_INLINED = 3,
ProcessingType_MESSAGE = 4,
};
enum Cardinality {
Cardinality_SINGULAR = 0,
Cardinality_REPEATED = 1,
Cardinality_ONEOF = 3
};
template <typename Type>
inline Type* Raw(MessageLite* msg, int64 offset) {
return reinterpret_cast<Type*>(reinterpret_cast<uint8*>(msg) + offset);
}
template <typename Type>
inline const Type* Raw(const MessageLite* msg, int64 offset) {
return reinterpret_cast<const Type*>(reinterpret_cast<const uint8*>(msg) +
offset);
}
template <typename InternalMetadata>
inline Arena* GetArena(MessageLite* msg, int64 arena_offset) {
if (GOOGLE_PREDICT_FALSE(arena_offset == -1)) {
return NULL;
}
return Raw<InternalMetadata>(msg, arena_offset)->arena();
}
inline ExtensionSet* GetExtensionSet(MessageLite* msg, int64 extension_offset) {
if (extension_offset == -1) {
return NULL;
}
return Raw<ExtensionSet>(msg, extension_offset);
}
template <typename Type>
inline Type* AddField(MessageLite* msg, int64 offset) {
static_assert(std::is_pod<Type>::value ||
std::is_same<Type, InlinedStringField>::value,
"Do not assign");
google::protobuf::RepeatedField<Type>* repeated =
Raw<google::protobuf::RepeatedField<Type> >(msg, offset);
return repeated->Add();
}
template <>
inline string* AddField<string>(MessageLite* msg, int64 offset) {
google::protobuf::RepeatedPtrField<string>* repeated =
Raw<google::protobuf::RepeatedPtrField<string> >(msg, offset);
return repeated->Add();
}
template <typename Type>
inline void AddField(MessageLite* msg, int64 offset, Type value) {
static_assert(std::is_pod<Type>::value,
"Do not assign");
*AddField<Type>(msg, offset) = value;
}
inline void SetBit(uint32* has_bits, uint32 has_bit_index) {
GOOGLE_DCHECK(has_bits != nullptr);
uint32 mask = static_cast<uint32>(1u) << (has_bit_index % 32);
has_bits[has_bit_index / 32u] |= mask;
}
template <typename Type>
inline Type* MutableField(MessageLite* msg, uint32* has_bits,
uint32 has_bit_index, int64 offset) {
SetBit(has_bits, has_bit_index);
return Raw<Type>(msg, offset);
}
template <typename Type>
inline void SetField(MessageLite* msg, uint32* has_bits, uint32 has_bit_index,
int64 offset, Type value) {
static_assert(std::is_pod<Type>::value,
"Do not assign");
*MutableField<Type>(msg, has_bits, has_bit_index, offset) = value;
}
template <typename Type>
inline void SetOneofField(MessageLite* msg, uint32* oneof_case,
uint32 oneof_case_index, int64 offset,
int field_number, Type value) {
oneof_case[oneof_case_index] = field_number;
*Raw<Type>(msg, offset) = value;
}
// Clears a oneof field. The field argument should correspond to the particular
// field that is currently set in the oneof.
inline void ClearOneofField(const ParseTableField& field, Arena* arena,
MessageLite* msg) {
switch (field.processing_type & kTypeMask) {
case WireFormatLite::TYPE_MESSAGE:
if (arena == NULL) {
delete *Raw<MessageLite*>(msg, field.offset);
}
break;
case WireFormatLite::TYPE_STRING:
case WireFormatLite::TYPE_BYTES:
Raw<ArenaStringPtr>(msg, field.offset)
->Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), arena);
break;
case TYPE_STRING_INLINED:
case TYPE_BYTES_INLINED:
Raw<InlinedStringField>(msg, field.offset)->DestroyNoArena(NULL);
break;
default:
// No cleanup needed.
break;
}
}
// Clears and reinitializes a oneof field as necessary, in preparation for
// parsing a new value with type field_type and field number field_number.
//
// Note: the oneof_case argument should point directly to the _oneof_case_
// element corresponding to this particular oneof, not to the beginning of the
// _oneof_case_ array.
template <ProcessingType field_type>
inline void ResetOneofField(const ParseTable& table, int field_number,
Arena* arena, MessageLite* msg, uint32* oneof_case,
int64 offset, const void* default_ptr) {
if (*oneof_case == field_number) {
// The oneof is already set to the right type, so there is no need to clear
// it.
return;
}
if (*oneof_case != 0) {
ClearOneofField(table.fields[*oneof_case], arena, msg);
}
*oneof_case = field_number;
switch (field_type) {
case ProcessingType_STRING:
Raw<ArenaStringPtr>(msg, offset)
->UnsafeSetDefault(static_cast<const string*>(default_ptr));
break;
case ProcessingType_INLINED:
new (Raw<InlinedStringField>(msg, offset))
InlinedStringField(*static_cast<const string*>(default_ptr));
break;
case ProcessingType_MESSAGE:
MessageLite** submessage = Raw<MessageLite*>(msg, offset);
const MessageLite* prototype =
table.aux[field_number].messages.default_message();
*submessage = prototype->New(arena);
break;
}
}
template <Cardinality cardinality, bool validate, StringType ctype>
static inline bool HandleString(io::CodedInputStream* input, MessageLite* msg,
Arena* arena, uint32* has_bits,
uint32 has_bit_index, int64 offset,
const void* default_ptr,
const char* field_name) {
#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
const char* sdata;
size_t size;
#endif
switch (ctype) {
case StringType_INLINED: {
InlinedStringField* s;
switch (cardinality) {
case Cardinality_SINGULAR:
// TODO(ckennelly): Is this optimal?
s = MutableField<InlinedStringField>(
msg, has_bits, has_bit_index, offset);
break;
case Cardinality_REPEATED:
s = AddField<InlinedStringField>(msg, offset);
break;
case Cardinality_ONEOF:
s = Raw<InlinedStringField>(msg, offset);
break;
}
GOOGLE_DCHECK(s != nullptr);
::std::string* value = s->MutableNoArena(NULL);
if (GOOGLE_PREDICT_FALSE(!WireFormatLite::ReadString(input, value))) {
return false;
}
#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
sdata = value->data();
size = value->size();
#endif
break;
}
case StringType_STRING: {
string* value;
switch (cardinality) {
case Cardinality_SINGULAR:
// TODO(ckennelly): Is this optimal?
value =
MutableField<ArenaStringPtr>(msg, has_bits, has_bit_index, offset)
->Mutable(static_cast<const string*>(default_ptr), arena);
break;
case Cardinality_REPEATED:
value = AddField<string>(msg, offset);
break;
case Cardinality_ONEOF:
value = Raw<ArenaStringPtr>(msg, offset)
->Mutable(static_cast<const string*>(default_ptr), arena);
break;
}
GOOGLE_DCHECK(value != nullptr);
if (GOOGLE_PREDICT_FALSE(!WireFormatLite::ReadString(input, value))) {
return false;
}
#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
sdata = value->data();
size = value->size();
#endif
break;
}
}
#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
if (validate) {
WireFormatLite::VerifyUtf8String(sdata, size, WireFormatLite::PARSE,
field_name);
}
#endif
return true;
}
template <typename UnknownFieldHandler, typename InternalMetadata,
Cardinality cardinality>
inline bool HandleEnum(const ParseTable& table, io::CodedInputStream* input,
MessageLite* msg, uint32* presence,
uint32 presence_index, int64 offset, uint32 tag,
int field_number) {
int value;
if (GOOGLE_PREDICT_FALSE(
(!WireFormatLite::ReadPrimitive<int, WireFormatLite::TYPE_ENUM>(
input, &value)))) {
return false;
}
AuxillaryParseTableField::EnumValidator validator =
table.aux[field_number].enums.validator;
if (validator(value)) {
switch (cardinality) {
case Cardinality_SINGULAR:
SetField(msg, presence, presence_index, offset, value);
break;
case Cardinality_REPEATED:
AddField(msg, offset, value);
break;
case Cardinality_ONEOF:
ClearOneofField(table.fields[presence[presence_index]],
GetArena<InternalMetadata>(msg, table.arena_offset),
msg);
SetOneofField(msg, presence, presence_index, offset, field_number,
value);
break;
}
} else {
UnknownFieldHandler::Varint(msg, table, tag, value);
}
return true;
}
// RepeatedMessageTypeHandler allows us to operate on RepeatedPtrField fields
// without instantiating the specific template.
class RepeatedMessageTypeHandler {
public:
typedef MessageLite Type;
typedef MessageLite WeakType;
static Arena* GetArena(Type* t) { return t->GetArena(); }
static void* GetMaybeArenaPointer(Type* t) {
return t->GetMaybeArenaPointer();
}
static inline Type* NewFromPrototype(const Type* prototype,
Arena* arena = NULL) {
return prototype->New(arena);
}
static void Delete(Type* t, Arena* arena = NULL) {
if (arena == NULL) {
delete t;
}
}
};
class MergePartialFromCodedStreamHelper {
public:
static MessageLite* Add(RepeatedPtrFieldBase* field,
const MessageLite* prototype) {
return field->Add<RepeatedMessageTypeHandler>(
const_cast<MessageLite*>(prototype));
}
};
template <typename UnknownFieldHandler, typename InternalMetadata>
bool MergePartialFromCodedStreamImpl(MessageLite* msg, const ParseTable& table,
io::CodedInputStream* input) {
// We require that has_bits are present, as to avoid having to check for them
// for every field.
//
// TODO(ckennelly): Make this a compile-time parameter with templates.
GOOGLE_DCHECK_GE(table.has_bits_offset, 0);
uint32* has_bits = Raw<uint32>(msg, table.has_bits_offset);
GOOGLE_DCHECK(has_bits != NULL);
while (true) {
uint32 tag = input->ReadTag();
const WireFormatLite::WireType wire_type =
WireFormatLite::GetTagWireType(tag);
const int field_number = WireFormatLite::GetTagFieldNumber(tag);
if (field_number > table.max_field_number) {
// check for possible extensions
if (UnknownFieldHandler::ParseExtension(msg, table, input, tag)) {
// successfully parsed
continue;
}
if (GOOGLE_PREDICT_FALSE(
!UnknownFieldHandler::Skip(msg, table, input, tag))) {
return false;
}
continue;
}
// We implicitly verify that data points to a valid field as we check the
// wire types. Entries in table.fields[i] that do not correspond to valid
// field numbers have their normal_wiretype and packed_wiretype fields set
// with the kInvalidMask value. As wire_type cannot take on that value, we
// will never match.
const ParseTableField* data = table.fields + field_number;
// TODO(ckennelly): Avoid sign extension
const int64 presence_index = data->presence_index;
const int64 offset = data->offset;
const unsigned char processing_type = data->processing_type;
if (data->normal_wiretype == static_cast<unsigned char>(wire_type)) {
// TODO(ckennelly): Use a computed goto on GCC/LLVM or otherwise eliminate
// the bounds check on processing_type.
switch (processing_type) {
#define HANDLE_TYPE(TYPE, CPPTYPE) \
case (WireFormatLite::TYPE_##TYPE): { \
CPPTYPE value; \
if (GOOGLE_PREDICT_FALSE( \
(!WireFormatLite::ReadPrimitive< \
CPPTYPE, WireFormatLite::TYPE_##TYPE>(input, &value)))) { \
return false; \
} \
SetField(msg, has_bits, presence_index, offset, value); \
break; \
} \
case (WireFormatLite::TYPE_##TYPE) | kRepeatedMask: { \
google::protobuf::RepeatedField<CPPTYPE>* values = \
Raw<google::protobuf::RepeatedField<CPPTYPE> >(msg, offset); \
if (GOOGLE_PREDICT_FALSE((!WireFormatLite::ReadRepeatedPrimitive< \
CPPTYPE, WireFormatLite::TYPE_##TYPE>( \
data->tag_size, tag, input, values)))) { \
return false; \
} \
break; \
} \
case (WireFormatLite::TYPE_##TYPE) | kOneofMask: { \
uint32* oneof_case = Raw<uint32>(msg, table.oneof_case_offset); \
CPPTYPE value; \
if (GOOGLE_PREDICT_FALSE( \
(!WireFormatLite::ReadPrimitive< \
CPPTYPE, WireFormatLite::TYPE_##TYPE>(input, &value)))) { \
return false; \
} \
ClearOneofField(table.fields[oneof_case[presence_index]], \
GetArena<InternalMetadata>(msg, table.arena_offset), msg); \
SetOneofField(msg, oneof_case, presence_index, offset, field_number, \
value); \
break; \
}
HANDLE_TYPE(INT32, int32)
HANDLE_TYPE(INT64, int64)
HANDLE_TYPE(SINT32, int32)
HANDLE_TYPE(SINT64, int64)
HANDLE_TYPE(UINT32, uint32)
HANDLE_TYPE(UINT64, uint64)
HANDLE_TYPE(FIXED32, uint32)
HANDLE_TYPE(FIXED64, uint64)
HANDLE_TYPE(SFIXED32, int32)
HANDLE_TYPE(SFIXED64, int64)
HANDLE_TYPE(FLOAT, float)
HANDLE_TYPE(DOUBLE, double)
HANDLE_TYPE(BOOL, bool)
#undef HANDLE_TYPE
case WireFormatLite::TYPE_BYTES:
#ifndef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
case WireFormatLite::TYPE_STRING:
#endif
{
Arena* const arena =
GetArena<InternalMetadata>(msg, table.arena_offset);
const void* default_ptr = table.aux[field_number].strings.default_ptr;
if (GOOGLE_PREDICT_FALSE((
!HandleString<Cardinality_SINGULAR, false, StringType_STRING>(
input, msg, arena, has_bits, presence_index, offset,
default_ptr, NULL)))) {
return false;
}
break;
}
case TYPE_BYTES_INLINED:
#ifndef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
case TYPE_STRING_INLINED:
#endif
{
Arena* const arena =
GetArena<InternalMetadata>(msg, table.arena_offset);
const void* default_ptr = table.aux[field_number].strings.default_ptr;
if (GOOGLE_PREDICT_FALSE((!HandleString<Cardinality_SINGULAR, false,
StringType_INLINED>(
input, msg, arena, has_bits, presence_index, offset,
default_ptr, NULL)))) {
return false;
}
break;
}
case WireFormatLite::TYPE_BYTES | kOneofMask:
#ifndef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
case WireFormatLite::TYPE_STRING | kOneofMask:
#endif
{
Arena* const arena =
GetArena<InternalMetadata>(msg, table.arena_offset);
uint32* oneof_case = Raw<uint32>(msg, table.oneof_case_offset);
const void* default_ptr = table.aux[field_number].strings.default_ptr;
ResetOneofField<ProcessingType_STRING>(
table, field_number, arena, msg, oneof_case + presence_index,
offset, default_ptr);
if (GOOGLE_PREDICT_FALSE(
(!HandleString<Cardinality_ONEOF, false, StringType_STRING>(
input, msg, arena, has_bits, presence_index, offset,
default_ptr, NULL)))) {
return false;
}
break;
}
case (WireFormatLite::TYPE_BYTES) | kRepeatedMask:
case TYPE_BYTES_INLINED | kRepeatedMask:
#ifndef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
case (WireFormatLite::TYPE_STRING) | kRepeatedMask:
case TYPE_STRING_INLINED | kRepeatedMask:
#endif
{
Arena* const arena =
GetArena<InternalMetadata>(msg, table.arena_offset);
const void* default_ptr =
table.aux[field_number].strings.default_ptr;
if (GOOGLE_PREDICT_FALSE((
!HandleString<Cardinality_REPEATED, false, StringType_STRING>(
input, msg, arena, has_bits, presence_index, offset,
default_ptr, NULL)))) {
return false;
}
break;
}
#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
case (WireFormatLite::TYPE_STRING): {
Arena* const arena =
GetArena<InternalMetadata>(msg, table.arena_offset);
const void* default_ptr = table.aux[field_number].strings.default_ptr;
const char* field_name = table.aux[field_number].strings.field_name;
if (GOOGLE_PREDICT_FALSE(
(!HandleString<Cardinality_SINGULAR, true, StringType_STRING>(
input, msg, arena, has_bits, presence_index, offset,
default_ptr, field_name)))) {
return false;
}
break;
}
case TYPE_STRING_INLINED | kRepeatedMask:
case (WireFormatLite::TYPE_STRING) | kRepeatedMask: {
Arena* const arena =
GetArena<InternalMetadata>(msg, table.arena_offset);
const void* default_ptr = table.aux[field_number].strings.default_ptr;
const char* field_name = table.aux[field_number].strings.field_name;
if (GOOGLE_PREDICT_FALSE(
(!HandleString<Cardinality_REPEATED, true, StringType_STRING>(
input, msg, arena, has_bits, presence_index, offset,
default_ptr, field_name)))) {
return false;
}
break;
}
case (WireFormatLite::TYPE_STRING) | kOneofMask: {
Arena* const arena =
GetArena<InternalMetadata>(msg, table.arena_offset);
uint32* oneof_case = Raw<uint32>(msg, table.oneof_case_offset);
const void* default_ptr = table.aux[field_number].strings.default_ptr;
const char* field_name = table.aux[field_number].strings.field_name;
ResetOneofField<ProcessingType_STRING>(
table, field_number, arena, msg, oneof_case + presence_index,
offset, default_ptr);
if (GOOGLE_PREDICT_FALSE(
(!HandleString<Cardinality_ONEOF, true, StringType_STRING>(
input, msg, arena, has_bits, presence_index, offset,
default_ptr, field_name)))) {
return false;
}
break;
}
#endif
case WireFormatLite::TYPE_ENUM: {
if (GOOGLE_PREDICT_FALSE(
(!HandleEnum<UnknownFieldHandler, InternalMetadata,
Cardinality_SINGULAR>(
table, input, msg, has_bits, presence_index, offset, tag,
field_number)))) {
return false;
}
break;
}
case WireFormatLite::TYPE_ENUM | kRepeatedMask: {
if (GOOGLE_PREDICT_FALSE(
(!HandleEnum<UnknownFieldHandler, InternalMetadata,
Cardinality_REPEATED>(
table, input, msg, has_bits, presence_index, offset, tag,
field_number)))) {
return false;
}
break;
}
case WireFormatLite::TYPE_ENUM | kOneofMask: {
uint32* oneof_case = Raw<uint32>(msg, table.oneof_case_offset);
if (GOOGLE_PREDICT_FALSE(
(!HandleEnum<UnknownFieldHandler, InternalMetadata,
Cardinality_ONEOF>(table, input, msg, oneof_case,
presence_index, offset, tag,
field_number)))) {
return false;
}
break;
}
case WireFormatLite::TYPE_GROUP: {
MessageLite** submsg_holder =
MutableField<MessageLite*>(msg, has_bits, presence_index, offset);
MessageLite* submsg = *submsg_holder;
if (submsg == NULL) {
Arena* const arena =
GetArena<InternalMetadata>(msg, table.arena_offset);
const MessageLite* prototype =
table.aux[field_number].messages.default_message();
submsg = prototype->New(arena);
*submsg_holder = submsg;
}
if (GOOGLE_PREDICT_FALSE(
!WireFormatLite::ReadGroup(field_number, input, submsg))) {
return false;
}
break;
}
case WireFormatLite::TYPE_GROUP | kRepeatedMask: {
RepeatedPtrFieldBase* field = Raw<RepeatedPtrFieldBase>(msg, offset);
const MessageLite* prototype =
table.aux[field_number].messages.default_message();
GOOGLE_DCHECK(prototype != NULL);
MessageLite* submsg =
MergePartialFromCodedStreamHelper::Add(field, prototype);
if (GOOGLE_PREDICT_FALSE(
!WireFormatLite::ReadGroup(field_number, input, submsg))) {
return false;
}
break;
}
case WireFormatLite::TYPE_MESSAGE: {
MessageLite** submsg_holder =
MutableField<MessageLite*>(msg, has_bits, presence_index, offset);
MessageLite* submsg = *submsg_holder;
if (submsg == NULL) {
Arena* const arena =
GetArena<InternalMetadata>(msg, table.arena_offset);
const MessageLite* prototype =
table.aux[field_number].messages.default_message();
if (prototype == NULL) {
prototype =
::google::protobuf::internal::ImplicitWeakMessage::default_instance();
}
submsg = prototype->New(arena);
*submsg_holder = submsg;
}
if (GOOGLE_PREDICT_FALSE(!WireFormatLite::ReadMessage(input, submsg))) {
return false;
}
break;
}
// TODO(ckennelly): Adapt ReadMessageNoVirtualNoRecursionDepth and
// manage input->IncrementRecursionDepth() here.
case WireFormatLite::TYPE_MESSAGE | kRepeatedMask: {
RepeatedPtrFieldBase* field = Raw<RepeatedPtrFieldBase>(msg, offset);
const MessageLite* prototype =
table.aux[field_number].messages.default_message();
if (prototype == NULL) {
prototype =
::google::protobuf::internal::ImplicitWeakMessage::default_instance();
}
MessageLite* submsg =
MergePartialFromCodedStreamHelper::Add(field, prototype);
if (GOOGLE_PREDICT_FALSE(!WireFormatLite::ReadMessage(input, submsg))) {
return false;
}
break;
}
case WireFormatLite::TYPE_MESSAGE | kOneofMask: {
Arena* const arena =
GetArena<InternalMetadata>(msg, table.arena_offset);
uint32* oneof_case = Raw<uint32>(msg, table.oneof_case_offset);
MessageLite** submsg_holder = Raw<MessageLite*>(msg, offset);
ResetOneofField<ProcessingType_MESSAGE>(
table, field_number, arena, msg, oneof_case + presence_index,
offset, NULL);
MessageLite* submsg = *submsg_holder;
if (GOOGLE_PREDICT_FALSE(!WireFormatLite::ReadMessage(input, submsg))) {
return false;
}
break;
}
#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
case TYPE_STRING_INLINED: {
Arena* const arena =
GetArena<InternalMetadata>(msg, table.arena_offset);
const void* default_ptr = table.aux[field_number].strings.default_ptr;
const char* field_name = table.aux[field_number].strings.field_name;
if (GOOGLE_PREDICT_FALSE((
!HandleString<Cardinality_SINGULAR, true, StringType_INLINED>(
input, msg, arena, has_bits, presence_index, offset,
default_ptr, field_name)))) {
return false;
}
break;
}
#endif // GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
case TYPE_MAP: {
if (GOOGLE_PREDICT_FALSE(!(*table.aux[field_number].maps.parse_map)(
input, Raw<void>(msg, offset)))) {
return false;
}
break;
}
case 0: {
// Done.
return true;
}
default:
break;
}
} else if (data->packed_wiretype == static_cast<unsigned char>(wire_type)) {
// Non-packable fields have their packed_wiretype masked with
// kNotPackedMask, which is impossible to match here.
GOOGLE_DCHECK(processing_type & kRepeatedMask);
GOOGLE_DCHECK_NE(processing_type, kRepeatedMask);
GOOGLE_DCHECK_EQ(0, processing_type & kOneofMask);
GOOGLE_DCHECK_NE(TYPE_BYTES_INLINED | kRepeatedMask, processing_type);
GOOGLE_DCHECK_NE(TYPE_STRING_INLINED | kRepeatedMask, processing_type);
// TODO(ckennelly): Use a computed goto on GCC/LLVM.
//
// Mask out kRepeatedMask bit, allowing the jump table to be smaller.
switch (static_cast<WireFormatLite::FieldType>(
processing_type ^ kRepeatedMask)) {
#define HANDLE_PACKED_TYPE(TYPE, CPPTYPE, CPPTYPE_METHOD) \
case WireFormatLite::TYPE_##TYPE: { \
google::protobuf::RepeatedField<CPPTYPE>* values = \
Raw<google::protobuf::RepeatedField<CPPTYPE> >(msg, offset); \
if (GOOGLE_PREDICT_FALSE( \
(!WireFormatLite::ReadPackedPrimitive< \
CPPTYPE, WireFormatLite::TYPE_##TYPE>(input, values)))) { \
return false; \
} \
break; \
}
HANDLE_PACKED_TYPE(INT32, int32, Int32)
HANDLE_PACKED_TYPE(INT64, int64, Int64)
HANDLE_PACKED_TYPE(SINT32, int32, Int32)
HANDLE_PACKED_TYPE(SINT64, int64, Int64)
HANDLE_PACKED_TYPE(UINT32, uint32, UInt32)
HANDLE_PACKED_TYPE(UINT64, uint64, UInt64)
HANDLE_PACKED_TYPE(FIXED32, uint32, UInt32)
HANDLE_PACKED_TYPE(FIXED64, uint64, UInt64)
HANDLE_PACKED_TYPE(SFIXED32, int32, Int32)
HANDLE_PACKED_TYPE(SFIXED64, int64, Int64)
HANDLE_PACKED_TYPE(FLOAT, float, Float)
HANDLE_PACKED_TYPE(DOUBLE, double, Double)
HANDLE_PACKED_TYPE(BOOL, bool, Bool)
#undef HANDLE_PACKED_TYPE
case WireFormatLite::TYPE_ENUM: {
// To avoid unnecessarily calling MutableUnknownFields (which mutates
// InternalMetadataWithArena) when all inputs in the repeated series
// are valid, we implement our own parser rather than call
// WireFormat::ReadPackedEnumPreserveUnknowns.
uint32 length;
if (GOOGLE_PREDICT_FALSE(!input->ReadVarint32(&length))) {
return false;
}
AuxillaryParseTableField::EnumValidator validator =
table.aux[field_number].enums.validator;
google::protobuf::RepeatedField<int>* values =
Raw<google::protobuf::RepeatedField<int> >(msg, offset);
io::CodedInputStream::Limit limit = input->PushLimit(length);
while (input->BytesUntilLimit() > 0) {
int value;
if (GOOGLE_PREDICT_FALSE(
(!google::protobuf::internal::WireFormatLite::ReadPrimitive<
int, WireFormatLite::TYPE_ENUM>(input, &value)))) {
return false;
}
if (validator(value)) {
values->Add(value);
} else {
// TODO(ckennelly): Consider caching here.
UnknownFieldHandler::Varint(msg, table, tag, value);
}
}
input->PopLimit(limit);
break;
}
case WireFormatLite::TYPE_STRING:
case WireFormatLite::TYPE_GROUP:
case WireFormatLite::TYPE_MESSAGE:
case WireFormatLite::TYPE_BYTES:
GOOGLE_DCHECK(false);
return false;
default:
break;
}
} else {
if (wire_type == WireFormatLite::WIRETYPE_END_GROUP) {
// Must be the end of the message.
return true;
}
// check for possible extensions
if (UnknownFieldHandler::ParseExtension(msg, table, input, tag)) {
// successfully parsed
continue;
}
// process unknown field.
if (GOOGLE_PREDICT_FALSE(
!UnknownFieldHandler::Skip(msg, table, input, tag))) {
return false;
}
}
}
}
} // namespace internal
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_GENERATED_MESSAGE_TABLE_DRIVEN_LITE_H__

View File

@ -0,0 +1,391 @@
// 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 contains miscellaneous helper code used by generated code --
// including lite types -- but which should not be used directly by users.
#ifndef GOOGLE_PROTOBUF_GENERATED_MESSAGE_UTIL_H__
#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_UTIL_H__
#include <assert.h>
#include <atomic>
#include <climits>
#include <string>
#include <vector>
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/once.h> // Add direct dep on port for pb.cc
#include <google/protobuf/has_bits.h>
#include <google/protobuf/implicit_weak_message.h>
#include <google/protobuf/map_entry_lite.h>
#include <google/protobuf/message_lite.h>
#include <google/protobuf/wire_format_lite.h>
namespace google {
namespace protobuf {
class Arena;
namespace io { class CodedInputStream; }
namespace internal {
// Annotation for the compiler to emit a deprecation message if a field marked
// with option 'deprecated=true' is used in the code, or for other things in
// generated code which are deprecated.
//
// For internal use in the pb.cc files, deprecation warnings are suppressed
// there.
#undef DEPRECATED_PROTOBUF_FIELD
#define PROTOBUF_DEPRECATED
#define GOOGLE_PROTOBUF_DEPRECATED_ATTR
// Returns the offset of the given field within the given aggregate type.
// This is equivalent to the ANSI C offsetof() macro. However, according
// to the C++ standard, offsetof() only works on POD types, and GCC
// enforces this requirement with a warning. In practice, this rule is
// unnecessarily strict; there is probably no compiler or platform on
// which the offsets of the direct fields of a class are non-constant.
// Fields inherited from superclasses *can* have non-constant offsets,
// but that's not what this macro will be used for.
#if defined(__clang__)
// For Clang we use __builtin_offsetof() and suppress the warning,
// to avoid Control Flow Integrity and UBSan vptr sanitizers from
// crashing while trying to validate the invalid reinterpet_casts.
#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TYPE, FIELD) \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
__builtin_offsetof(TYPE, FIELD) \
_Pragma("clang diagnostic pop")
#else
// Note that we calculate relative to the pointer value 16 here since if we
// just use zero, GCC complains about dereferencing a NULL pointer. We
// choose 16 rather than some other number just in case the compiler would
// be confused by an unaligned pointer.
#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TYPE, FIELD) \
static_cast< ::google::protobuf::uint32>( \
reinterpret_cast<const char*>( \
&reinterpret_cast<const TYPE*>(16)->FIELD) - \
reinterpret_cast<const char*>(16))
#endif
// Constants for special floating point values.
LIBPROTOBUF_EXPORT double Infinity();
LIBPROTOBUF_EXPORT double NaN();
LIBPROTOBUF_EXPORT void InitProtobufDefaults();
// This used by proto1
inline const std::string& GetEmptyString() {
InitProtobufDefaults();
return GetEmptyStringAlreadyInited();
}
// True if IsInitialized() is true for all elements of t. Type is expected
// to be a RepeatedPtrField<some message type>. It's useful to have this
// helper here to keep the protobuf compiler from ever having to emit loops in
// IsInitialized() methods. We want the C++ compiler to inline this or not
// as it sees fit.
template <class Type> bool AllAreInitialized(const Type& t) {
for (int i = t.size(); --i >= 0; ) {
if (!t.Get(i).IsInitialized()) return false;
}
return true;
}
// "Weak" variant of AllAreInitialized, used to implement implicit weak fields.
// This version operates on MessageLite to avoid introducing a dependency on the
// concrete message type.
template <class T>
bool AllAreInitializedWeak(const ::google::protobuf::RepeatedPtrField<T>& t) {
for (int i = t.size(); --i >= 0;) {
if (!reinterpret_cast<const ::google::protobuf::internal::RepeatedPtrFieldBase&>(t)
.Get<::google::protobuf::internal::ImplicitWeakTypeHandler<T> >(i)
.IsInitialized()) {
return false;
}
}
return true;
}
struct LIBPROTOBUF_EXPORT FieldMetadata {
uint32 offset; // offset of this field in the struct
uint32 tag; // field * 8 + wire_type
// byte offset * 8 + bit_offset;
// if the high bit is set then this is the byte offset of the oneof_case
// for this field.
uint32 has_offset;
uint32 type; // the type of this field.
const void* ptr; // auxiliary data
// From the serializer point of view each fundamental type can occur in
// 4 different ways. For simplicity we treat all combinations as a cartesion
// product although not all combinations are allowed.
enum FieldTypeClass {
kPresence,
kNoPresence,
kRepeated,
kPacked,
kOneOf,
kNumTypeClasses // must be last enum
};
// C++ protobuf has 20 fundamental types, were we added Cord and StringPiece
// and also distinquish the same types if they have different wire format.
enum {
kCordType = 19,
kStringPieceType = 20,
kInlinedType = 21,
kNumTypes = 21,
kSpecial = kNumTypes * kNumTypeClasses,
};
static int CalculateType(int fundamental_type, FieldTypeClass type_class);
};
inline bool IsPresent(const void* base, uint32 hasbit) {
const uint32* has_bits_array = static_cast<const uint32*>(base);
return (has_bits_array[hasbit / 32] & (1u << (hasbit & 31))) != 0;
}
inline bool IsOneofPresent(const void* base, uint32 offset, uint32 tag) {
const uint32* oneof =
reinterpret_cast<const uint32*>(static_cast<const uint8*>(base) + offset);
return *oneof == tag >> 3;
}
typedef void (*SpecialSerializer)(const uint8* base, uint32 offset, uint32 tag,
uint32 has_offset,
::google::protobuf::io::CodedOutputStream* output);
LIBPROTOBUF_EXPORT void ExtensionSerializer(const uint8* base, uint32 offset, uint32 tag,
uint32 has_offset,
::google::protobuf::io::CodedOutputStream* output);
LIBPROTOBUF_EXPORT void UnknownFieldSerializerLite(const uint8* base, uint32 offset, uint32 tag,
uint32 has_offset,
::google::protobuf::io::CodedOutputStream* output);
struct SerializationTable {
int num_fields;
const FieldMetadata* field_table;
};
LIBPROTOBUF_EXPORT void SerializeInternal(const uint8* base, const FieldMetadata* table,
int num_fields, ::google::protobuf::io::CodedOutputStream* output);
inline void TableSerialize(const ::google::protobuf::MessageLite& msg,
const SerializationTable* table,
::google::protobuf::io::CodedOutputStream* output) {
const FieldMetadata* field_table = table->field_table;
int num_fields = table->num_fields - 1;
const uint8* base = reinterpret_cast<const uint8*>(&msg);
// TODO(gerbens) This skips the first test if we could use the fast
// array serialization path, we should make this
// int cached_size =
// *reinterpret_cast<const int32*>(base + field_table->offset);
// SerializeWithCachedSize(msg, field_table + 1, num_fields, cached_size, ...)
// But we keep conformance with the old way for now.
SerializeInternal(base, field_table + 1, num_fields, output);
}
uint8* SerializeInternalToArray(const uint8* base, const FieldMetadata* table,
int num_fields, bool is_deterministic,
uint8* buffer);
inline uint8* TableSerializeToArray(const ::google::protobuf::MessageLite& msg,
const SerializationTable* table,
bool is_deterministic, uint8* buffer) {
const uint8* base = reinterpret_cast<const uint8*>(&msg);
const FieldMetadata* field_table = table->field_table + 1;
int num_fields = table->num_fields - 1;
return SerializeInternalToArray(base, field_table, num_fields,
is_deterministic, buffer);
}
template <typename T>
struct CompareHelper {
bool operator()(const T& a, const T& b) { return a < b; }
};
template <>
struct CompareHelper<ArenaStringPtr> {
bool operator()(const ArenaStringPtr& a, const ArenaStringPtr& b) {
return a.Get() < b.Get();
}
};
struct CompareMapKey {
template <typename T>
bool operator()(const MapEntryHelper<T>& a, const MapEntryHelper<T>& b) {
return Compare(a.key_, b.key_);
}
template <typename T>
bool Compare(const T& a, const T& b) {
return CompareHelper<T>()(a, b);
}
};
template <typename MapFieldType, const SerializationTable* table>
void MapFieldSerializer(const uint8* base, uint32 offset, uint32 tag,
uint32 has_offset,
::google::protobuf::io::CodedOutputStream* output) {
typedef MapEntryHelper<typename MapFieldType::EntryTypeTrait> Entry;
typedef typename MapFieldType::MapType::const_iterator Iter;
const MapFieldType& map_field =
*reinterpret_cast<const MapFieldType*>(base + offset);
const SerializationTable* t =
table +
has_offset; // has_offset is overloaded for maps to mean table offset
if (!output->IsSerializationDeterministic()) {
for (Iter it = map_field.GetMap().begin(); it != map_field.GetMap().end();
++it) {
Entry map_entry(*it);
output->WriteVarint32(tag);
output->WriteVarint32(map_entry._cached_size_);
SerializeInternal(reinterpret_cast<const uint8*>(&map_entry),
t->field_table, t->num_fields, output);
}
} else {
std::vector<Entry> v;
for (Iter it = map_field.GetMap().begin(); it != map_field.GetMap().end();
++it) {
v.push_back(Entry(*it));
}
std::sort(v.begin(), v.end(), CompareMapKey());
for (int i = 0; i < v.size(); i++) {
output->WriteVarint32(tag);
output->WriteVarint32(v[i]._cached_size_);
SerializeInternal(reinterpret_cast<const uint8*>(&v[i]), t->field_table,
t->num_fields, output);
}
}
}
LIBPROTOBUF_EXPORT MessageLite* DuplicateIfNonNullInternal(MessageLite* message);
LIBPROTOBUF_EXPORT MessageLite* GetOwnedMessageInternal(Arena* message_arena,
MessageLite* submessage,
Arena* submessage_arena);
template <typename T>
T* DuplicateIfNonNull(T* message) {
// The casts must be reinterpret_cast<> because T might be a forward-declared
// type that the compiler doesn't know is related to MessageLite.
return reinterpret_cast<T*>(
DuplicateIfNonNullInternal(reinterpret_cast<MessageLite*>(message)));
}
template <typename T>
T* GetOwnedMessage(Arena* message_arena, T* submessage,
Arena* submessage_arena) {
// The casts must be reinterpret_cast<> because T might be a forward-declared
// type that the compiler doesn't know is related to MessageLite.
return reinterpret_cast<T*>(GetOwnedMessageInternal(
message_arena, reinterpret_cast<MessageLite*>(submessage),
submessage_arena));
}
// Hide atomic from the public header and allow easy change to regular int
// on platforms where the atomic might have a perf impact.
class LIBPROTOBUF_EXPORT CachedSize {
public:
int Get() const { return size_.load(std::memory_order_relaxed); }
void Set(int size) { size_.store(size, std::memory_order_relaxed); }
private:
std::atomic<int> size_{0};
};
// SCCInfo represents information of a strongly connected component of
// mutual dependent messages.
struct LIBPROTOBUF_EXPORT SCCInfoBase {
// We use 0 for the Initialized state, because test eax,eax, jnz is smaller
// and is subject to macro fusion.
enum {
kInitialized = 0, // final state
kRunning = 1,
kUninitialized = -1, // initial state
};
#ifndef _MSC_VER
std::atomic<int> visit_status;
#else
// MSVC doesnt make std::atomic constant initialized. This union trick
// makes it so.
union {
int visit_status_to_make_linker_init;
std::atomic<int> visit_status;
};
#endif
int num_deps;
void (*init_func)();
// This is followed by an array of num_deps
// const SCCInfoBase* deps[];
};
template <int N>
struct SCCInfo {
SCCInfoBase base;
// Semantically this is const SCCInfo<T>* which is is a templated type.
// The obvious inheriting from SCCInfoBase mucks with struct initialization.
// Attempts showed the compiler was generating dynamic initialization code.
// Zero length arrays produce warnings with MSVC.
SCCInfoBase* deps[N ? N : 1];
};
LIBPROTOBUF_EXPORT void InitSCCImpl(SCCInfoBase* scc);
inline void InitSCC(SCCInfoBase* scc) {
auto status = scc->visit_status.load(std::memory_order_acquire);
if (GOOGLE_PREDICT_FALSE(status != SCCInfoBase::kInitialized)) InitSCCImpl(scc);
}
LIBPROTOBUF_EXPORT void DestroyMessage(const void* message);
LIBPROTOBUF_EXPORT void DestroyString(const void* s);
// Destroy (not delete) the message
inline void OnShutdownDestroyMessage(const void* ptr) {
OnShutdownRun(DestroyMessage, ptr);
}
// Destroy the string (call string destructor)
inline void OnShutdownDestroyString(const std::string* ptr) {
OnShutdownRun(DestroyString, ptr);
}
} // namespace internal
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_GENERATED_MESSAGE_UTIL_H__

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_HAS_BITS_H__
#define GOOGLE_PROTOBUF_HAS_BITS_H__
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/port.h>
namespace google {
namespace protobuf {
namespace internal {
template<size_t doublewords>
class HasBits {
public:
HasBits() GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE { Clear(); }
void Clear() GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE {
memset(has_bits_, 0, sizeof(has_bits_));
}
::google::protobuf::uint32& operator[](int index) GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE {
return has_bits_[index];
}
const ::google::protobuf::uint32& operator[](int index) const
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE {
return has_bits_[index];
}
bool operator==(const HasBits<doublewords>& rhs) const {
return memcmp(has_bits_, rhs.has_bits_, sizeof(has_bits_)) == 0;
}
bool operator!=(const HasBits<doublewords>& rhs) const {
return !(*this == rhs);
}
bool empty() const;
private:
::google::protobuf::uint32 has_bits_[doublewords];
};
template <>
inline bool HasBits<1>::empty() const {
return !has_bits_[0];
}
template <>
inline bool HasBits<2>::empty() const {
return !(has_bits_[0] | has_bits_[1]);
}
template <>
inline bool HasBits<3>::empty() const {
return !(has_bits_[0] | has_bits_[1] | has_bits_[2]);
}
template <>
inline bool HasBits<4>::empty() const {
return !(has_bits_[0] | has_bits_[1] | has_bits_[2] | has_bits_[3]);
}
template <size_t doublewords>
inline bool HasBits<doublewords>::empty() const {
for (size_t i = 0; i < doublewords; ++i) {
if (has_bits_[i]) return false;
}
return true;
}
} // namespace internal
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_HAS_BITS_H__

View File

@ -0,0 +1,135 @@
// 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_IMPLICIT_WEAK_MESSAGE_H__
#define GOOGLE_PROTOBUF_IMPLICIT_WEAK_MESSAGE_H__
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/arena.h>
#include <google/protobuf/message_lite.h>
// This file is logically internal-only and should only be used by protobuf
// generated code.
namespace google {
namespace protobuf {
namespace internal {
// An implementation of MessageLite that treats all data as unknown. This type
// acts as a placeholder for an implicit weak field in the case where the true
// message type does not get linked into the binary.
class LIBPROTOBUF_EXPORT ImplicitWeakMessage : public MessageLite {
public:
ImplicitWeakMessage() : arena_(NULL) {}
explicit ImplicitWeakMessage(Arena* arena) : arena_(arena) {}
static const ImplicitWeakMessage* default_instance();
string GetTypeName() const { return ""; }
MessageLite* New() const { return new ImplicitWeakMessage; }
MessageLite* New(Arena* arena) const {
return Arena::CreateMessage<ImplicitWeakMessage>(arena);
}
Arena* GetArena() const { return arena_; }
void Clear() { data_.clear(); }
bool IsInitialized() const { return true; }
void CheckTypeAndMergeFrom(const MessageLite& other) {
data_.append(static_cast<const ImplicitWeakMessage&>(other).data_);
}
bool MergePartialFromCodedStream(io::CodedInputStream* input);
size_t ByteSizeLong() const { return data_.size(); }
void SerializeWithCachedSizes(io::CodedOutputStream* output) const {
output->WriteString(data_);
}
int GetCachedSize() const { return static_cast<int>(data_.size()); }
typedef void InternalArenaConstructable_;
private:
Arena* const arena_;
string data_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImplicitWeakMessage);
};
// A type handler for use with implicit weak repeated message fields.
template <typename ImplicitWeakType>
class ImplicitWeakTypeHandler {
public:
typedef ImplicitWeakType Type;
typedef ::google::protobuf::MessageLite WeakType;
static const bool Moveable = false;
// With implicit weak fields, we need separate NewFromPrototype and
// NewFromPrototypeWeak functions. The former is used when we want to create a
// strong dependency on the message type, and it just delegates to the
// GenericTypeHandler. The latter avoids creating a strong dependency, by
// simply calling MessageLite::New.
static inline ::google::protobuf::MessageLite* NewFromPrototype(
const ::google::protobuf::MessageLite* prototype, ::google::protobuf::Arena* arena = NULL) {
return prototype->New(arena);
}
static inline void Delete(::google::protobuf::MessageLite* value, Arena* arena) {
if (arena == NULL) {
delete value;
}
}
static inline ::google::protobuf::Arena* GetArena(::google::protobuf::MessageLite* value) {
return value->GetArena();
}
static inline void* GetMaybeArenaPointer(::google::protobuf::MessageLite* value) {
return value->GetArena();
}
static inline void Clear(::google::protobuf::MessageLite* value) {
value->Clear();
}
static void Merge(const ::google::protobuf::MessageLite& from,
::google::protobuf::MessageLite* to) {
to->CheckTypeAndMergeFrom(from);
}
static inline size_t SpaceUsedLong(const Type& value) {
return value.SpaceUsedLong();
}
};
} // namespace internal
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_IMPLICIT_WEAK_MESSAGE_H__

View File

@ -0,0 +1,271 @@
// 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_INLINED_STRING_FIELD_H__
#define GOOGLE_PROTOBUF_INLINED_STRING_FIELD_H__
#include <string>
#include <google/protobuf/stubs/port.h>
#include <google/protobuf/stubs/stringpiece.h>
namespace google {
namespace protobuf {
class Arena;
namespace internal {
// InlinedStringField wraps a ::std::string instance and exposes an API similar to
// ArenaStringPtr's wrapping of a ::std::string* instance. As ::std::string is never
// allocated on the Arena, we expose only the *NoArena methods of
// ArenaStringPtr.
//
// default_value parameters are taken for consistency with ArenaStringPtr, but
// are not used for most methods. With inlining, these should be removed from
// the generated binary.
class LIBPROTOBUF_EXPORT InlinedStringField {
public:
InlinedStringField()
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE;
explicit InlinedStringField(const ::std::string& default_value);
void AssignWithDefault(const ::std::string* default_value,
const InlinedStringField& from)
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE;
void ClearToEmpty(const ::std::string* default_value, Arena* arena)
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE {
ClearToEmptyNoArena(default_value);
}
void ClearNonDefaultToEmpty() GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE {
ClearNonDefaultToEmptyNoArena();
}
void ClearToEmptyNoArena(const ::std::string* default_value)
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE {
ClearNonDefaultToEmptyNoArena();
}
void ClearNonDefaultToEmptyNoArena()
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE;
void ClearToDefault(const ::std::string* default_value, Arena* arena)
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE {
ClearToDefaultNoArena(default_value);
}
void ClearToDefaultNoArena(const ::std::string* default_value)
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE;
void Destroy(const ::std::string* default_value, Arena* arena)
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE {
DestroyNoArena(default_value);
}
void DestroyNoArena(const ::std::string* default_value)
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE;
const ::std::string& Get() const GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE {
return GetNoArena();
}
const ::std::string& GetNoArena() const GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE;
::std::string* Mutable(const ::std::string* default_value, Arena* arena)
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE {
return MutableNoArena(default_value);
}
::std::string* MutableNoArena(const ::std::string* default_value)
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE;
::std::string* Release(const ::std::string* default_value, Arena* arena) {
return ReleaseNoArena(default_value);
}
::std::string* ReleaseNonDefault(const ::std::string* default_value, Arena* arena) {
return ReleaseNonDefaultNoArena(default_value);
}
::std::string* ReleaseNoArena(const ::std::string* default_value) {
return ReleaseNonDefaultNoArena(default_value);
}
::std::string* ReleaseNonDefaultNoArena(const ::std::string* default_value);
void Set(const ::std::string* default_value,
StringPiece value,
Arena* arena) GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE {
SetNoArena(default_value, value);
}
void SetLite(const ::std::string* default_value,
StringPiece value,
Arena* arena) GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE {
SetNoArena(default_value, value);
}
void SetNoArena(const ::std::string* default_value,
StringPiece value) GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE;
void Set(const ::std::string* default_value,
const ::std::string& value,
Arena* arena) GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE {
SetNoArena(default_value, value);
}
void SetLite(const ::std::string* default_value,
const ::std::string& value,
Arena* arena) GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE {
SetNoArena(default_value, value);
}
void SetNoArena(const ::std::string* default_value,
const ::std::string& value)
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE;
#if LANG_CXX11
void SetNoArena(const ::std::string* default_value,
::std::string&& value)
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE;
#endif
void SetAllocated(const ::std::string* default_value,
::std::string* value,
Arena* arena) {
SetAllocatedNoArena(default_value, value);
}
void SetAllocatedNoArena(const ::std::string* default_value,
::std::string* value);
void Swap(InlinedStringField* from)
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE;
::std::string* UnsafeMutablePointer();
void UnsafeSetDefault(const ::std::string* default_value);
::std::string* UnsafeArenaRelease(const ::std::string* default_value, Arena* arena);
void UnsafeArenaSetAllocated(
const ::std::string* default_value, ::std::string* value, Arena* arena);
bool IsDefault(const ::std::string* default_value) {
return false;
}
private:
::std::string value_;
};
inline InlinedStringField::InlinedStringField() {}
inline InlinedStringField::InlinedStringField(const ::std::string& default_value) :
value_(default_value) {}
inline void InlinedStringField::AssignWithDefault(
const ::std::string* default_value, const InlinedStringField& from) {
value_ = from.value_;
}
inline const ::std::string& InlinedStringField::GetNoArena() const {
return value_;
}
inline ::std::string* InlinedStringField::MutableNoArena(const ::std::string*) {
return &value_;
}
inline void InlinedStringField::SetAllocatedNoArena(
const ::std::string* default_value, ::std::string* value) {
if (value == NULL) {
value_.assign(*default_value);
} else {
#if LANG_CXX11
value_.assign(std::move(*value));
#else
value_.swap(*value);
#endif
delete value;
}
}
inline void InlinedStringField::DestroyNoArena(const ::std::string*) {
// This is invoked from the generated message's ArenaDtor, which is used to
// clean up objects not allocated on the Arena.
this->~InlinedStringField();
}
inline void InlinedStringField::ClearNonDefaultToEmptyNoArena() {
value_.clear();
}
inline void InlinedStringField::ClearToDefaultNoArena(
const ::std::string* default_value) {
value_.assign(*default_value);
}
inline ::std::string* InlinedStringField::ReleaseNonDefaultNoArena(
const ::std::string* default_value) {
::std::string* released = new ::std::string(*default_value);
value_.swap(*released);
return released;
}
inline void InlinedStringField::SetNoArena(
const ::std::string* default_value, StringPiece value) {
value_.assign(value.data(), value.length());
}
inline void InlinedStringField::SetNoArena(
const ::std::string* default_value, const ::std::string& value) {
value_.assign(value);
}
#if LANG_CXX11
inline void InlinedStringField::SetNoArena(
const ::std::string* default_value, ::std::string&& value) {
value_.assign(std::move(value));
}
#endif
inline void InlinedStringField::Swap(InlinedStringField* from) {
value_.swap(from->value_);
}
inline ::std::string* InlinedStringField::UnsafeMutablePointer() {
return &value_;
}
inline void InlinedStringField::UnsafeSetDefault(
const ::std::string* default_value) {
value_.assign(*default_value);
}
inline ::std::string* InlinedStringField::UnsafeArenaRelease(
const ::std::string* default_value, Arena* arena) {
return ReleaseNoArena(default_value);
}
inline void InlinedStringField::UnsafeArenaSetAllocated(
const ::std::string* default_value, ::std::string* value, Arena* arena) {
if (value == NULL) {
value_.assign(*default_value);
} else {
value_.assign(*value);
}
}
} // namespace internal
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_INLINED_STRING_FIELD_H__

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,90 @@
// 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: jasonh@google.com (Jason Hsueh)
//
// Implements methods of coded_stream.h that need to be inlined for performance
// reasons, but should not be defined in a public header.
#ifndef GOOGLE_PROTOBUF_IO_CODED_STREAM_INL_H__
#define GOOGLE_PROTOBUF_IO_CODED_STREAM_INL_H__
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
#include <string>
#include <google/protobuf/stubs/stl_util.h>
namespace google {
namespace protobuf {
namespace io {
inline bool CodedInputStream::InternalReadStringInline(string* buffer,
int size) {
if (size < 0) return false; // security: size is often user-supplied
if (BufferSize() >= size) {
STLStringResizeUninitialized(buffer, size);
std::pair<char*, bool> z = as_string_data(buffer);
if (z.second) {
// Oddly enough, memcpy() requires its first two args to be non-NULL even
// if we copy 0 bytes. So, we have ensured that z.first is non-NULL here.
GOOGLE_DCHECK(z.first != NULL);
memcpy(z.first, buffer_, size);
Advance(size);
}
return true;
}
return ReadStringFallback(buffer, size);
}
inline bool CodedInputStream::InternalReadRawInline(void* buffer, int size) {
int current_buffer_size;
while ((current_buffer_size = BufferSize()) < size) {
// Reading past end of buffer. Copy what we have, then refresh.
memcpy(buffer, buffer_, current_buffer_size);
buffer = reinterpret_cast<uint8*>(buffer) + current_buffer_size;
size -= current_buffer_size;
Advance(current_buffer_size);
if (!Refresh()) return false;
}
memcpy(buffer, buffer_, size);
Advance(size);
return true;
}
} // namespace io
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_IO_CODED_STREAM_INL_H__

View File

@ -0,0 +1,248 @@
// 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 contains the ZeroCopyInputStream and ZeroCopyOutputStream
// interfaces, which represent abstract I/O streams to and from which
// protocol buffers can be read and written. For a few simple
// implementations of these interfaces, see zero_copy_stream_impl.h.
//
// These interfaces are different from classic I/O streams in that they
// try to minimize the amount of data copying that needs to be done.
// To accomplish this, responsibility for allocating buffers is moved to
// the stream object, rather than being the responsibility of the caller.
// So, the stream can return a buffer which actually points directly into
// the final data structure where the bytes are to be stored, and the caller
// can interact directly with that buffer, eliminating an intermediate copy
// operation.
//
// As an example, consider the common case in which you are reading bytes
// from an array that is already in memory (or perhaps an mmap()ed file).
// With classic I/O streams, you would do something like:
// char buffer[BUFFER_SIZE];
// input->Read(buffer, BUFFER_SIZE);
// DoSomething(buffer, BUFFER_SIZE);
// Then, the stream basically just calls memcpy() to copy the data from
// the array into your buffer. With a ZeroCopyInputStream, you would do
// this instead:
// const void* buffer;
// int size;
// input->Next(&buffer, &size);
// DoSomething(buffer, size);
// Here, no copy is performed. The input stream returns a pointer directly
// into the backing array, and the caller ends up reading directly from it.
//
// If you want to be able to read the old-fashion way, you can create
// a CodedInputStream or CodedOutputStream wrapping these objects and use
// their ReadRaw()/WriteRaw() methods. These will, of course, add a copy
// step, but Coded*Stream will handle buffering so at least it will be
// reasonably efficient.
//
// ZeroCopyInputStream example:
// // Read in a file and print its contents to stdout.
// int fd = open("myfile", O_RDONLY);
// ZeroCopyInputStream* input = new FileInputStream(fd);
//
// const void* buffer;
// int size;
// while (input->Next(&buffer, &size)) {
// cout.write(buffer, size);
// }
//
// delete input;
// close(fd);
//
// ZeroCopyOutputStream example:
// // Copy the contents of "infile" to "outfile", using plain read() for
// // "infile" but a ZeroCopyOutputStream for "outfile".
// int infd = open("infile", O_RDONLY);
// int outfd = open("outfile", O_WRONLY);
// ZeroCopyOutputStream* output = new FileOutputStream(outfd);
//
// void* buffer;
// int size;
// while (output->Next(&buffer, &size)) {
// int bytes = read(infd, buffer, size);
// if (bytes < size) {
// // Reached EOF.
// output->BackUp(size - bytes);
// break;
// }
// }
//
// delete output;
// close(infd);
// close(outfd);
#ifndef GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_H__
#define GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_H__
#include <string>
#include <google/protobuf/stubs/common.h>
namespace google {
namespace protobuf {
namespace io {
// Defined in this file.
class ZeroCopyInputStream;
class ZeroCopyOutputStream;
// Abstract interface similar to an input stream but designed to minimize
// copying.
class LIBPROTOBUF_EXPORT ZeroCopyInputStream {
public:
ZeroCopyInputStream() {}
virtual ~ZeroCopyInputStream() {}
// Obtains a chunk of data from the stream.
//
// Preconditions:
// * "size" and "data" are not NULL.
//
// Postconditions:
// * If the returned value is false, there is no more data to return or
// an error occurred. All errors are permanent.
// * Otherwise, "size" points to the actual number of bytes read and "data"
// points to a pointer to a buffer containing these bytes.
// * Ownership of this buffer remains with the stream, and the buffer
// remains valid only until some other method of the stream is called
// or the stream is destroyed.
// * It is legal for the returned buffer to have zero size, as long
// as repeatedly calling Next() eventually yields a buffer with non-zero
// size.
virtual bool Next(const void** data, int* size) = 0;
// Backs up a number of bytes, so that the next call to Next() returns
// data again that was already returned by the last call to Next(). This
// is useful when writing procedures that are only supposed to read up
// to a certain point in the input, then return. If Next() returns a
// buffer that goes beyond what you wanted to read, you can use BackUp()
// to return to the point where you intended to finish.
//
// Preconditions:
// * The last method called must have been Next().
// * count must be less than or equal to the size of the last buffer
// returned by Next().
//
// Postconditions:
// * The last "count" bytes of the last buffer returned by Next() will be
// pushed back into the stream. Subsequent calls to Next() will return
// the same data again before producing new data.
virtual void BackUp(int count) = 0;
// Skips a number of bytes. Returns false if the end of the stream is
// reached or some input error occurred. In the end-of-stream case, the
// stream is advanced to the end of the stream (so ByteCount() will return
// the total size of the stream).
virtual bool Skip(int count) = 0;
// Returns the total number of bytes read since this object was created.
virtual int64 ByteCount() const = 0;
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ZeroCopyInputStream);
};
// Abstract interface similar to an output stream but designed to minimize
// copying.
class LIBPROTOBUF_EXPORT ZeroCopyOutputStream {
public:
ZeroCopyOutputStream() {}
virtual ~ZeroCopyOutputStream() {}
// Obtains a buffer into which data can be written. Any data written
// into this buffer will eventually (maybe instantly, maybe later on)
// be written to the output.
//
// Preconditions:
// * "size" and "data" are not NULL.
//
// Postconditions:
// * If the returned value is false, an error occurred. All errors are
// permanent.
// * Otherwise, "size" points to the actual number of bytes in the buffer
// and "data" points to the buffer.
// * Ownership of this buffer remains with the stream, and the buffer
// remains valid only until some other method of the stream is called
// or the stream is destroyed.
// * Any data which the caller stores in this buffer will eventually be
// written to the output (unless BackUp() is called).
// * It is legal for the returned buffer to have zero size, as long
// as repeatedly calling Next() eventually yields a buffer with non-zero
// size.
virtual bool Next(void** data, int* size) = 0;
// Backs up a number of bytes, so that the end of the last buffer returned
// by Next() is not actually written. This is needed when you finish
// writing all the data you want to write, but the last buffer was bigger
// than you needed. You don't want to write a bunch of garbage after the
// end of your data, so you use BackUp() to back up.
//
// Preconditions:
// * The last method called must have been Next().
// * count must be less than or equal to the size of the last buffer
// returned by Next().
// * The caller must not have written anything to the last "count" bytes
// of that buffer.
//
// Postconditions:
// * The last "count" bytes of the last buffer returned by Next() will be
// ignored.
virtual void BackUp(int count) = 0;
// Returns the total number of bytes written since this object was created.
virtual int64 ByteCount() const = 0;
// Write a given chunk of data to the output. Some output streams may
// implement this in a way that avoids copying. Check AllowsAliasing() before
// calling WriteAliasedRaw(). It will GOOGLE_CHECK fail if WriteAliasedRaw() is
// called on a stream that does not allow aliasing.
//
// NOTE: It is caller's responsibility to ensure that the chunk of memory
// remains live until all of the data has been consumed from the stream.
virtual bool WriteAliasedRaw(const void* data, int size);
virtual bool AllowsAliasing() const { return false; }
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ZeroCopyOutputStream);
};
} // namespace io
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_H__

View File

@ -0,0 +1,383 @@
// 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 contains common implementations of the interfaces defined in
// zero_copy_stream.h which are included in the "lite" protobuf library.
// These implementations cover I/O on raw arrays and strings, as well as
// adaptors which make it easy to implement streams based on traditional
// streams. Of course, many users will probably want to write their own
// implementations of these interfaces specific to the particular I/O
// abstractions they prefer to use, but these should cover the most common
// cases.
#ifndef GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_LITE_H__
#define GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_LITE_H__
#include <memory>
#include <string>
#include <iosfwd>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/stubs/callback.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/stl_util.h>
namespace google {
namespace protobuf {
namespace io {
// ===================================================================
// A ZeroCopyInputStream backed by an in-memory array of bytes.
class LIBPROTOBUF_EXPORT ArrayInputStream : public ZeroCopyInputStream {
public:
// Create an InputStream that returns the bytes pointed to by "data".
// "data" remains the property of the caller but must remain valid until
// the stream is destroyed. If a block_size is given, calls to Next()
// will return data blocks no larger than the given size. Otherwise, the
// first call to Next() returns the entire array. block_size is mainly
// useful for testing; in production you would probably never want to set
// it.
ArrayInputStream(const void* data, int size, int block_size = -1);
// implements ZeroCopyInputStream ----------------------------------
bool Next(const void** data, int* size);
void BackUp(int count);
bool Skip(int count);
int64 ByteCount() const;
private:
const uint8* const data_; // The byte array.
const int size_; // Total size of the array.
const int block_size_; // How many bytes to return at a time.
int position_;
int last_returned_size_; // How many bytes we returned last time Next()
// was called (used for error checking only).
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ArrayInputStream);
};
// ===================================================================
// A ZeroCopyOutputStream backed by an in-memory array of bytes.
class LIBPROTOBUF_EXPORT ArrayOutputStream : public ZeroCopyOutputStream {
public:
// Create an OutputStream that writes to the bytes pointed to by "data".
// "data" remains the property of the caller but must remain valid until
// the stream is destroyed. If a block_size is given, calls to Next()
// will return data blocks no larger than the given size. Otherwise, the
// first call to Next() returns the entire array. block_size is mainly
// useful for testing; in production you would probably never want to set
// it.
ArrayOutputStream(void* data, int size, int block_size = -1);
// implements ZeroCopyOutputStream ---------------------------------
bool Next(void** data, int* size);
void BackUp(int count);
int64 ByteCount() const;
private:
uint8* const data_; // The byte array.
const int size_; // Total size of the array.
const int block_size_; // How many bytes to return at a time.
int position_;
int last_returned_size_; // How many bytes we returned last time Next()
// was called (used for error checking only).
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ArrayOutputStream);
};
// ===================================================================
// A ZeroCopyOutputStream which appends bytes to a string.
class LIBPROTOBUF_EXPORT StringOutputStream : public ZeroCopyOutputStream {
public:
// Create a StringOutputStream which appends bytes to the given string.
// The string remains property of the caller, but it is mutated in arbitrary
// ways and MUST NOT be accessed in any way until you're done with the
// stream. Either be sure there's no further usage, or (safest) destroy the
// stream before using the contents.
//
// Hint: If you call target->reserve(n) before creating the stream,
// the first call to Next() will return at least n bytes of buffer
// space.
explicit StringOutputStream(string* target);
// implements ZeroCopyOutputStream ---------------------------------
bool Next(void** data, int* size);
void BackUp(int count);
int64 ByteCount() const;
protected:
void SetString(string* target);
private:
static const int kMinimumSize = 16;
string* target_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringOutputStream);
};
// Note: There is no StringInputStream. Instead, just create an
// ArrayInputStream as follows:
// ArrayInputStream input(str.data(), str.size());
// ===================================================================
// A generic traditional input stream interface.
//
// Lots of traditional input streams (e.g. file descriptors, C stdio
// streams, and C++ iostreams) expose an interface where every read
// involves copying bytes into a buffer. If you want to take such an
// interface and make a ZeroCopyInputStream based on it, simply implement
// CopyingInputStream and then use CopyingInputStreamAdaptor.
//
// CopyingInputStream implementations should avoid buffering if possible.
// CopyingInputStreamAdaptor does its own buffering and will read data
// in large blocks.
class LIBPROTOBUF_EXPORT CopyingInputStream {
public:
virtual ~CopyingInputStream() {}
// Reads up to "size" bytes into the given buffer. Returns the number of
// bytes read. Read() waits until at least one byte is available, or
// returns zero if no bytes will ever become available (EOF), or -1 if a
// permanent read error occurred.
virtual int Read(void* buffer, int size) = 0;
// Skips the next "count" bytes of input. Returns the number of bytes
// actually skipped. This will always be exactly equal to "count" unless
// EOF was reached or a permanent read error occurred.
//
// The default implementation just repeatedly calls Read() into a scratch
// buffer.
virtual int Skip(int count);
};
// A ZeroCopyInputStream which reads from a CopyingInputStream. This is
// useful for implementing ZeroCopyInputStreams that read from traditional
// streams. Note that this class is not really zero-copy.
//
// If you want to read from file descriptors or C++ istreams, this is
// already implemented for you: use FileInputStream or IstreamInputStream
// respectively.
class LIBPROTOBUF_EXPORT CopyingInputStreamAdaptor : public ZeroCopyInputStream {
public:
// Creates a stream that reads from the given CopyingInputStream.
// If a block_size is given, it specifies the number of bytes that
// should be read and returned with each call to Next(). Otherwise,
// a reasonable default is used. The caller retains ownership of
// copying_stream unless SetOwnsCopyingStream(true) is called.
explicit CopyingInputStreamAdaptor(CopyingInputStream* copying_stream,
int block_size = -1);
~CopyingInputStreamAdaptor();
// Call SetOwnsCopyingStream(true) to tell the CopyingInputStreamAdaptor to
// delete the underlying CopyingInputStream when it is destroyed.
void SetOwnsCopyingStream(bool value) { owns_copying_stream_ = value; }
// implements ZeroCopyInputStream ----------------------------------
bool Next(const void** data, int* size);
void BackUp(int count);
bool Skip(int count);
int64 ByteCount() const;
private:
// Insures that buffer_ is not NULL.
void AllocateBufferIfNeeded();
// Frees the buffer and resets buffer_used_.
void FreeBuffer();
// The underlying copying stream.
CopyingInputStream* copying_stream_;
bool owns_copying_stream_;
// True if we have seen a permenant error from the underlying stream.
bool failed_;
// The current position of copying_stream_, relative to the point where
// we started reading.
int64 position_;
// Data is read into this buffer. It may be NULL if no buffer is currently
// in use. Otherwise, it points to an array of size buffer_size_.
std::unique_ptr<uint8[]> buffer_;
const int buffer_size_;
// Number of valid bytes currently in the buffer (i.e. the size last
// returned by Next()). 0 <= buffer_used_ <= buffer_size_.
int buffer_used_;
// Number of bytes in the buffer which were backed up over by a call to
// BackUp(). These need to be returned again.
// 0 <= backup_bytes_ <= buffer_used_
int backup_bytes_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingInputStreamAdaptor);
};
// ===================================================================
// A generic traditional output stream interface.
//
// Lots of traditional output streams (e.g. file descriptors, C stdio
// streams, and C++ iostreams) expose an interface where every write
// involves copying bytes from a buffer. If you want to take such an
// interface and make a ZeroCopyOutputStream based on it, simply implement
// CopyingOutputStream and then use CopyingOutputStreamAdaptor.
//
// CopyingOutputStream implementations should avoid buffering if possible.
// CopyingOutputStreamAdaptor does its own buffering and will write data
// in large blocks.
class LIBPROTOBUF_EXPORT CopyingOutputStream {
public:
virtual ~CopyingOutputStream() {}
// Writes "size" bytes from the given buffer to the output. Returns true
// if successful, false on a write error.
virtual bool Write(const void* buffer, int size) = 0;
};
// A ZeroCopyOutputStream which writes to a CopyingOutputStream. This is
// useful for implementing ZeroCopyOutputStreams that write to traditional
// streams. Note that this class is not really zero-copy.
//
// If you want to write to file descriptors or C++ ostreams, this is
// already implemented for you: use FileOutputStream or OstreamOutputStream
// respectively.
class LIBPROTOBUF_EXPORT CopyingOutputStreamAdaptor : public ZeroCopyOutputStream {
public:
// Creates a stream that writes to the given Unix file descriptor.
// If a block_size is given, it specifies the size of the buffers
// that should be returned by Next(). Otherwise, a reasonable default
// is used.
explicit CopyingOutputStreamAdaptor(CopyingOutputStream* copying_stream,
int block_size = -1);
~CopyingOutputStreamAdaptor();
// Writes all pending data to the underlying stream. Returns false if a
// write error occurred on the underlying stream. (The underlying
// stream itself is not necessarily flushed.)
bool Flush();
// Call SetOwnsCopyingStream(true) to tell the CopyingOutputStreamAdaptor to
// delete the underlying CopyingOutputStream when it is destroyed.
void SetOwnsCopyingStream(bool value) { owns_copying_stream_ = value; }
// implements ZeroCopyOutputStream ---------------------------------
bool Next(void** data, int* size);
void BackUp(int count);
int64 ByteCount() const;
private:
// Write the current buffer, if it is present.
bool WriteBuffer();
// Insures that buffer_ is not NULL.
void AllocateBufferIfNeeded();
// Frees the buffer.
void FreeBuffer();
// The underlying copying stream.
CopyingOutputStream* copying_stream_;
bool owns_copying_stream_;
// True if we have seen a permenant error from the underlying stream.
bool failed_;
// The current position of copying_stream_, relative to the point where
// we started writing.
int64 position_;
// Data is written from this buffer. It may be NULL if no buffer is
// currently in use. Otherwise, it points to an array of size buffer_size_.
std::unique_ptr<uint8[]> buffer_;
const int buffer_size_;
// Number of valid bytes currently in the buffer (i.e. the size last
// returned by Next()). When BackUp() is called, we just reduce this.
// 0 <= buffer_used_ <= buffer_size_.
int buffer_used_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingOutputStreamAdaptor);
};
// ===================================================================
// mutable_string_data() and as_string_data() are workarounds to improve
// the performance of writing new data to an existing string. Unfortunately
// the methods provided by the string class are suboptimal, and using memcpy()
// is mildly annoying because it requires its pointer args to be non-NULL even
// if we ask it to copy 0 bytes. Furthermore, string_as_array() has the
// property that it always returns NULL if its arg is the empty string, exactly
// what we want to avoid if we're using it in conjunction with memcpy()!
// With C++11, the desired memcpy() boils down to memcpy(..., &(*s)[0], size),
// where s is a string*. Without C++11, &(*s)[0] is not guaranteed to be safe,
// so we use string_as_array(), and live with the extra logic that tests whether
// *s is empty.
// Return a pointer to mutable characters underlying the given string. The
// return value is valid until the next time the string is resized. We
// trust the caller to treat the return value as an array of length s->size().
inline char* mutable_string_data(string* s) {
#ifdef LANG_CXX11
// This should be simpler & faster than string_as_array() because the latter
// is guaranteed to return NULL when *s is empty, so it has to check for that.
return &(*s)[0];
#else
return string_as_array(s);
#endif
}
// as_string_data(s) is equivalent to
// ({ char* p = mutable_string_data(s); make_pair(p, p != NULL); })
// Sometimes it's faster: in some scenarios p cannot be NULL, and then the
// code can avoid that check.
inline std::pair<char*, bool> as_string_data(string* s) {
char *p = mutable_string_data(s);
#ifdef LANG_CXX11
return std::make_pair(p, true);
#else
return std::make_pair(p, p != NULL);
#endif
}
} // namespace io
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_LITE_H__

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,671 @@
// 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_MAP_ENTRY_LITE_H__
#define GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__
#include <assert.h>
#include <google/protobuf/stubs/casts.h>
#include <google/protobuf/arena.h>
#include <google/protobuf/arenastring.h>
#include <google/protobuf/map.h>
#include <google/protobuf/map_type_handler.h>
#include <google/protobuf/stubs/port.h>
#include <google/protobuf/wire_format_lite_inl.h>
namespace google {
namespace protobuf {
namespace internal {
template <typename Derived, typename Key, typename Value,
WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType, int default_enum_value>
class MapEntry;
template <typename Derived, typename Key, typename Value,
WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType, int default_enum_value>
class MapFieldLite;
} // namespace internal
} // namespace protobuf
namespace protobuf {
namespace internal {
// MoveHelper::Move is used to set *dest. It copies *src, or moves it (in
// the C++11 sense), or swaps it. *src is left in a sane state for
// subsequent destruction, but shouldn't be used for anything.
template <bool is_enum, bool is_message, bool is_stringlike, typename T>
struct MoveHelper { // primitives
static void Move(T* src, T* dest) { *dest = *src; }
};
template <bool is_message, bool is_stringlike, typename T>
struct MoveHelper<true, is_message, is_stringlike, T> { // enums
static void Move(T* src, T* dest) { *dest = *src; }
// T is an enum here, so allow conversions to and from int.
static void Move(T* src, int* dest) { *dest = static_cast<int>(*src); }
static void Move(int* src, T* dest) { *dest = static_cast<T>(*src); }
};
template <bool is_stringlike, typename T>
struct MoveHelper<false, true, is_stringlike, T> { // messages
static void Move(T* src, T* dest) { dest->Swap(src); }
};
template <typename T>
struct MoveHelper<false, false, true, T> { // strings and similar
static void Move(T* src, T* dest) {
#if __cplusplus >= 201103L
*dest = std::move(*src);
#else
dest->swap(*src);
#endif
}
};
// MapEntryImpl is used to implement parsing and serialization of map entries.
// It uses Curious Recursive Template Pattern (CRTP) to provide the type of
// the eventual code to the template code.
template <typename Derived, typename Base, typename Key, typename Value,
WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType, int default_enum_value>
class MapEntryImpl : public Base {
protected:
// Provide utilities to parse/serialize key/value. Provide utilities to
// manipulate internal stored type.
typedef MapTypeHandler<kKeyFieldType, Key> KeyTypeHandler;
typedef MapTypeHandler<kValueFieldType, Value> ValueTypeHandler;
// Define internal memory layout. Strings and messages are stored as
// pointers, while other types are stored as values.
typedef typename KeyTypeHandler::TypeOnMemory KeyOnMemory;
typedef typename ValueTypeHandler::TypeOnMemory ValueOnMemory;
// Enum type cannot be used for MapTypeHandler::Read. Define a type
// which will replace Enum with int.
typedef typename KeyTypeHandler::MapEntryAccessorType KeyMapEntryAccessorType;
typedef typename ValueTypeHandler::MapEntryAccessorType
ValueMapEntryAccessorType;
// Constants for field number.
static const int kKeyFieldNumber = 1;
static const int kValueFieldNumber = 2;
// Constants for field tag.
static const uint8 kKeyTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(
kKeyFieldNumber, KeyTypeHandler::kWireType);
static const uint8 kValueTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(
kValueFieldNumber, ValueTypeHandler::kWireType);
static const size_t kTagSize = 1;
public:
// Work-around for a compiler bug (see repeated_field.h).
typedef void MapEntryHasMergeTypeTrait;
typedef Derived EntryType;
typedef Key EntryKeyType;
typedef Value EntryValueType;
static const WireFormatLite::FieldType kEntryKeyFieldType = kKeyFieldType;
static const WireFormatLite::FieldType kEntryValueFieldType = kValueFieldType;
static const int kEntryDefaultEnumValue = default_enum_value;
MapEntryImpl() : arena_(NULL) {
KeyTypeHandler::Initialize(&key_, NULL);
ValueTypeHandler::InitializeMaybeByDefaultEnum(&value_, default_enum_value,
NULL);
_has_bits_[0] = 0;
}
explicit MapEntryImpl(Arena* arena) : arena_(arena) {
KeyTypeHandler::Initialize(&key_, arena);
ValueTypeHandler::InitializeMaybeByDefaultEnum(&value_, default_enum_value,
arena);
_has_bits_[0] = 0;
}
~MapEntryImpl() {
if (GetArenaNoVirtual() != NULL) return;
KeyTypeHandler::DeleteNoArena(key_);
ValueTypeHandler::DeleteNoArena(value_);
}
// accessors ======================================================
virtual inline const KeyMapEntryAccessorType& key() const {
return KeyTypeHandler::GetExternalReference(key_);
}
virtual inline const ValueMapEntryAccessorType& value() const {
return ValueTypeHandler::DefaultIfNotInitialized(
value_, Derived::internal_default_instance()->value_);
}
inline KeyMapEntryAccessorType* mutable_key() {
set_has_key();
return KeyTypeHandler::EnsureMutable(&key_, GetArenaNoVirtual());
}
inline ValueMapEntryAccessorType* mutable_value() {
set_has_value();
return ValueTypeHandler::EnsureMutable(&value_, GetArenaNoVirtual());
}
// implements MessageLite =========================================
// MapEntryImpl is for implementation only and this function isn't called
// anywhere. Just provide a fake implementation here for MessageLite.
string GetTypeName() const { return ""; }
void CheckTypeAndMergeFrom(const MessageLite& other) {
MergeFromInternal(*::google::protobuf::down_cast<const Derived*>(&other));
}
bool MergePartialFromCodedStream(::google::protobuf::io::CodedInputStream* input) {
uint32 tag;
for (;;) {
// 1) corrupted data: return false;
// 2) unknown field: skip without putting into unknown field set;
// 3) unknown enum value: keep it in parsing. In proto2, caller should
// check the value and put this entry into containing message's unknown
// field set if the value is an unknown enum. In proto3, caller doesn't
// need to care whether the value is unknown enum;
// 4) missing key/value: missed key/value will have default value. caller
// should take this entry as if key/value is set to default value.
tag = input->ReadTagNoLastTag();
switch (tag) {
case kKeyTag:
if (!KeyTypeHandler::Read(input, mutable_key())) {
return false;
}
set_has_key();
break;
case kValueTag:
if (!ValueTypeHandler::Read(input, mutable_value())) {
return false;
}
set_has_value();
if (input->ExpectAtEnd()) return true;
break;
default:
if (tag == 0 ||
WireFormatLite::GetTagWireType(tag) ==
WireFormatLite::WIRETYPE_END_GROUP) {
return true;
}
if (!WireFormatLite::SkipField(input, tag)) return false;
break;
}
}
}
size_t ByteSizeLong() const {
size_t size = 0;
size += has_key() ?
kTagSize + static_cast<size_t>(KeyTypeHandler::ByteSize(key())) : 0;
size += has_value() ?
kTagSize + static_cast<size_t>(ValueTypeHandler::ByteSize(value())) : 0;
return size;
}
void SerializeWithCachedSizes(::google::protobuf::io::CodedOutputStream* output) const {
KeyTypeHandler::Write(kKeyFieldNumber, key(), output);
ValueTypeHandler::Write(kValueFieldNumber, value(), output);
}
::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(bool deterministic,
::google::protobuf::uint8* output) const {
output = KeyTypeHandler::InternalWriteToArray(kKeyFieldNumber, key(),
deterministic, output);
output = ValueTypeHandler::InternalWriteToArray(kValueFieldNumber, value(),
deterministic, output);
return output;
}
// Don't override SerializeWithCachedSizesToArray. Use MessageLite's.
int GetCachedSize() const {
int size = 0;
size += has_key()
? static_cast<int>(kTagSize) + KeyTypeHandler::GetCachedSize(key())
: 0;
size += has_value()
? static_cast<int>(kTagSize) + ValueTypeHandler::GetCachedSize(value())
: 0;
return size;
}
bool IsInitialized() const { return ValueTypeHandler::IsInitialized(value_); }
Base* New() const {
Derived* entry = new Derived;
return entry;
}
Base* New(Arena* arena) const {
Derived* entry = Arena::CreateMessage<Derived>(arena);
return entry;
}
size_t SpaceUsedLong() const {
size_t size = sizeof(Derived);
size += KeyTypeHandler::SpaceUsedInMapEntryLong(key_);
size += ValueTypeHandler::SpaceUsedInMapEntryLong(value_);
return size;
}
protected:
// We can't declare this function directly here as it would hide the other
// overload (const Message&).
void MergeFromInternal(const MapEntryImpl& from) {
if (from._has_bits_[0]) {
if (from.has_key()) {
KeyTypeHandler::EnsureMutable(&key_, GetArenaNoVirtual());
KeyTypeHandler::Merge(from.key(), &key_, GetArenaNoVirtual());
set_has_key();
}
if (from.has_value()) {
ValueTypeHandler::EnsureMutable(&value_, GetArenaNoVirtual());
ValueTypeHandler::Merge(from.value(), &value_, GetArenaNoVirtual());
set_has_value();
}
}
}
public:
void Clear() {
KeyTypeHandler::Clear(&key_, GetArenaNoVirtual());
ValueTypeHandler::ClearMaybeByDefaultEnum(
&value_, GetArenaNoVirtual(), default_enum_value);
clear_has_key();
clear_has_value();
}
static void InitAsDefaultInstance() {
Derived* d = const_cast<Derived*>(Derived::internal_default_instance());
KeyTypeHandler::AssignDefaultValue(&d->key_);
ValueTypeHandler::AssignDefaultValue(&d->value_);
}
Arena* GetArena() const {
return GetArenaNoVirtual();
}
// Create a MapEntryImpl for given key and value from google::protobuf::Map in
// serialization. This function is only called when value is enum. Enum is
// treated differently because its type in MapEntry is int and its type in
// google::protobuf::Map is enum. We cannot create a reference to int from an enum.
static Derived* EnumWrap(const Key& key, const Value value, Arena* arena) {
return Arena::CreateMessage<MapEnumEntryWrapper>(arena, key, value);
}
// Like above, but for all the other types. This avoids value copy to create
// MapEntryImpl from google::protobuf::Map in serialization.
static Derived* Wrap(const Key& key, const Value& value, Arena* arena) {
return Arena::CreateMessage<MapEntryWrapper>(arena, key, value);
}
// Parsing using MergePartialFromCodedStream, above, is not as
// efficient as it could be. This helper class provides a speedier way.
template <typename MapField, typename Map>
class Parser {
public:
explicit Parser(MapField* mf) : mf_(mf), map_(mf->MutableMap()) {}
// This does what the typical MergePartialFromCodedStream() is expected to
// do, with the additional side-effect that if successful (i.e., if true is
// going to be its return value) it inserts the key-value pair into map_.
bool MergePartialFromCodedStream(::google::protobuf::io::CodedInputStream* input) {
// Look for the expected thing: a key and then a value. If it fails,
// invoke the enclosing class's MergePartialFromCodedStream, or return
// false if that would be pointless.
if (input->ExpectTag(kKeyTag)) {
if (!KeyTypeHandler::Read(input, &key_)) {
return false;
}
// Peek at the next byte to see if it is kValueTag. If not, bail out.
const void* data;
int size;
input->GetDirectBufferPointerInline(&data, &size);
// We could use memcmp here, but we don't bother. The tag is one byte.
GOOGLE_COMPILE_ASSERT(kTagSize == 1, tag_size_error);
if (size > 0 && *reinterpret_cast<const char*>(data) == kValueTag) {
typename Map::size_type map_size = map_->size();
value_ptr_ = &(*map_)[key_];
if (GOOGLE_PREDICT_TRUE(map_size != map_->size())) {
// We created a new key-value pair. Fill in the value.
typedef
typename MapIf<ValueTypeHandler::kIsEnum, int*, Value*>::type T;
input->Skip(kTagSize); // Skip kValueTag.
if (!ValueTypeHandler::Read(input,
reinterpret_cast<T>(value_ptr_))) {
map_->erase(key_); // Failure! Undo insertion.
return false;
}
if (input->ExpectAtEnd()) return true;
return ReadBeyondKeyValuePair(input);
}
}
} else {
key_ = Key();
}
entry_.reset(mf_->NewEntry());
*entry_->mutable_key() = key_;
const bool result = entry_->MergePartialFromCodedStream(input);
if (result) UseKeyAndValueFromEntry();
if (entry_->GetArena() != NULL) entry_.release();
return result;
}
const Key& key() const { return key_; }
const Value& value() const { return *value_ptr_; }
private:
void UseKeyAndValueFromEntry() GOOGLE_PROTOBUF_ATTRIBUTE_COLD {
// Update key_ in case we need it later (because key() is called).
// This is potentially inefficient, especially if the key is
// expensive to copy (e.g., a long string), but this is a cold
// path, so it's not a big deal.
key_ = entry_->key();
value_ptr_ = &(*map_)[key_];
MoveHelper<ValueTypeHandler::kIsEnum,
ValueTypeHandler::kIsMessage,
ValueTypeHandler::kWireType ==
WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
Value>::Move(entry_->mutable_value(), value_ptr_);
}
// After reading a key and value successfully, and inserting that data
// into map_, we are not at the end of the input. This is unusual, but
// allowed by the spec.
bool ReadBeyondKeyValuePair(::google::protobuf::io::CodedInputStream* input)
GOOGLE_PROTOBUF_ATTRIBUTE_COLD {
typedef MoveHelper<KeyTypeHandler::kIsEnum,
KeyTypeHandler::kIsMessage,
KeyTypeHandler::kWireType ==
WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
Key> KeyMover;
typedef MoveHelper<ValueTypeHandler::kIsEnum,
ValueTypeHandler::kIsMessage,
ValueTypeHandler::kWireType ==
WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
Value> ValueMover;
entry_.reset(mf_->NewEntry());
ValueMover::Move(value_ptr_, entry_->mutable_value());
map_->erase(key_);
KeyMover::Move(&key_, entry_->mutable_key());
const bool result = entry_->MergePartialFromCodedStream(input);
if (result) UseKeyAndValueFromEntry();
if (entry_->GetArena() != NULL) entry_.release();
return result;
}
MapField* const mf_;
Map* const map_;
Key key_;
Value* value_ptr_;
// On the fast path entry_ is not used. And, when entry_ is used, it's set
// to mf_->NewEntry(), so in the arena case we must call entry_.release.
std::unique_ptr<MapEntryImpl> entry_;
};
protected:
void set_has_key() { _has_bits_[0] |= 0x00000001u; }
bool has_key() const { return (_has_bits_[0] & 0x00000001u) != 0; }
void clear_has_key() { _has_bits_[0] &= ~0x00000001u; }
void set_has_value() { _has_bits_[0] |= 0x00000002u; }
bool has_value() const { return (_has_bits_[0] & 0x00000002u) != 0; }
void clear_has_value() { _has_bits_[0] &= ~0x00000002u; }
private:
// Serializing a generated message containing map field involves serializing
// key-value pairs from google::protobuf::Map. The wire format of each key-value pair
// after serialization should be the same as that of a MapEntry message
// containing the same key and value inside it. However, google::protobuf::Map doesn't
// store key and value as MapEntry message, which disables us to use existing
// code to serialize message. In order to use existing code to serialize
// message, we need to construct a MapEntry from key-value pair. But it
// involves copy of key and value to construct a MapEntry. In order to avoid
// this copy in constructing a MapEntry, we need the following class which
// only takes references of given key and value.
class MapEntryWrapper : public Derived {
typedef Derived BaseClass;
typedef typename BaseClass::KeyMapEntryAccessorType KeyMapEntryAccessorType;
typedef
typename BaseClass::ValueMapEntryAccessorType ValueMapEntryAccessorType;
public:
MapEntryWrapper(Arena* arena, const Key& key, const Value& value)
: Derived(arena), key_(key), value_(value) {
BaseClass::set_has_key();
BaseClass::set_has_value();
}
inline const KeyMapEntryAccessorType& key() const { return key_; }
inline const ValueMapEntryAccessorType& value() const { return value_; }
private:
const Key& key_;
const Value& value_;
friend class ::google::protobuf::Arena;
typedef void InternalArenaConstructable_;
typedef void DestructorSkippable_;
};
// Like above, but for enum value only, which stores value instead of
// reference of value field inside. This is needed because the type of value
// field in constructor is an enum, while we need to store it as an int. If we
// initialize a reference to int with a reference to enum, compiler will
// generate a temporary int from enum and initialize the reference to int with
// the temporary.
class MapEnumEntryWrapper : public Derived {
typedef Derived BaseClass;
typedef typename BaseClass::KeyMapEntryAccessorType KeyMapEntryAccessorType;
typedef
typename BaseClass::ValueMapEntryAccessorType ValueMapEntryAccessorType;
public:
MapEnumEntryWrapper(Arena* arena, const Key& key, const Value& value)
: Derived(arena), key_(key), value_(value) {
BaseClass::set_has_key();
BaseClass::set_has_value();
}
inline const KeyMapEntryAccessorType& key() const { return key_; }
inline const ValueMapEntryAccessorType& value() const { return value_; }
private:
const KeyMapEntryAccessorType& key_;
const ValueMapEntryAccessorType value_;
friend class google::protobuf::Arena;
typedef void DestructorSkippable_;
};
inline Arena* GetArenaNoVirtual() const {
return arena_;
}
public: // Needed for constructing tables
KeyOnMemory key_;
ValueOnMemory value_;
Arena* arena_;
uint32 _has_bits_[1];
private:
friend class ::google::protobuf::Arena;
typedef void InternalArenaConstructable_;
typedef void DestructorSkippable_;
template <typename C, typename K, typename V, WireFormatLite::FieldType,
WireFormatLite::FieldType, int>
friend class internal::MapEntry;
template <typename C, typename K, typename V, WireFormatLite::FieldType,
WireFormatLite::FieldType, int>
friend class internal::MapFieldLite;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapEntryImpl);
};
template <typename T, typename Key, typename Value,
WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType, int default_enum_value>
class MapEntryLite
: public MapEntryImpl<T, MessageLite, Key, Value, kKeyFieldType,
kValueFieldType, default_enum_value> {
public:
typedef MapEntryImpl<T, MessageLite, Key, Value, kKeyFieldType,
kValueFieldType, default_enum_value>
SuperType;
MapEntryLite() {}
explicit MapEntryLite(Arena* arena) : SuperType(arena) {}
void MergeFrom(const MapEntryLite& other) { MergeFromInternal(other); }
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapEntryLite);
};
// The completely unprincipled and unwieldy use of template parameters in
// the map code necessitates wrappers to make the code a little bit more
// manageable.
template <typename Derived>
struct DeconstructMapEntry;
template <typename T, typename K, typename V, WireFormatLite::FieldType key,
WireFormatLite::FieldType value, int default_enum>
struct DeconstructMapEntry<MapEntryLite<T, K, V, key, value, default_enum> > {
typedef K Key;
typedef V Value;
static const WireFormatLite::FieldType kKeyFieldType = key;
static const WireFormatLite::FieldType kValueFieldType = value;
static const int default_enum_value = default_enum;
};
// Helpers for deterministic serialization =============================
// This struct can be used with any generic sorting algorithm. If the Key
// type is relatively small and easy to copy then copying Keys into an
// array of SortItems can be beneficial. Then all the data the sorting
// algorithm needs to touch is in that one array.
template <typename Key, typename PtrToKeyValuePair> struct SortItem {
SortItem() {}
explicit SortItem(PtrToKeyValuePair p) : first(p->first), second(p) {}
Key first;
PtrToKeyValuePair second;
};
template <typename T> struct CompareByFirstField {
bool operator()(const T& a, const T& b) const {
return a.first < b.first;
}
};
template <typename T> struct CompareByDerefFirst {
bool operator()(const T& a, const T& b) const {
return a->first < b->first;
}
};
// Helper for table driven serialization
template <WireFormatLite::FieldType FieldType>
struct FromHelper {
template <typename T>
static const T& From(const T& x) {
return x;
}
};
template <>
struct FromHelper<WireFormatLite::TYPE_STRING> {
static ArenaStringPtr From(const string& x) {
ArenaStringPtr res;
TaggedPtr<::std::string> ptr;
ptr.Set(const_cast<string*>(&x));
res.UnsafeSetTaggedPointer(ptr);
return res;
}
};
template <>
struct FromHelper<WireFormatLite::TYPE_BYTES> {
static ArenaStringPtr From(const string& x) {
ArenaStringPtr res;
TaggedPtr<::std::string> ptr;
ptr.Set(const_cast<string*>(&x));
res.UnsafeSetTaggedPointer(ptr);
return res;
}
};
template <>
struct FromHelper<WireFormatLite::TYPE_MESSAGE> {
template <typename T>
static T* From(const T& x) {
return const_cast<T*>(&x);
}
};
template <typename MapEntryType>
struct MapEntryHelper;
template <typename T, typename Key, typename Value,
WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType, int default_enum_value>
struct MapEntryHelper<MapEntryLite<T, Key, Value, kKeyFieldType,
kValueFieldType, default_enum_value> > {
// Provide utilities to parse/serialize key/value. Provide utilities to
// manipulate internal stored type.
typedef MapTypeHandler<kKeyFieldType, Key> KeyTypeHandler;
typedef MapTypeHandler<kValueFieldType, Value> ValueTypeHandler;
// Define internal memory layout. Strings and messages are stored as
// pointers, while other types are stored as values.
typedef typename KeyTypeHandler::TypeOnMemory KeyOnMemory;
typedef typename ValueTypeHandler::TypeOnMemory ValueOnMemory;
explicit MapEntryHelper(const MapPair<Key, Value>& map_pair)
: _has_bits_(3),
_cached_size_(2 + KeyTypeHandler::GetCachedSize(map_pair.first) +
ValueTypeHandler::GetCachedSize(map_pair.second)),
key_(FromHelper<kKeyFieldType>::From(map_pair.first)),
value_(FromHelper<kValueFieldType>::From(map_pair.second)) {}
// Purposely not folowing the style guide naming. These are the names
// the proto compiler would generate given the map entry descriptor.
// The proto compiler generates the offsets in this struct as if this was
// a regular message. This way the table driven code barely notices it's
// dealing with a map field.
uint32 _has_bits_; // NOLINT
uint32 _cached_size_; // NOLINT
KeyOnMemory key_; // NOLINT
ValueOnMemory value_; // NOLINT
};
} // namespace internal
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__

View File

@ -0,0 +1,143 @@
// 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_MAP_FIELD_LITE_H__
#define GOOGLE_PROTOBUF_MAP_FIELD_LITE_H__
#include <google/protobuf/map.h>
#include <google/protobuf/map_entry_lite.h>
#include <google/protobuf/wire_format_lite.h>
namespace google {
namespace protobuf {
namespace internal {
// This class provides access to map field using generated api. It is used for
// internal generated message implentation only. Users should never use this
// directly.
template <typename Derived, typename Key, typename T,
WireFormatLite::FieldType key_wire_type,
WireFormatLite::FieldType value_wire_type, int default_enum_value = 0>
class MapFieldLite {
// Define message type for internal repeated field.
typedef Derived EntryType;
public:
typedef Map<Key, T> MapType;
typedef EntryType EntryTypeTrait;
MapFieldLite() : arena_(NULL) { SetDefaultEnumValue(); }
explicit MapFieldLite(Arena* arena) : arena_(arena), map_(arena) {
SetDefaultEnumValue();
}
// Accessors
const Map<Key, T>& GetMap() const { return map_; }
Map<Key, T>* MutableMap() { return &map_; }
// Convenient methods for generated message implementation.
int size() const { return static_cast<int>(map_.size()); }
void Clear() { return map_.clear(); }
void MergeFrom(const MapFieldLite& other) {
for (typename Map<Key, T>::const_iterator it = other.map_.begin();
it != other.map_.end(); ++it) {
map_[it->first] = it->second;
}
}
void Swap(MapFieldLite* other) { map_.swap(other->map_); }
// Set default enum value only for proto2 map field whose value is enum type.
void SetDefaultEnumValue() {
MutableMap()->SetDefaultEnumValue(default_enum_value);
}
// Used in the implementation of parsing. Caller should take the ownership iff
// arena_ is NULL.
EntryType* NewEntry() const {
if (arena_ == NULL) {
return new EntryType();
} else {
return Arena::CreateMessage<EntryType>(arena_);
}
}
// Used in the implementation of serializing enum value type. Caller should
// take the ownership iff arena_ is NULL.
EntryType* NewEnumEntryWrapper(const Key& key, const T t) const {
return EntryType::EnumWrap(key, t, arena_);
}
// Used in the implementation of serializing other value types. Caller should
// take the ownership iff arena_ is NULL.
EntryType* NewEntryWrapper(const Key& key, const T& t) const {
return EntryType::Wrap(key, t, arena_);
}
private:
typedef void DestructorSkippable_;
Arena* arena_;
Map<Key, T> map_;
friend class ::google::protobuf::Arena;
};
// True if IsInitialized() is true for value field in all elements of t. T is
// expected to be message. It's useful to have this helper here to keep the
// protobuf compiler from ever having to emit loops in IsInitialized() methods.
// We want the C++ compiler to inline this or not as it sees fit.
template <typename Key, typename T>
bool AllAreInitialized(const Map<Key, T>& t) {
for (typename Map<Key, T>::const_iterator it = t.begin(); it != t.end();
++it) {
if (!it->second.IsInitialized()) return false;
}
return true;
}
template <typename MEntry>
struct MapEntryToMapField : MapEntryToMapField<typename MEntry::SuperType> {};
template <typename T, typename Key, typename Value,
WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType, int default_enum_value>
struct MapEntryToMapField<MapEntryLite<T, Key, Value, kKeyFieldType,
kValueFieldType, default_enum_value> > {
typedef MapFieldLite<MapEntryLite<T, Key, Value, kKeyFieldType,
kValueFieldType, default_enum_value>,
Key, Value, kKeyFieldType, kValueFieldType,
default_enum_value>
MapFieldType;
};
} // namespace internal
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_MAP_FIELD_LITE_H__

View File

@ -0,0 +1,739 @@
// 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_TYPE_HANDLER_H__
#define GOOGLE_PROTOBUF_TYPE_HANDLER_H__
#include <google/protobuf/arena.h>
#include <google/protobuf/wire_format_lite_inl.h>
namespace google {
namespace protobuf {
namespace internal {
// Used for compile time type selection. MapIf::type will be TrueType if Flag is
// true and FalseType otherwise.
template<bool Flag, typename TrueType, typename FalseType>
struct MapIf;
template<typename TrueType, typename FalseType>
struct MapIf<true, TrueType, FalseType> {
typedef TrueType type;
};
template<typename TrueType, typename FalseType>
struct MapIf<false, TrueType, FalseType> {
typedef FalseType type;
};
// In proto2 Map, enum needs to be initialized to given default value, while
// other types' default value can be inferred from the type.
template <bool IsEnum, typename Type>
class MapValueInitializer {
public:
static inline void Initialize(Type& type, int default_enum_value);
};
template <typename Type>
class MapValueInitializer<true, Type> {
public:
static inline void Initialize(Type& value, int default_enum_value) {
value = static_cast<Type>(default_enum_value);
}
};
template <typename Type>
class MapValueInitializer<false, Type> {
public:
static inline void Initialize(Type& /* value */, int /* default_enum_value */) {}
};
template <typename Type, bool is_arena_constructable>
class MapArenaMessageCreator {
public:
// Use arena to create message if Type is arena constructable. Otherwise,
// create the message on heap.
static inline Type* CreateMessage(Arena* arena);
};
template <typename Type>
class MapArenaMessageCreator<Type, true> {
public:
static inline Type* CreateMessage(Arena* arena) {
return Arena::CreateMessage<Type>(arena);
}
};
template <typename Type>
class MapArenaMessageCreator<Type, false> {
public:
static inline Type* CreateMessage(Arena* arena) {
return Arena::Create<Type>(arena);
}
};
// Define constants for given wire field type
template <WireFormatLite::FieldType field_type, typename Type>
class MapWireFieldTypeTraits {};
#define TYPE_TRAITS(FieldType, CType, WireFormatType, IsMessage, IsEnum) \
template <typename Type> \
class MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType, Type> { \
public: \
static const bool kIsMessage = IsMessage; \
static const bool kIsEnum = IsEnum; \
typedef typename MapIf<kIsMessage, Type*, CType>::type TypeOnMemory; \
typedef typename MapIf<kIsEnum, int, Type>::type MapEntryAccessorType; \
static const WireFormatLite::WireType kWireType = \
WireFormatLite::WIRETYPE_##WireFormatType; \
};
TYPE_TRAITS(MESSAGE , Type, LENGTH_DELIMITED, true, false)
TYPE_TRAITS(STRING , ArenaStringPtr, LENGTH_DELIMITED, false, false)
TYPE_TRAITS(BYTES , ArenaStringPtr , LENGTH_DELIMITED, false, false)
TYPE_TRAITS(INT64 , int64 , VARINT , false, false)
TYPE_TRAITS(UINT64 , uint64 , VARINT , false, false)
TYPE_TRAITS(INT32 , int32 , VARINT , false, false)
TYPE_TRAITS(UINT32 , uint32 , VARINT , false, false)
TYPE_TRAITS(SINT64 , int64 , VARINT , false, false)
TYPE_TRAITS(SINT32 , int32 , VARINT , false, false)
TYPE_TRAITS(ENUM , int , VARINT , false, true )
TYPE_TRAITS(DOUBLE , double , FIXED64, false, false)
TYPE_TRAITS(FLOAT , float , FIXED32, false, false)
TYPE_TRAITS(FIXED64 , uint64 , FIXED64, false, false)
TYPE_TRAITS(FIXED32 , uint32 , FIXED32, false, false)
TYPE_TRAITS(SFIXED64, int64 , FIXED64, false, false)
TYPE_TRAITS(SFIXED32, int32 , FIXED32, false, false)
TYPE_TRAITS(BOOL , bool , VARINT , false, false)
#undef TYPE_TRAITS
template <WireFormatLite::FieldType field_type, typename Type>
class MapTypeHandler {};
template <typename Type>
class MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type> {
public:
// Enum type cannot be used for MapTypeHandler::Read. Define a type which will
// replace Enum with int.
typedef typename MapWireFieldTypeTraits<WireFormatLite::TYPE_MESSAGE,
Type>::MapEntryAccessorType MapEntryAccessorType;
// Internal stored type in MapEntryLite for given wire field type.
typedef typename MapWireFieldTypeTraits<WireFormatLite::TYPE_MESSAGE,
Type>::TypeOnMemory TypeOnMemory;
// Corresponding wire type for field type.
static const WireFormatLite::WireType kWireType =
MapWireFieldTypeTraits<WireFormatLite::TYPE_MESSAGE, Type>::kWireType;
// Whether wire type is for message.
static const bool kIsMessage =
MapWireFieldTypeTraits<WireFormatLite::TYPE_MESSAGE, Type>::kIsMessage;
// Whether wire type is for enum.
static const bool kIsEnum =
MapWireFieldTypeTraits<WireFormatLite::TYPE_MESSAGE, Type>::kIsEnum;
// Functions used in parsing and serialization. ===================
static inline size_t ByteSize(const MapEntryAccessorType& value);
static inline int GetCachedSize(const MapEntryAccessorType& value);
static inline bool Read(io::CodedInputStream* input,
MapEntryAccessorType* value);
static inline void Write(int field, const MapEntryAccessorType& value,
io::CodedOutputStream* output);
static inline uint8* InternalWriteToArray(int field,
const MapEntryAccessorType& value,
bool deterministic, uint8* target);
static inline uint8* WriteToArray(int field,
const MapEntryAccessorType& value,
uint8* target);
// Functions to manipulate data on memory. ========================
static inline const Type& GetExternalReference(const Type* value);
static inline void DeleteNoArena(const Type* x);
static inline void Merge(const Type& from, Type** to, Arena* arena);
static inline void Clear(Type** value, Arena* arena);
static inline void ClearMaybeByDefaultEnum(Type** value, Arena* arena,
int default_enum_value);
static inline void Initialize(Type** x, Arena* arena);
static inline void InitializeMaybeByDefaultEnum(Type** x,
int default_enum_value,
Arena* arena);
static inline Type* EnsureMutable(Type** value, Arena* arena);
// SpaceUsedInMapEntry: Return bytes used by value in MapEntry, excluding
// those already calculate in sizeof(MapField).
static inline size_t SpaceUsedInMapEntryLong(const Type* value);
// Return bytes used by value in Map.
static inline size_t SpaceUsedInMapLong(const Type& value);
// Assign default value to given instance.
static inline void AssignDefaultValue(Type** value);
// Return default instance if value is not initialized when calling const
// reference accessor.
static inline const Type& DefaultIfNotInitialized(
const Type* value, const Type* default_value);
// Check if all required fields have values set.
static inline bool IsInitialized(Type* value);
};
#define MAP_HANDLER(FieldType) \
template <typename Type> \
class MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type> { \
public: \
typedef typename MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType, \
Type>::MapEntryAccessorType \
MapEntryAccessorType; \
typedef typename MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType, \
Type>::TypeOnMemory TypeOnMemory; \
static const WireFormatLite::WireType kWireType = \
MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType, \
Type>::kWireType; \
static const bool kIsMessage = \
MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType, \
Type>::kIsMessage; \
static const bool kIsEnum = \
MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType, \
Type>::kIsEnum; \
static inline int ByteSize(const MapEntryAccessorType& value); \
static inline int GetCachedSize(const MapEntryAccessorType& value); \
static inline bool Read(io::CodedInputStream* input, \
MapEntryAccessorType* value); \
static inline void Write(int field, const MapEntryAccessorType& value, \
io::CodedOutputStream* output); \
static inline uint8* InternalWriteToArray( \
int field, const MapEntryAccessorType& value, bool deterministic, \
uint8* target); \
static inline uint8* WriteToArray(int field, \
const MapEntryAccessorType& value, \
uint8* target) { \
return InternalWriteToArray(field, value, false, target); \
} \
static inline const MapEntryAccessorType& GetExternalReference( \
const TypeOnMemory& value); \
static inline void DeleteNoArena(const TypeOnMemory& x); \
static inline void Merge(const MapEntryAccessorType& from, \
TypeOnMemory* to, Arena* arena); \
static inline void Clear(TypeOnMemory* value, Arena* arena); \
static inline void ClearMaybeByDefaultEnum(TypeOnMemory* value, \
Arena* arena, \
int default_enum); \
static inline size_t SpaceUsedInMapEntryLong(const TypeOnMemory& value); \
static inline size_t SpaceUsedInMapLong(const TypeOnMemory& value); \
static inline size_t SpaceUsedInMapLong(const string& value); \
static inline void AssignDefaultValue(TypeOnMemory* value); \
static inline const MapEntryAccessorType& DefaultIfNotInitialized( \
const TypeOnMemory& value, const TypeOnMemory& default_value); \
static inline bool IsInitialized(const TypeOnMemory& value); \
static void DeleteNoArena(TypeOnMemory& value); \
static inline void Initialize(TypeOnMemory* value, Arena* arena); \
static inline void InitializeMaybeByDefaultEnum(TypeOnMemory* value, \
int default_enum_value, \
Arena* arena); \
static inline MapEntryAccessorType* EnsureMutable(TypeOnMemory* value, \
Arena* arena); \
};
MAP_HANDLER(STRING)
MAP_HANDLER(BYTES)
MAP_HANDLER(INT64)
MAP_HANDLER(UINT64)
MAP_HANDLER(INT32)
MAP_HANDLER(UINT32)
MAP_HANDLER(SINT64)
MAP_HANDLER(SINT32)
MAP_HANDLER(ENUM)
MAP_HANDLER(DOUBLE)
MAP_HANDLER(FLOAT)
MAP_HANDLER(FIXED64)
MAP_HANDLER(FIXED32)
MAP_HANDLER(SFIXED64)
MAP_HANDLER(SFIXED32)
MAP_HANDLER(BOOL)
#undef MAP_HANDLER
template <typename Type>
inline size_t
MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::ByteSize(
const MapEntryAccessorType& value) {
return WireFormatLite::MessageSizeNoVirtual(value);
}
#define GOOGLE_PROTOBUF_BYTE_SIZE(FieldType, DeclaredType) \
template <typename Type> \
inline int MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::ByteSize( \
const MapEntryAccessorType& value) { \
return static_cast<int>(WireFormatLite::DeclaredType##Size(value)); \
}
GOOGLE_PROTOBUF_BYTE_SIZE(STRING, String)
GOOGLE_PROTOBUF_BYTE_SIZE(BYTES , Bytes)
GOOGLE_PROTOBUF_BYTE_SIZE(INT64 , Int64)
GOOGLE_PROTOBUF_BYTE_SIZE(UINT64, UInt64)
GOOGLE_PROTOBUF_BYTE_SIZE(INT32 , Int32)
GOOGLE_PROTOBUF_BYTE_SIZE(UINT32, UInt32)
GOOGLE_PROTOBUF_BYTE_SIZE(SINT64, SInt64)
GOOGLE_PROTOBUF_BYTE_SIZE(SINT32, SInt32)
GOOGLE_PROTOBUF_BYTE_SIZE(ENUM , Enum)
#undef GOOGLE_PROTOBUF_BYTE_SIZE
#define FIXED_BYTE_SIZE(FieldType, DeclaredType) \
template <typename Type> \
inline int MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::ByteSize( \
const MapEntryAccessorType& /* value */) { \
return WireFormatLite::k##DeclaredType##Size; \
}
FIXED_BYTE_SIZE(DOUBLE , Double)
FIXED_BYTE_SIZE(FLOAT , Float)
FIXED_BYTE_SIZE(FIXED64 , Fixed64)
FIXED_BYTE_SIZE(FIXED32 , Fixed32)
FIXED_BYTE_SIZE(SFIXED64, SFixed64)
FIXED_BYTE_SIZE(SFIXED32, SFixed32)
FIXED_BYTE_SIZE(BOOL , Bool)
#undef FIXED_BYTE_SIZE
template <typename Type>
inline int
MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::GetCachedSize(
const MapEntryAccessorType& value) {
return static_cast<int>(
WireFormatLite::LengthDelimitedSize(
static_cast<size_t>(value.GetCachedSize())));
}
#define GET_CACHED_SIZE(FieldType, DeclaredType) \
template <typename Type> \
inline int \
MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::GetCachedSize( \
const MapEntryAccessorType& value) { \
return static_cast<int>(WireFormatLite::DeclaredType##Size(value)); \
}
GET_CACHED_SIZE(STRING, String)
GET_CACHED_SIZE(BYTES , Bytes)
GET_CACHED_SIZE(INT64 , Int64)
GET_CACHED_SIZE(UINT64, UInt64)
GET_CACHED_SIZE(INT32 , Int32)
GET_CACHED_SIZE(UINT32, UInt32)
GET_CACHED_SIZE(SINT64, SInt64)
GET_CACHED_SIZE(SINT32, SInt32)
GET_CACHED_SIZE(ENUM , Enum)
#undef GET_CACHED_SIZE
#define GET_FIXED_CACHED_SIZE(FieldType, DeclaredType) \
template <typename Type> \
inline int \
MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::GetCachedSize( \
const MapEntryAccessorType& /* value */) { \
return WireFormatLite::k##DeclaredType##Size; \
}
GET_FIXED_CACHED_SIZE(DOUBLE , Double)
GET_FIXED_CACHED_SIZE(FLOAT , Float)
GET_FIXED_CACHED_SIZE(FIXED64 , Fixed64)
GET_FIXED_CACHED_SIZE(FIXED32 , Fixed32)
GET_FIXED_CACHED_SIZE(SFIXED64, SFixed64)
GET_FIXED_CACHED_SIZE(SFIXED32, SFixed32)
GET_FIXED_CACHED_SIZE(BOOL , Bool)
#undef GET_FIXED_CACHED_SIZE
template <typename Type>
inline void MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::Write(
int field, const MapEntryAccessorType& value,
io::CodedOutputStream* output) {
WireFormatLite::WriteMessageMaybeToArray(field, value, output);
}
template <typename Type>
inline uint8*
MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::InternalWriteToArray(
int field, const MapEntryAccessorType& value, bool deterministic,
uint8* target) {
return WireFormatLite::InternalWriteMessageToArray(field, value,
deterministic, target);
}
#define WRITE_METHOD(FieldType, DeclaredType) \
template <typename Type> \
inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Write( \
int field, const MapEntryAccessorType& value, \
io::CodedOutputStream* output) { \
return WireFormatLite::Write##DeclaredType(field, value, output); \
} \
template <typename Type> \
inline uint8* \
MapTypeHandler<WireFormatLite::TYPE_##FieldType, \
Type>::InternalWriteToArray( \
int field, const MapEntryAccessorType& value, bool, uint8* target) { \
return WireFormatLite::Write##DeclaredType##ToArray(field, value, target); \
}
WRITE_METHOD(STRING , String)
WRITE_METHOD(BYTES , Bytes)
WRITE_METHOD(INT64 , Int64)
WRITE_METHOD(UINT64 , UInt64)
WRITE_METHOD(INT32 , Int32)
WRITE_METHOD(UINT32 , UInt32)
WRITE_METHOD(SINT64 , SInt64)
WRITE_METHOD(SINT32 , SInt32)
WRITE_METHOD(ENUM , Enum)
WRITE_METHOD(DOUBLE , Double)
WRITE_METHOD(FLOAT , Float)
WRITE_METHOD(FIXED64 , Fixed64)
WRITE_METHOD(FIXED32 , Fixed32)
WRITE_METHOD(SFIXED64, SFixed64)
WRITE_METHOD(SFIXED32, SFixed32)
WRITE_METHOD(BOOL , Bool)
#undef WRITE_METHOD
template <typename Type>
inline bool MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::Read(
io::CodedInputStream* input, MapEntryAccessorType* value) {
return WireFormatLite::ReadMessageNoVirtual(input, value);
}
template <typename Type>
inline bool MapTypeHandler<WireFormatLite::TYPE_STRING, Type>::Read(
io::CodedInputStream* input, MapEntryAccessorType* value) {
return WireFormatLite::ReadString(input, value);
}
template <typename Type>
inline bool MapTypeHandler<WireFormatLite::TYPE_BYTES, Type>::Read(
io::CodedInputStream* input, MapEntryAccessorType* value) {
return WireFormatLite::ReadBytes(input, value);
}
#define READ_METHOD(FieldType) \
template <typename Type> \
inline bool MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Read( \
io::CodedInputStream* input, MapEntryAccessorType* value) { \
return WireFormatLite::ReadPrimitive<TypeOnMemory, \
WireFormatLite::TYPE_##FieldType>( \
input, value); \
}
READ_METHOD(INT64)
READ_METHOD(UINT64)
READ_METHOD(INT32)
READ_METHOD(UINT32)
READ_METHOD(SINT64)
READ_METHOD(SINT32)
READ_METHOD(ENUM)
READ_METHOD(DOUBLE)
READ_METHOD(FLOAT)
READ_METHOD(FIXED64)
READ_METHOD(FIXED32)
READ_METHOD(SFIXED64)
READ_METHOD(SFIXED32)
READ_METHOD(BOOL)
#undef READ_METHOD
// Definition for message handler
template <typename Type>
inline const Type&
MapTypeHandler<WireFormatLite::TYPE_MESSAGE,
Type>::GetExternalReference(const Type* value) {
return *value;
}
template <typename Type>
inline size_t MapTypeHandler<WireFormatLite::TYPE_MESSAGE,
Type>::SpaceUsedInMapEntryLong(const Type* value) {
return value->SpaceUsedLong();
}
template <typename Type>
size_t MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::SpaceUsedInMapLong(
const Type& value) {
return value.SpaceUsedLong();
}
template <typename Type>
inline void MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::Clear(
Type** value, Arena* /* arena */) {
if (*value != NULL) (*value)->Clear();
}
template <typename Type>
inline void
MapTypeHandler<WireFormatLite::TYPE_MESSAGE,
Type>::ClearMaybeByDefaultEnum(Type** value,
Arena* /* arena */,
int /* default_enum_value */) {
if (*value != NULL) (*value)->Clear();
}
template <typename Type>
inline void MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::Merge(
const Type& from, Type** to, Arena* /* arena */) {
(*to)->MergeFrom(from);
}
template <typename Type>
void MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::DeleteNoArena(
const Type* ptr) {
delete ptr;
}
template <typename Type>
inline void MapTypeHandler<WireFormatLite::TYPE_MESSAGE,
Type>::AssignDefaultValue(Type** value) {
*value = const_cast<Type*>(Type::internal_default_instance());
}
template <typename Type>
inline void MapTypeHandler<WireFormatLite::TYPE_MESSAGE,
Type>::Initialize(Type** x,
Arena* /* arena */) {
*x = NULL;
}
template <typename Type>
inline void MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::
InitializeMaybeByDefaultEnum(Type** x, int /* default_enum_value */,
Arena* /* arena */) {
*x = NULL;
}
template <typename Type>
inline Type* MapTypeHandler<WireFormatLite::TYPE_MESSAGE,
Type>::EnsureMutable(Type** value,
Arena* arena) {
if (*value == NULL) {
*value =
MapArenaMessageCreator<Type, Arena::is_arena_constructable<Type>::
type::value>::CreateMessage(arena);
}
return *value;
}
template <typename Type>
inline const Type& MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::
DefaultIfNotInitialized(const Type* value, const Type* default_value) {
return value != NULL ? *value : *default_value;
}
template <typename Type>
inline bool MapTypeHandler<WireFormatLite::TYPE_MESSAGE,
Type>::IsInitialized(Type* value) {
return value->IsInitialized();
}
// Definition for string/bytes handler
#define STRING_OR_BYTES_HANDLER_FUNCTIONS(FieldType) \
template <typename Type> \
inline const typename MapTypeHandler<WireFormatLite::TYPE_##FieldType, \
Type>::MapEntryAccessorType& \
MapTypeHandler<WireFormatLite::TYPE_##FieldType, \
Type>::GetExternalReference(const TypeOnMemory& value) { \
return value.Get(); \
} \
template <typename Type> \
inline size_t \
MapTypeHandler<WireFormatLite::TYPE_##FieldType, \
Type>::SpaceUsedInMapEntryLong(const TypeOnMemory& value) { \
return sizeof(value); \
} \
template <typename Type> \
inline size_t \
MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::SpaceUsedInMapLong( \
const TypeOnMemory& value) { \
return sizeof(value); \
} \
template <typename Type> \
inline size_t \
MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::SpaceUsedInMapLong( \
const string& value) { \
return sizeof(value); \
} \
template <typename Type> \
inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Clear( \
TypeOnMemory* value, Arena* arena) { \
value->ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), \
arena); \
} \
template <typename Type> \
inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>:: \
ClearMaybeByDefaultEnum(TypeOnMemory* value, Arena* arena, \
int /* default_enum */) { \
Clear(value, arena); \
} \
template <typename Type> \
inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Merge( \
const MapEntryAccessorType& from, TypeOnMemory* to, Arena* arena) { \
to->Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from, arena); \
} \
template <typename Type> \
void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::DeleteNoArena( \
TypeOnMemory& value) { \
value.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); \
} \
template <typename Type> \
inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, \
Type>::AssignDefaultValue(TypeOnMemory* /* value */) {} \
template <typename Type> \
inline void \
MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Initialize( \
TypeOnMemory* value, Arena* /* arena */) { \
value->UnsafeSetDefault( \
&::google::protobuf::internal::GetEmptyStringAlreadyInited()); \
} \
template <typename Type> \
inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>:: \
InitializeMaybeByDefaultEnum(TypeOnMemory* value, \
int /* default_enum_value */, \
Arena* arena) { \
Initialize(value, arena); \
} \
template <typename Type> \
inline typename MapTypeHandler<WireFormatLite::TYPE_##FieldType, \
Type>::MapEntryAccessorType* \
MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::EnsureMutable( \
TypeOnMemory* value, Arena* arena) { \
return value->Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), \
arena); \
} \
template <typename Type> \
inline const typename MapTypeHandler<WireFormatLite::TYPE_##FieldType, \
Type>::MapEntryAccessorType& \
MapTypeHandler<WireFormatLite::TYPE_##FieldType, \
Type>::DefaultIfNotInitialized(const TypeOnMemory& value, \
const TypeOnMemory& \
/* default_value */) { \
return value.Get(); \
} \
template <typename Type> \
inline bool MapTypeHandler<WireFormatLite::TYPE_##FieldType, \
Type>::IsInitialized(const TypeOnMemory& /* value */) { \
return true; \
}
STRING_OR_BYTES_HANDLER_FUNCTIONS(STRING)
STRING_OR_BYTES_HANDLER_FUNCTIONS(BYTES)
#undef STRING_OR_BYTES_HANDLER_FUNCTIONS
#define PRIMITIVE_HANDLER_FUNCTIONS(FieldType) \
template <typename Type> \
inline const typename MapTypeHandler<WireFormatLite::TYPE_##FieldType, \
Type>::MapEntryAccessorType& \
MapTypeHandler<WireFormatLite::TYPE_##FieldType, \
Type>::GetExternalReference(const TypeOnMemory& value) { \
return value; \
} \
template <typename Type> \
inline size_t \
MapTypeHandler<WireFormatLite::TYPE_##FieldType, \
Type>::SpaceUsedInMapEntryLong(const TypeOnMemory& /* value */) { \
return 0; \
} \
template <typename Type> \
inline size_t \
MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::SpaceUsedInMapLong( \
const TypeOnMemory& /* value */) { \
return sizeof(Type); \
} \
template <typename Type> \
inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Clear( \
TypeOnMemory* value, Arena* /* arena */) { \
*value = 0; \
} \
template <typename Type> \
inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>:: \
ClearMaybeByDefaultEnum(TypeOnMemory* value, Arena* /* arena */, \
int default_enum_value) { \
*value = static_cast<TypeOnMemory>(default_enum_value); \
} \
template <typename Type> \
inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Merge( \
const MapEntryAccessorType& from, TypeOnMemory* to, \
Arena* /* arena */) { \
*to = from; \
} \
template <typename Type> \
inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, \
Type>::DeleteNoArena(TypeOnMemory& /* x */) {} \
template <typename Type> \
inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, \
Type>::AssignDefaultValue(TypeOnMemory* /* value */) {} \
template <typename Type> \
inline void \
MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Initialize( \
TypeOnMemory* value, Arena* /* arena */) { \
*value = 0; \
} \
template <typename Type> \
inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>:: \
InitializeMaybeByDefaultEnum(TypeOnMemory* value, \
int default_enum_value, \
Arena* /* arena */) { \
*value = static_cast<TypeOnMemory>(default_enum_value); \
} \
template <typename Type> \
inline typename MapTypeHandler<WireFormatLite::TYPE_##FieldType, \
Type>::MapEntryAccessorType* \
MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::EnsureMutable( \
TypeOnMemory* value, Arena* /* arena */) { \
return value; \
} \
template <typename Type> \
inline const typename MapTypeHandler<WireFormatLite::TYPE_##FieldType, \
Type>::MapEntryAccessorType& \
MapTypeHandler<WireFormatLite::TYPE_##FieldType, \
Type>::DefaultIfNotInitialized(const TypeOnMemory& value, \
const TypeOnMemory& \
/* default_value */) { \
return value; \
} \
template <typename Type> \
inline bool MapTypeHandler<WireFormatLite::TYPE_##FieldType, \
Type>::IsInitialized(const TypeOnMemory& /* value */) { \
return true; \
}
PRIMITIVE_HANDLER_FUNCTIONS(INT64)
PRIMITIVE_HANDLER_FUNCTIONS(UINT64)
PRIMITIVE_HANDLER_FUNCTIONS(INT32)
PRIMITIVE_HANDLER_FUNCTIONS(UINT32)
PRIMITIVE_HANDLER_FUNCTIONS(SINT64)
PRIMITIVE_HANDLER_FUNCTIONS(SINT32)
PRIMITIVE_HANDLER_FUNCTIONS(ENUM)
PRIMITIVE_HANDLER_FUNCTIONS(DOUBLE)
PRIMITIVE_HANDLER_FUNCTIONS(FLOAT)
PRIMITIVE_HANDLER_FUNCTIONS(FIXED64)
PRIMITIVE_HANDLER_FUNCTIONS(FIXED32)
PRIMITIVE_HANDLER_FUNCTIONS(SFIXED64)
PRIMITIVE_HANDLER_FUNCTIONS(SFIXED32)
PRIMITIVE_HANDLER_FUNCTIONS(BOOL)
#undef PRIMITIVE_HANDLER_FUNCTIONS
} // namespace internal
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_TYPE_HANDLER_H__

View File

@ -0,0 +1,424 @@
// 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.
// Authors: wink@google.com (Wink Saville),
// kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
//
// Defines MessageLite, the abstract interface implemented by all (lite
// and non-lite) protocol message objects.
#ifndef GOOGLE_PROTOBUF_MESSAGE_LITE_H__
#define GOOGLE_PROTOBUF_MESSAGE_LITE_H__
#include <climits>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/once.h>
#include <google/protobuf/arena.h>
#include <google/protobuf/stubs/port.h>
namespace google {
namespace protobuf {
template <typename T>
class RepeatedPtrField;
namespace io {
class CodedInputStream;
class CodedOutputStream;
class ZeroCopyInputStream;
class ZeroCopyOutputStream;
}
namespace internal {
class RepeatedPtrFieldBase;
class WireFormatLite;
class WeakFieldMap;
#ifndef SWIG
// We compute sizes as size_t but cache them as int. This function converts a
// computed size to a cached size. Since we don't proceed with serialization
// if the total size was > INT_MAX, it is not important what this function
// returns for inputs > INT_MAX. However this case should not error or
// GOOGLE_CHECK-fail, because the full size_t resolution is still returned from
// ByteSizeLong() and checked against INT_MAX; we can catch the overflow
// there.
inline int ToCachedSize(size_t size) { return static_cast<int>(size); }
// We mainly calculate sizes in terms of size_t, but some functions that
// compute sizes return "int". These int sizes are expected to always be
// positive. This function is more efficient than casting an int to size_t
// directly on 64-bit platforms because it avoids making the compiler emit a
// sign extending instruction, which we don't want and don't want to pay for.
inline size_t FromIntSize(int size) {
// Convert to unsigned before widening so sign extension is not necessary.
return static_cast<unsigned int>(size);
}
// For cases where a legacy function returns an integer size. We GOOGLE_DCHECK()
// that the conversion will fit within an integer; if this is false then we
// are losing information.
inline int ToIntSize(size_t size) {
GOOGLE_DCHECK_LE(size, static_cast<size_t>(INT_MAX));
return static_cast<int>(size);
}
// This type wraps a variable whose constructor and destructor are explicitly
// called. It is particularly useful for a global variable, without its
// constructor and destructor run on start and end of the program lifetime.
// This circumvents the initial construction order fiasco, while keeping
// the address of the empty string a compile time constant.
//
// Pay special attention to the initialization state of the object.
// 1. The object is "uninitialized" to begin with.
// 2. Call DefaultConstruct() only if the object is uninitialized.
// After the call, the object becomes "initialized".
// 3. Call get() and get_mutable() only if the object is initialized.
// 4. Call Destruct() only if the object is initialized.
// After the call, the object becomes uninitialized.
template <typename T>
class ExplicitlyConstructed {
public:
void DefaultConstruct() {
new (&union_) T();
}
void Destruct() {
get_mutable()->~T();
}
constexpr const T& get() const { return reinterpret_cast<const T&>(union_); }
T* get_mutable() { return reinterpret_cast<T*>(&union_); }
private:
// Prefer c++14 aligned_storage, but for compatibility this will do.
union AlignedUnion {
char space[sizeof(T)];
int64 align_to_int64;
void* align_to_ptr;
} union_;
};
// Default empty string object. Don't use this directly. Instead, call
// GetEmptyString() to get the reference.
LIBPROTOBUF_EXPORT extern ExplicitlyConstructed<::std::string> fixed_address_empty_string;
LIBPROTOBUF_EXPORT inline const ::std::string& GetEmptyStringAlreadyInited() {
return fixed_address_empty_string.get();
}
LIBPROTOBUF_EXPORT size_t StringSpaceUsedExcludingSelfLong(const string& str);
#endif // SWIG
} // namespace internal
// Interface to light weight protocol messages.
//
// This interface is implemented by all protocol message objects. Non-lite
// messages additionally implement the Message interface, which is a
// subclass of MessageLite. Use MessageLite instead when you only need
// the subset of features which it supports -- namely, nothing that uses
// descriptors or reflection. You can instruct the protocol compiler
// to generate classes which implement only MessageLite, not the full
// Message interface, by adding the following line to the .proto file:
//
// option optimize_for = LITE_RUNTIME;
//
// This is particularly useful on resource-constrained systems where
// the full protocol buffers runtime library is too big.
//
// Note that on non-constrained systems (e.g. servers) when you need
// to link in lots of protocol definitions, a better way to reduce
// total code footprint is to use optimize_for = CODE_SIZE. This
// will make the generated code smaller while still supporting all the
// same features (at the expense of speed). optimize_for = LITE_RUNTIME
// is best when you only have a small number of message types linked
// into your binary, in which case the size of the protocol buffers
// runtime itself is the biggest problem.
class LIBPROTOBUF_EXPORT MessageLite {
public:
inline MessageLite() {}
virtual ~MessageLite() {}
// Basic Operations ------------------------------------------------
// Get the name of this message type, e.g. "foo.bar.BazProto".
virtual string GetTypeName() const = 0;
// Construct a new instance of the same type. Ownership is passed to the
// caller.
virtual MessageLite* New() const = 0;
// Construct a new instance on the arena. Ownership is passed to the caller
// if arena is a NULL. Default implementation for backwards compatibility.
virtual MessageLite* New(::google::protobuf::Arena* arena) const;
// Get the arena, if any, associated with this message. Virtual method
// required for generic operations but most arena-related operations should
// use the GetArenaNoVirtual() generated-code method. Default implementation
// to reduce code size by avoiding the need for per-type implementations
// when types do not implement arena support.
virtual ::google::protobuf::Arena* GetArena() const { return NULL; }
// Get a pointer that may be equal to this message's arena, or may not be.
// If the value returned by this method is equal to some arena pointer, then
// this message is on that arena; however, if this message is on some arena,
// this method may or may not return that arena's pointer. As a tradeoff,
// this method may be more efficient than GetArena(). The intent is to allow
// underlying representations that use e.g. tagged pointers to sometimes
// store the arena pointer directly, and sometimes in a more indirect way,
// and allow a fastpath comparison against the arena pointer when it's easy
// to obtain.
virtual void* GetMaybeArenaPointer() const { return GetArena(); }
// Clear all fields of the message and set them to their default values.
// Clear() avoids freeing memory, assuming that any memory allocated
// to hold parts of the message will be needed again to hold the next
// message. If you actually want to free the memory used by a Message,
// you must delete it.
virtual void Clear() = 0;
// Quickly check if all required fields have values set.
virtual bool IsInitialized() const = 0;
// This is not implemented for Lite messages -- it just returns "(cannot
// determine missing fields for lite message)". However, it is implemented
// for full messages. See message.h.
virtual string InitializationErrorString() const;
// If |other| is the exact same class as this, calls MergeFrom(). Otherwise,
// results are undefined (probably crash).
virtual void CheckTypeAndMergeFrom(const MessageLite& other) = 0;
// Parsing ---------------------------------------------------------
// Methods for parsing in protocol buffer format. Most of these are
// just simple wrappers around MergeFromCodedStream(). Clear() will be
// called before merging the input.
// Fill the message with a protocol buffer parsed from the given input
// stream. Returns false on a read error or if the input is in the wrong
// format. A successful return does not indicate the entire input is
// consumed, ensure you call ConsumedEntireMessage() to check that if
// applicable.
bool ParseFromCodedStream(io::CodedInputStream* input);
// Like ParseFromCodedStream(), but accepts messages that are missing
// required fields.
bool ParsePartialFromCodedStream(io::CodedInputStream* input);
// Read a protocol buffer from the given zero-copy input stream. If
// successful, the entire input will be consumed.
bool ParseFromZeroCopyStream(io::ZeroCopyInputStream* input);
// Like ParseFromZeroCopyStream(), but accepts messages that are missing
// required fields.
bool ParsePartialFromZeroCopyStream(io::ZeroCopyInputStream* input);
// Read a protocol buffer from the given zero-copy input stream, expecting
// the message to be exactly "size" bytes long. If successful, exactly
// this many bytes will have been consumed from the input.
bool ParseFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input, int size);
// Like ParseFromBoundedZeroCopyStream(), but accepts messages that are
// missing required fields.
bool ParsePartialFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input,
int size);
// Parses a protocol buffer contained in a string. Returns true on success.
// This function takes a string in the (non-human-readable) binary wire
// format, matching the encoding output by MessageLite::SerializeToString().
// If you'd like to convert a human-readable string into a protocol buffer
// object, see google::protobuf::TextFormat::ParseFromString().
bool ParseFromString(const string& data);
// Like ParseFromString(), but accepts messages that are missing
// required fields.
bool ParsePartialFromString(const string& data);
// Parse a protocol buffer contained in an array of bytes.
bool ParseFromArray(const void* data, int size);
// Like ParseFromArray(), but accepts messages that are missing
// required fields.
bool ParsePartialFromArray(const void* data, int size);
// Reads a protocol buffer from the stream and merges it into this
// Message. Singular fields read from the what is
// already in the Message and repeated fields are appended to those
// already present.
//
// It is the responsibility of the caller to call input->LastTagWas()
// (for groups) or input->ConsumedEntireMessage() (for non-groups) after
// this returns to verify that the message's end was delimited correctly.
//
// ParsefromCodedStream() is implemented as Clear() followed by
// MergeFromCodedStream().
bool MergeFromCodedStream(io::CodedInputStream* input);
// Like MergeFromCodedStream(), but succeeds even if required fields are
// missing in the input.
//
// MergeFromCodedStream() is just implemented as MergePartialFromCodedStream()
// followed by IsInitialized().
virtual bool MergePartialFromCodedStream(io::CodedInputStream* input) = 0;
// Serialization ---------------------------------------------------
// Methods for serializing in protocol buffer format. Most of these
// are just simple wrappers around ByteSize() and SerializeWithCachedSizes().
// Write a protocol buffer of this message to the given output. Returns
// false on a write error. If the message is missing required fields,
// this may GOOGLE_CHECK-fail.
bool SerializeToCodedStream(io::CodedOutputStream* output) const;
// Like SerializeToCodedStream(), but allows missing required fields.
bool SerializePartialToCodedStream(io::CodedOutputStream* output) const;
// Write the message to the given zero-copy output stream. All required
// fields must be set.
bool SerializeToZeroCopyStream(io::ZeroCopyOutputStream* output) const;
// Like SerializeToZeroCopyStream(), but allows missing required fields.
bool SerializePartialToZeroCopyStream(io::ZeroCopyOutputStream* output) const;
// Serialize the message and store it in the given string. All required
// fields must be set.
bool SerializeToString(string* output) const;
// Like SerializeToString(), but allows missing required fields.
bool SerializePartialToString(string* output) const;
// Serialize the message and store it in the given byte array. All required
// fields must be set.
bool SerializeToArray(void* data, int size) const;
// Like SerializeToArray(), but allows missing required fields.
bool SerializePartialToArray(void* data, int size) const;
// Make a string encoding the message. Is equivalent to calling
// SerializeToString() on a string and using that. Returns the empty
// string if SerializeToString() would have returned an error.
// Note: If you intend to generate many such strings, you may
// reduce heap fragmentation by instead re-using the same string
// object with calls to SerializeToString().
string SerializeAsString() const;
// Like SerializeAsString(), but allows missing required fields.
string SerializePartialAsString() const;
// Like SerializeToString(), but appends to the data to the string's existing
// contents. All required fields must be set.
bool AppendToString(string* output) const;
// Like AppendToString(), but allows missing required fields.
bool AppendPartialToString(string* output) const;
// Computes the serialized size of the message. This recursively calls
// ByteSizeLong() on all embedded messages.
//
// ByteSizeLong() is generally linear in the number of fields defined for the
// proto.
virtual size_t ByteSizeLong() const = 0;
// Legacy ByteSize() API.
PROTOBUF_RUNTIME_DEPRECATED("Please use ByteSizeLong() instead")
int ByteSize() const {
return internal::ToIntSize(ByteSizeLong());
}
// Serializes the message without recomputing the size. The message must not
// have changed since the last call to ByteSize(), and the value returned by
// ByteSize must be non-negative. Otherwise the results are undefined.
virtual void SerializeWithCachedSizes(
io::CodedOutputStream* output) const;
// Functions below here are not part of the public interface. It isn't
// enforced, but they should be treated as private, and will be private
// at some future time. Unfortunately the implementation of the "friend"
// keyword in GCC is broken at the moment, but we expect it will be fixed.
// Like SerializeWithCachedSizes, but writes directly to *target, returning
// a pointer to the byte immediately after the last byte written. "target"
// must point at a byte array of at least ByteSize() bytes. Whether to use
// deterministic serialization, e.g., maps in sorted order, is determined by
// CodedOutputStream::IsDefaultSerializationDeterministic().
virtual uint8* SerializeWithCachedSizesToArray(uint8* target) const;
// Returns the result of the last call to ByteSize(). An embedded message's
// size is needed both to serialize it (because embedded messages are
// length-delimited) and to compute the outer message's size. Caching
// the size avoids computing it multiple times.
//
// ByteSize() does not automatically use the cached size when available
// because this would require invalidating it every time the message was
// modified, which would be too hard and expensive. (E.g. if a deeply-nested
// sub-message is changed, all of its parents' cached sizes would need to be
// invalidated, which is too much work for an otherwise inlined setter
// method.)
virtual int GetCachedSize() const = 0;
virtual uint8* InternalSerializeWithCachedSizesToArray(bool deterministic,
uint8* target) const;
protected:
// CastToBase allows generated code to cast a RepeatedPtrField<T> to
// RepeatedPtrFieldBase. We try to restrict access to RepeatedPtrFieldBase
// because it is an implementation detail that user code should not access
// directly.
template <typename T>
static ::google::protobuf::internal::RepeatedPtrFieldBase* CastToBase(
::google::protobuf::RepeatedPtrField<T>* repeated) {
return repeated;
}
template <typename T>
static const ::google::protobuf::internal::RepeatedPtrFieldBase& CastToBase(
const ::google::protobuf::RepeatedPtrField<T>& repeated) {
return repeated;
}
template <typename T>
static T* CreateMaybeMessage(Arena* arena) {
return Arena::CreateMaybeMessage<T>(arena);
}
private:
// TODO(gerbens) make this a pure abstract function
virtual const void* InternalGetTable() const { return NULL; }
friend class internal::WireFormatLite;
friend class Message;
friend class internal::WeakFieldMap;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageLite);
};
namespace internal {
extern bool LIBPROTOBUF_EXPORT proto3_preserve_unknown_;
// DO NOT USE: For migration only. Will be removed when Proto3 defaults to
// preserve unknowns.
inline bool GetProto3PreserveUnknownsDefault() {
return proto3_preserve_unknown_;
}
// DO NOT USE: For migration only. Will be removed when Proto3 defaults to
// preserve unknowns.
void LIBPROTOBUF_EXPORT SetProto3PreserveUnknownsDefault(bool preserve);
} // namespace internal
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_MESSAGE_LITE_H__

View File

@ -0,0 +1,224 @@
// 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_METADATA_LITE_H__
#define GOOGLE_PROTOBUF_METADATA_LITE_H__
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/arena.h>
#include <google/protobuf/message_lite.h>
#include <google/protobuf/stubs/port.h>
namespace google {
namespace protobuf {
namespace internal {
// This is the representation for messages that support arena allocation. It
// uses a tagged pointer to either store the Arena pointer, if there are no
// unknown fields, or a pointer to a block of memory with both the Arena pointer
// and the UnknownFieldSet, if there are unknown fields. This optimization
// allows for "zero-overhead" storage of the Arena pointer, relative to the
// above baseline implementation.
//
// The tagged pointer uses the LSB to disambiguate cases, and uses bit 0 == 0 to
// indicate an arena pointer and bit 0 == 1 to indicate a UFS+Arena-container
// pointer.
template <class T, class Derived>
class InternalMetadataWithArenaBase {
public:
InternalMetadataWithArenaBase() : ptr_(NULL) {}
explicit InternalMetadataWithArenaBase(Arena* arena) : ptr_(arena) {}
~InternalMetadataWithArenaBase() {
if (have_unknown_fields() && arena() == NULL) {
delete PtrValue<Container>();
}
ptr_ = NULL;
}
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE const T& unknown_fields() const {
if (GOOGLE_PREDICT_FALSE(have_unknown_fields())) {
return PtrValue<Container>()->unknown_fields;
} else {
return Derived::default_instance();
}
}
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE T* mutable_unknown_fields() {
if (GOOGLE_PREDICT_TRUE(have_unknown_fields())) {
return &PtrValue<Container>()->unknown_fields;
} else {
return mutable_unknown_fields_slow();
}
}
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE Arena* arena() const {
if (GOOGLE_PREDICT_FALSE(have_unknown_fields())) {
return PtrValue<Container>()->arena;
} else {
return PtrValue<Arena>();
}
}
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE bool have_unknown_fields() const {
return PtrTag() == kTagContainer;
}
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE void Swap(Derived* other) {
// Semantics here are that we swap only the unknown fields, not the arena
// pointer. We cannot simply swap ptr_ with other->ptr_ because we need to
// maintain our own arena ptr. Also, our ptr_ and other's ptr_ may be in
// different states (direct arena pointer vs. container with UFS) so we
// cannot simply swap ptr_ and then restore the arena pointers. We reuse
// UFS's swap implementation instead.
if (have_unknown_fields() || other->have_unknown_fields()) {
static_cast<Derived*>(this)->DoSwap(other->mutable_unknown_fields());
}
}
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE void MergeFrom(const Derived& other) {
if (other.have_unknown_fields()) {
static_cast<Derived*>(this)->DoMergeFrom(other.unknown_fields());
}
}
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE void Clear() {
if (have_unknown_fields()) {
static_cast<Derived*>(this)->DoClear();
}
}
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE void* raw_arena_ptr() const {
return ptr_;
}
private:
void* ptr_;
// Tagged pointer implementation.
enum {
// ptr_ is an Arena*.
kTagArena = 0,
// ptr_ is a Container*.
kTagContainer = 1,
};
static const intptr_t kPtrTagMask = 1;
static const intptr_t kPtrValueMask = ~kPtrTagMask;
// Accessors for pointer tag and pointer value.
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE int PtrTag() const {
return reinterpret_cast<intptr_t>(ptr_) & kPtrTagMask;
}
template<typename U> U* PtrValue() const {
return reinterpret_cast<U*>(
reinterpret_cast<intptr_t>(ptr_) & kPtrValueMask);
}
// If ptr_'s tag is kTagContainer, it points to an instance of this struct.
struct Container {
T unknown_fields;
Arena* arena;
};
GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE T* mutable_unknown_fields_slow() {
Arena* my_arena = arena();
Container* container = Arena::Create<Container>(my_arena);
// Two-step assignment works around a bug in clang's static analyzer:
// https://bugs.llvm.org/show_bug.cgi?id=34198.
ptr_ = container;
ptr_ = reinterpret_cast<void*>(
reinterpret_cast<intptr_t>(ptr_) | kTagContainer);
container->arena = my_arena;
return &(container->unknown_fields);
}
};
// We store unknown fields as a string right now, because there is currently no
// good interface for reading unknown fields into an ArenaString. We may want
// to revisit this to allow unknown fields to be parsed onto the Arena.
class InternalMetadataWithArenaLite
: public InternalMetadataWithArenaBase<string,
InternalMetadataWithArenaLite> {
public:
InternalMetadataWithArenaLite() {}
explicit InternalMetadataWithArenaLite(Arena* arena)
: InternalMetadataWithArenaBase<string,
InternalMetadataWithArenaLite>(arena) {}
void DoSwap(string* other) {
mutable_unknown_fields()->swap(*other);
}
void DoMergeFrom(const string& other) {
mutable_unknown_fields()->append(other);
}
void DoClear() {
mutable_unknown_fields()->clear();
}
static const string& default_instance() {
return GetEmptyStringAlreadyInited();
}
};
// This helper RAII class is needed to efficiently parse unknown fields. We
// should only call mutable_unknown_fields if there are actual unknown fields.
// The obvious thing to just use a stack string and swap it at the end of the
// parse won't work, because the destructor of StringOutputStream needs to be
// called before we can modify the string (it check-fails). Using
// LiteUnknownFieldSetter setter(&_internal_metadata_);
// StringOutputStream stream(setter.buffer());
// guarantees that the string is only swapped after stream is destroyed.
class LIBPROTOBUF_EXPORT LiteUnknownFieldSetter {
public:
explicit LiteUnknownFieldSetter(InternalMetadataWithArenaLite* metadata)
: metadata_(metadata) {
if (metadata->have_unknown_fields()) {
buffer_.swap(*metadata->mutable_unknown_fields());
}
}
~LiteUnknownFieldSetter() {
if (!buffer_.empty()) metadata_->mutable_unknown_fields()->swap(buffer_);
}
string* buffer() { return &buffer_; }
private:
InternalMetadataWithArenaLite* metadata_;
string buffer_;
};
} // namespace internal
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_METADATA_LITE_H__

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,348 @@
// 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 declares the ByteSink and ByteSource abstract interfaces. These
// interfaces represent objects that consume (ByteSink) or produce (ByteSource)
// a sequence of bytes. Using these abstract interfaces in your APIs can help
// make your code work with a variety of input and output types.
//
// This file also declares the following commonly used implementations of these
// interfaces.
//
// ByteSink:
// UncheckedArrayByteSink Writes to an array, without bounds checking
// CheckedArrayByteSink Writes to an array, with bounds checking
// GrowingArrayByteSink Allocates and writes to a growable buffer
// StringByteSink Writes to an STL string
// NullByteSink Consumes a never-ending stream of bytes
//
// ByteSource:
// ArrayByteSource Reads from an array or string/StringPiece
// LimitedByteSource Limits the number of bytes read from an
#ifndef GOOGLE_PROTOBUF_STUBS_BYTESTREAM_H_
#define GOOGLE_PROTOBUF_STUBS_BYTESTREAM_H_
#include <stddef.h>
#include <string>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/stringpiece.h>
class CordByteSink;
class MemBlock;
namespace google {
namespace protobuf {
namespace strings {
// An abstract interface for an object that consumes a sequence of bytes. This
// interface offers a way to append data as well as a Flush() function.
//
// Example:
//
// string my_data;
// ...
// ByteSink* sink = ...
// sink->Append(my_data.data(), my_data.size());
// sink->Flush();
//
class LIBPROTOBUF_EXPORT ByteSink {
public:
ByteSink() {}
virtual ~ByteSink() {}
// Appends the "n" bytes starting at "bytes".
virtual void Append(const char* bytes, size_t n) = 0;
// Flushes internal buffers. The default implemenation does nothing. ByteSink
// subclasses may use internal buffers that require calling Flush() at the end
// of the stream.
virtual void Flush();
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ByteSink);
};
// An abstract interface for an object that produces a fixed-size sequence of
// bytes.
//
// Example:
//
// ByteSource* source = ...
// while (source->Available() > 0) {
// StringPiece data = source->Peek();
// ... do something with "data" ...
// source->Skip(data.length());
// }
//
class LIBPROTOBUF_EXPORT ByteSource {
public:
ByteSource() {}
virtual ~ByteSource() {}
// Returns the number of bytes left to read from the source. Available()
// should decrease by N each time Skip(N) is called. Available() may not
// increase. Available() returning 0 indicates that the ByteSource is
// exhausted.
//
// Note: Size() may have been a more appropriate name as it's more
// indicative of the fixed-size nature of a ByteSource.
virtual size_t Available() const = 0;
// Returns a StringPiece of the next contiguous region of the source. Does not
// reposition the source. The returned region is empty iff Available() == 0.
//
// The returned region is valid until the next call to Skip() or until this
// object is destroyed, whichever occurs first.
//
// The length of the returned StringPiece will be <= Available().
virtual StringPiece Peek() = 0;
// Skips the next n bytes. Invalidates any StringPiece returned by a previous
// call to Peek().
//
// REQUIRES: Available() >= n
virtual void Skip(size_t n) = 0;
// Writes the next n bytes in this ByteSource to the given ByteSink, and
// advances this ByteSource past the copied bytes. The default implementation
// of this method just copies the bytes normally, but subclasses might
// override CopyTo to optimize certain cases.
//
// REQUIRES: Available() >= n
virtual void CopyTo(ByteSink* sink, size_t n);
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ByteSource);
};
//
// Some commonly used implementations of ByteSink
//
// Implementation of ByteSink that writes to an unsized byte array. No
// bounds-checking is performed--it is the caller's responsibility to ensure
// that the destination array is large enough.
//
// Example:
//
// char buf[10];
// UncheckedArrayByteSink sink(buf);
// sink.Append("hi", 2); // OK
// sink.Append(data, 100); // WOOPS! Overflows buf[10].
//
class LIBPROTOBUF_EXPORT UncheckedArrayByteSink : public ByteSink {
public:
explicit UncheckedArrayByteSink(char* dest) : dest_(dest) {}
virtual void Append(const char* data, size_t n);
// Returns the current output pointer so that a caller can see how many bytes
// were produced.
//
// Note: this method is not part of the ByteSink interface.
char* CurrentDestination() const { return dest_; }
private:
char* dest_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(UncheckedArrayByteSink);
};
// Implementation of ByteSink that writes to a sized byte array. This sink will
// not write more than "capacity" bytes to outbuf. Once "capacity" bytes are
// appended, subsequent bytes will be ignored and Overflowed() will return true.
// Overflowed() does not cause a runtime error (i.e., it does not CHECK fail).
//
// Example:
//
// char buf[10];
// CheckedArrayByteSink sink(buf, 10);
// sink.Append("hi", 2); // OK
// sink.Append(data, 100); // Will only write 8 more bytes
//
class LIBPROTOBUF_EXPORT CheckedArrayByteSink : public ByteSink {
public:
CheckedArrayByteSink(char* outbuf, size_t capacity);
virtual void Append(const char* bytes, size_t n);
// Returns the number of bytes actually written to the sink.
size_t NumberOfBytesWritten() const { return size_; }
// Returns true if any bytes were discarded, i.e., if there was an
// attempt to write more than 'capacity' bytes.
bool Overflowed() const { return overflowed_; }
private:
char* outbuf_;
const size_t capacity_;
size_t size_;
bool overflowed_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CheckedArrayByteSink);
};
// Implementation of ByteSink that allocates an internal buffer (a char array)
// and expands it as needed to accommodate appended data (similar to a string),
// and allows the caller to take ownership of the internal buffer via the
// GetBuffer() method. The buffer returned from GetBuffer() must be deleted by
// the caller with delete[]. GetBuffer() also sets the internal buffer to be
// empty, and subsequent appends to the sink will create a new buffer. The
// destructor will free the internal buffer if GetBuffer() was not called.
//
// Example:
//
// GrowingArrayByteSink sink(10);
// sink.Append("hi", 2);
// sink.Append(data, n);
// const char* buf = sink.GetBuffer(); // Ownership transferred
// delete[] buf;
//
class LIBPROTOBUF_EXPORT GrowingArrayByteSink : public strings::ByteSink {
public:
explicit GrowingArrayByteSink(size_t estimated_size);
virtual ~GrowingArrayByteSink();
virtual void Append(const char* bytes, size_t n);
// Returns the allocated buffer, and sets nbytes to its size. The caller takes
// ownership of the buffer and must delete it with delete[].
char* GetBuffer(size_t* nbytes);
private:
void Expand(size_t amount);
void ShrinkToFit();
size_t capacity_;
char* buf_;
size_t size_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GrowingArrayByteSink);
};
// Implementation of ByteSink that appends to the given string.
// Existing contents of "dest" are not modified; new data is appended.
//
// Example:
//
// string dest = "Hello ";
// StringByteSink sink(&dest);
// sink.Append("World", 5);
// assert(dest == "Hello World");
//
class LIBPROTOBUF_EXPORT StringByteSink : public ByteSink {
public:
explicit StringByteSink(string* dest) : dest_(dest) {}
virtual void Append(const char* data, size_t n);
private:
string* dest_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringByteSink);
};
// Implementation of ByteSink that discards all data.
//
// Example:
//
// NullByteSink sink;
// sink.Append(data, data.size()); // All data ignored.
//
class LIBPROTOBUF_EXPORT NullByteSink : public ByteSink {
public:
NullByteSink() {}
virtual void Append(const char *data, size_t n) {}
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(NullByteSink);
};
//
// Some commonly used implementations of ByteSource
//
// Implementation of ByteSource that reads from a StringPiece.
//
// Example:
//
// string data = "Hello";
// ArrayByteSource source(data);
// assert(source.Available() == 5);
// assert(source.Peek() == "Hello");
//
class LIBPROTOBUF_EXPORT ArrayByteSource : public ByteSource {
public:
explicit ArrayByteSource(StringPiece s) : input_(s) {}
virtual size_t Available() const;
virtual StringPiece Peek();
virtual void Skip(size_t n);
private:
StringPiece input_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ArrayByteSource);
};
// Implementation of ByteSource that wraps another ByteSource, limiting the
// number of bytes returned.
//
// The caller maintains ownership of the underlying source, and may not use the
// underlying source while using the LimitByteSource object. The underlying
// source's pointer is advanced by n bytes every time this LimitByteSource
// object is advanced by n.
//
// Example:
//
// string data = "Hello World";
// ArrayByteSource abs(data);
// assert(abs.Available() == data.size());
//
// LimitByteSource limit(abs, 5);
// assert(limit.Available() == 5);
// assert(limit.Peek() == "Hello");
//
class LIBPROTOBUF_EXPORT LimitByteSource : public ByteSource {
public:
// Returns at most "limit" bytes from "source".
LimitByteSource(ByteSource* source, size_t limit);
virtual size_t Available() const;
virtual StringPiece Peek();
virtual void Skip(size_t n);
// We override CopyTo so that we can forward to the underlying source, in
// case it has an efficient implementation of CopyTo.
virtual void CopyTo(ByteSink* sink, size_t n);
private:
ByteSource* source_;
size_t limit_;
};
} // namespace strings
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_STUBS_BYTESTREAM_H_

View File

@ -0,0 +1,577 @@
#ifndef GOOGLE_PROTOBUF_STUBS_CALLBACK_H_
#define GOOGLE_PROTOBUF_STUBS_CALLBACK_H_
#include <type_traits>
#include <google/protobuf/stubs/macros.h>
// ===================================================================
// emulates google3/base/callback.h
namespace google {
namespace protobuf {
// Abstract interface for a callback. When calling an RPC, you must provide
// a Closure to call when the procedure completes. See the Service interface
// in service.h.
//
// To automatically construct a Closure which calls a particular function or
// method with a particular set of parameters, use the NewCallback() function.
// Example:
// void FooDone(const FooResponse* response) {
// ...
// }
//
// void CallFoo() {
// ...
// // When done, call FooDone() and pass it a pointer to the response.
// Closure* callback = NewCallback(&FooDone, response);
// // Make the call.
// service->Foo(controller, request, response, callback);
// }
//
// Example that calls a method:
// class Handler {
// public:
// ...
//
// void FooDone(const FooResponse* response) {
// ...
// }
//
// void CallFoo() {
// ...
// // When done, call FooDone() and pass it a pointer to the response.
// Closure* callback = NewCallback(this, &Handler::FooDone, response);
// // Make the call.
// service->Foo(controller, request, response, callback);
// }
// };
//
// Currently NewCallback() supports binding zero, one, or two arguments.
//
// Callbacks created with NewCallback() automatically delete themselves when
// executed. They should be used when a callback is to be called exactly
// once (usually the case with RPC callbacks). If a callback may be called
// a different number of times (including zero), create it with
// NewPermanentCallback() instead. You are then responsible for deleting the
// callback (using the "delete" keyword as normal).
//
// Note that NewCallback() is a bit touchy regarding argument types. Generally,
// the values you provide for the parameter bindings must exactly match the
// types accepted by the callback function. For example:
// void Foo(string s);
// NewCallback(&Foo, "foo"); // WON'T WORK: const char* != string
// NewCallback(&Foo, string("foo")); // WORKS
// Also note that the arguments cannot be references:
// void Foo(const string& s);
// string my_str;
// NewCallback(&Foo, my_str); // WON'T WORK: Can't use referecnes.
// However, correctly-typed pointers will work just fine.
class LIBPROTOBUF_EXPORT Closure {
public:
Closure() {}
virtual ~Closure();
virtual void Run() = 0;
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Closure);
};
template<typename R>
class ResultCallback {
public:
ResultCallback() {}
virtual ~ResultCallback() {}
virtual R Run() = 0;
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ResultCallback);
};
template<typename R, typename A1>
class LIBPROTOBUF_EXPORT ResultCallback1 {
public:
ResultCallback1() {}
virtual ~ResultCallback1() {}
virtual R Run(A1) = 0;
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ResultCallback1);
};
template<typename R, typename A1, typename A2>
class LIBPROTOBUF_EXPORT ResultCallback2 {
public:
ResultCallback2() {}
virtual ~ResultCallback2() {}
virtual R Run(A1,A2) = 0;
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ResultCallback2);
};
namespace internal {
class LIBPROTOBUF_EXPORT FunctionClosure0 : public Closure {
public:
typedef void (*FunctionType)();
FunctionClosure0(FunctionType function, bool self_deleting)
: function_(function), self_deleting_(self_deleting) {}
~FunctionClosure0();
void Run() {
bool needs_delete = self_deleting_; // read in case callback deletes
function_();
if (needs_delete) delete this;
}
private:
FunctionType function_;
bool self_deleting_;
};
template <typename Class>
class MethodClosure0 : public Closure {
public:
typedef void (Class::*MethodType)();
MethodClosure0(Class* object, MethodType method, bool self_deleting)
: object_(object), method_(method), self_deleting_(self_deleting) {}
~MethodClosure0() {}
void Run() {
bool needs_delete = self_deleting_; // read in case callback deletes
(object_->*method_)();
if (needs_delete) delete this;
}
private:
Class* object_;
MethodType method_;
bool self_deleting_;
};
template <typename Arg1>
class FunctionClosure1 : public Closure {
public:
typedef void (*FunctionType)(Arg1 arg1);
FunctionClosure1(FunctionType function, bool self_deleting,
Arg1 arg1)
: function_(function), self_deleting_(self_deleting),
arg1_(arg1) {}
~FunctionClosure1() {}
void Run() {
bool needs_delete = self_deleting_; // read in case callback deletes
function_(arg1_);
if (needs_delete) delete this;
}
private:
FunctionType function_;
bool self_deleting_;
Arg1 arg1_;
};
template <typename Class, typename Arg1>
class MethodClosure1 : public Closure {
public:
typedef void (Class::*MethodType)(Arg1 arg1);
MethodClosure1(Class* object, MethodType method, bool self_deleting,
Arg1 arg1)
: object_(object), method_(method), self_deleting_(self_deleting),
arg1_(arg1) {}
~MethodClosure1() {}
void Run() {
bool needs_delete = self_deleting_; // read in case callback deletes
(object_->*method_)(arg1_);
if (needs_delete) delete this;
}
private:
Class* object_;
MethodType method_;
bool self_deleting_;
Arg1 arg1_;
};
template <typename Arg1, typename Arg2>
class FunctionClosure2 : public Closure {
public:
typedef void (*FunctionType)(Arg1 arg1, Arg2 arg2);
FunctionClosure2(FunctionType function, bool self_deleting,
Arg1 arg1, Arg2 arg2)
: function_(function), self_deleting_(self_deleting),
arg1_(arg1), arg2_(arg2) {}
~FunctionClosure2() {}
void Run() {
bool needs_delete = self_deleting_; // read in case callback deletes
function_(arg1_, arg2_);
if (needs_delete) delete this;
}
private:
FunctionType function_;
bool self_deleting_;
Arg1 arg1_;
Arg2 arg2_;
};
template <typename Class, typename Arg1, typename Arg2>
class MethodClosure2 : public Closure {
public:
typedef void (Class::*MethodType)(Arg1 arg1, Arg2 arg2);
MethodClosure2(Class* object, MethodType method, bool self_deleting,
Arg1 arg1, Arg2 arg2)
: object_(object), method_(method), self_deleting_(self_deleting),
arg1_(arg1), arg2_(arg2) {}
~MethodClosure2() {}
void Run() {
bool needs_delete = self_deleting_; // read in case callback deletes
(object_->*method_)(arg1_, arg2_);
if (needs_delete) delete this;
}
private:
Class* object_;
MethodType method_;
bool self_deleting_;
Arg1 arg1_;
Arg2 arg2_;
};
template<typename R>
class FunctionResultCallback_0_0 : public ResultCallback<R> {
public:
typedef R (*FunctionType)();
FunctionResultCallback_0_0(FunctionType function, bool self_deleting)
: function_(function), self_deleting_(self_deleting) {}
~FunctionResultCallback_0_0() {}
R Run() {
bool needs_delete = self_deleting_; // read in case callback deletes
R result = function_();
if (needs_delete) delete this;
return result;
}
private:
FunctionType function_;
bool self_deleting_;
};
template<typename R, typename P1>
class FunctionResultCallback_1_0 : public ResultCallback<R> {
public:
typedef R (*FunctionType)(P1);
FunctionResultCallback_1_0(FunctionType function, bool self_deleting,
P1 p1)
: function_(function), self_deleting_(self_deleting), p1_(p1) {}
~FunctionResultCallback_1_0() {}
R Run() {
bool needs_delete = self_deleting_; // read in case callback deletes
R result = function_(p1_);
if (needs_delete) delete this;
return result;
}
private:
FunctionType function_;
bool self_deleting_;
P1 p1_;
};
template<typename R, typename Arg1>
class FunctionResultCallback_0_1 : public ResultCallback1<R, Arg1> {
public:
typedef R (*FunctionType)(Arg1 arg1);
FunctionResultCallback_0_1(FunctionType function, bool self_deleting)
: function_(function), self_deleting_(self_deleting) {}
~FunctionResultCallback_0_1() {}
R Run(Arg1 a1) {
bool needs_delete = self_deleting_; // read in case callback deletes
R result = function_(a1);
if (needs_delete) delete this;
return result;
}
private:
FunctionType function_;
bool self_deleting_;
};
template<typename R, typename P1, typename A1>
class FunctionResultCallback_1_1 : public ResultCallback1<R, A1> {
public:
typedef R (*FunctionType)(P1, A1);
FunctionResultCallback_1_1(FunctionType function, bool self_deleting,
P1 p1)
: function_(function), self_deleting_(self_deleting), p1_(p1) {}
~FunctionResultCallback_1_1() {}
R Run(A1 a1) {
bool needs_delete = self_deleting_; // read in case callback deletes
R result = function_(p1_, a1);
if (needs_delete) delete this;
return result;
}
private:
FunctionType function_;
bool self_deleting_;
P1 p1_;
};
template <typename T>
struct InternalConstRef {
typedef typename std::remove_reference<T>::type base_type;
typedef const base_type& type;
};
template<typename R, typename T>
class MethodResultCallback_0_0 : public ResultCallback<R> {
public:
typedef R (T::*MethodType)();
MethodResultCallback_0_0(T* object, MethodType method, bool self_deleting)
: object_(object),
method_(method),
self_deleting_(self_deleting) {}
~MethodResultCallback_0_0() {}
R Run() {
bool needs_delete = self_deleting_;
R result = (object_->*method_)();
if (needs_delete) delete this;
return result;
}
private:
T* object_;
MethodType method_;
bool self_deleting_;
};
template <typename R, typename T, typename P1, typename P2, typename P3,
typename P4, typename P5, typename A1, typename A2>
class MethodResultCallback_5_2 : public ResultCallback2<R, A1, A2> {
public:
typedef R (T::*MethodType)(P1, P2, P3, P4, P5, A1, A2);
MethodResultCallback_5_2(T* object, MethodType method, bool self_deleting,
P1 p1, P2 p2, P3 p3, P4 p4, P5 p5)
: object_(object),
method_(method),
self_deleting_(self_deleting),
p1_(p1),
p2_(p2),
p3_(p3),
p4_(p4),
p5_(p5) {}
~MethodResultCallback_5_2() {}
R Run(A1 a1, A2 a2) {
bool needs_delete = self_deleting_;
R result = (object_->*method_)(p1_, p2_, p3_, p4_, p5_, a1, a2);
if (needs_delete) delete this;
return result;
}
private:
T* object_;
MethodType method_;
bool self_deleting_;
typename std::remove_reference<P1>::type p1_;
typename std::remove_reference<P2>::type p2_;
typename std::remove_reference<P3>::type p3_;
typename std::remove_reference<P4>::type p4_;
typename std::remove_reference<P5>::type p5_;
};
} // namespace internal
// See Closure.
inline Closure* NewCallback(void (*function)()) {
return new internal::FunctionClosure0(function, true);
}
// See Closure.
inline Closure* NewPermanentCallback(void (*function)()) {
return new internal::FunctionClosure0(function, false);
}
// See Closure.
template <typename Class>
inline Closure* NewCallback(Class* object, void (Class::*method)()) {
return new internal::MethodClosure0<Class>(object, method, true);
}
// See Closure.
template <typename Class>
inline Closure* NewPermanentCallback(Class* object, void (Class::*method)()) {
return new internal::MethodClosure0<Class>(object, method, false);
}
// See Closure.
template <typename Arg1>
inline Closure* NewCallback(void (*function)(Arg1),
Arg1 arg1) {
return new internal::FunctionClosure1<Arg1>(function, true, arg1);
}
// See Closure.
template <typename Arg1>
inline Closure* NewPermanentCallback(void (*function)(Arg1),
Arg1 arg1) {
return new internal::FunctionClosure1<Arg1>(function, false, arg1);
}
// See Closure.
template <typename Class, typename Arg1>
inline Closure* NewCallback(Class* object, void (Class::*method)(Arg1),
Arg1 arg1) {
return new internal::MethodClosure1<Class, Arg1>(object, method, true, arg1);
}
// See Closure.
template <typename Class, typename Arg1>
inline Closure* NewPermanentCallback(Class* object, void (Class::*method)(Arg1),
Arg1 arg1) {
return new internal::MethodClosure1<Class, Arg1>(object, method, false, arg1);
}
// See Closure.
template <typename Arg1, typename Arg2>
inline Closure* NewCallback(void (*function)(Arg1, Arg2),
Arg1 arg1, Arg2 arg2) {
return new internal::FunctionClosure2<Arg1, Arg2>(
function, true, arg1, arg2);
}
// See Closure.
template <typename Arg1, typename Arg2>
inline Closure* NewPermanentCallback(void (*function)(Arg1, Arg2),
Arg1 arg1, Arg2 arg2) {
return new internal::FunctionClosure2<Arg1, Arg2>(
function, false, arg1, arg2);
}
// See Closure.
template <typename Class, typename Arg1, typename Arg2>
inline Closure* NewCallback(Class* object, void (Class::*method)(Arg1, Arg2),
Arg1 arg1, Arg2 arg2) {
return new internal::MethodClosure2<Class, Arg1, Arg2>(
object, method, true, arg1, arg2);
}
// See Closure.
template <typename Class, typename Arg1, typename Arg2>
inline Closure* NewPermanentCallback(
Class* object, void (Class::*method)(Arg1, Arg2),
Arg1 arg1, Arg2 arg2) {
return new internal::MethodClosure2<Class, Arg1, Arg2>(
object, method, false, arg1, arg2);
}
// See ResultCallback
template<typename R>
inline ResultCallback<R>* NewCallback(R (*function)()) {
return new internal::FunctionResultCallback_0_0<R>(function, true);
}
// See ResultCallback
template<typename R>
inline ResultCallback<R>* NewPermanentCallback(R (*function)()) {
return new internal::FunctionResultCallback_0_0<R>(function, false);
}
// See ResultCallback
template<typename R, typename P1>
inline ResultCallback<R>* NewCallback(R (*function)(P1), P1 p1) {
return new internal::FunctionResultCallback_1_0<R, P1>(
function, true, p1);
}
// See ResultCallback
template<typename R, typename P1>
inline ResultCallback<R>* NewPermanentCallback(
R (*function)(P1), P1 p1) {
return new internal::FunctionResultCallback_1_0<R, P1>(
function, false, p1);
}
// See ResultCallback1
template<typename R, typename A1>
inline ResultCallback1<R, A1>* NewCallback(R (*function)(A1)) {
return new internal::FunctionResultCallback_0_1<R, A1>(function, true);
}
// See ResultCallback1
template<typename R, typename A1>
inline ResultCallback1<R, A1>* NewPermanentCallback(R (*function)(A1)) {
return new internal::FunctionResultCallback_0_1<R, A1>(function, false);
}
// See ResultCallback1
template<typename R, typename P1, typename A1>
inline ResultCallback1<R, A1>* NewCallback(R (*function)(P1, A1), P1 p1) {
return new internal::FunctionResultCallback_1_1<R, P1, A1>(
function, true, p1);
}
// See ResultCallback1
template<typename R, typename P1, typename A1>
inline ResultCallback1<R, A1>* NewPermanentCallback(
R (*function)(P1, A1), P1 p1) {
return new internal::FunctionResultCallback_1_1<R, P1, A1>(
function, false, p1);
}
// See MethodResultCallback_0_0
template <typename R, typename T1, typename T2>
inline ResultCallback<R>* NewPermanentCallback(
T1* object, R (T2::*function)()) {
return new internal::MethodResultCallback_0_0<R, T1>(object, function, false);
}
// See MethodResultCallback_5_2
template <typename R, typename T, typename P1, typename P2, typename P3,
typename P4, typename P5, typename A1, typename A2>
inline ResultCallback2<R, A1, A2>* NewPermanentCallback(
T* object, R (T::*function)(P1, P2, P3, P4, P5, A1, A2),
typename internal::InternalConstRef<P1>::type p1,
typename internal::InternalConstRef<P2>::type p2,
typename internal::InternalConstRef<P3>::type p3,
typename internal::InternalConstRef<P4>::type p4,
typename internal::InternalConstRef<P5>::type p5) {
return new internal::MethodResultCallback_5_2<R, T, P1, P2, P3, P4, P5, A1,
A2>(object, function, false, p1,
p2, p3, p4, p5);
}
// A function which does nothing. Useful for creating no-op callbacks, e.g.:
// Closure* nothing = NewCallback(&DoNothing);
void LIBPROTOBUF_EXPORT DoNothing();
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_STUBS_CALLBACK_H_

View File

@ -0,0 +1,134 @@
// 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.
#ifndef GOOGLE_PROTOBUF_CASTS_H__
#define GOOGLE_PROTOBUF_CASTS_H__
#include <type_traits>
#include <google/protobuf/stubs/common.h>
namespace google {
namespace protobuf {
namespace internal {
// Use implicit_cast as a safe version of static_cast or const_cast
// for upcasting in the type hierarchy (i.e. casting a pointer to Foo
// to a pointer to SuperclassOfFoo or casting a pointer to Foo to
// a const pointer to Foo).
// When you use implicit_cast, the compiler checks that the cast is safe.
// Such explicit implicit_casts are necessary in surprisingly many
// situations where C++ demands an exact type match instead of an
// argument type convertable to a target type.
//
// The From type can be inferred, so the preferred syntax for using
// implicit_cast is the same as for static_cast etc.:
//
// implicit_cast<ToType>(expr)
//
// implicit_cast would have been part of the C++ standard library,
// but the proposal was submitted too late. It will probably make
// its way into the language in the future.
template<typename To, typename From>
inline To implicit_cast(From const &f) {
return f;
}
// When you upcast (that is, cast a pointer from type Foo to type
// SuperclassOfFoo), it's fine to use implicit_cast<>, since upcasts
// always succeed. When you downcast (that is, cast a pointer from
// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because
// how do you know the pointer is really of type SubclassOfFoo? It
// could be a bare Foo, or of type DifferentSubclassOfFoo. Thus,
// when you downcast, you should use this macro. In debug mode, we
// use dynamic_cast<> to double-check the downcast is legal (we die
// if it's not). In normal mode, we do the efficient static_cast<>
// instead. Thus, it's important to test in debug mode to make sure
// the cast is legal!
// This is the only place in the code we should use dynamic_cast<>.
// In particular, you SHOULDN'T be using dynamic_cast<> in order to
// do RTTI (eg code like this:
// if (dynamic_cast<Subclass1>(foo)) HandleASubclass1Object(foo);
// if (dynamic_cast<Subclass2>(foo)) HandleASubclass2Object(foo);
// You should design the code some other way not to need this.
template<typename To, typename From> // use like this: down_cast<T*>(foo);
inline To down_cast(From* f) { // so we only accept pointers
// Ensures that To is a sub-type of From *. This test is here only
// for compile-time type checking, and has no overhead in an
// optimized build at run-time, as it will be optimized away
// completely.
if (false) {
implicit_cast<From*, To>(0);
}
#if !defined(NDEBUG) && !defined(GOOGLE_PROTOBUF_NO_RTTI)
assert(f == NULL || dynamic_cast<To>(f) != NULL); // RTTI: debug mode only!
#endif
return static_cast<To>(f);
}
template<typename To, typename From> // use like this: down_cast<T&>(foo);
inline To down_cast(From& f) {
typedef typename std::remove_reference<To>::type* ToAsPointer;
// Ensures that To is a sub-type of From *. This test is here only
// for compile-time type checking, and has no overhead in an
// optimized build at run-time, as it will be optimized away
// completely.
if (false) {
implicit_cast<From*, ToAsPointer>(0);
}
#if !defined(NDEBUG) && !defined(GOOGLE_PROTOBUF_NO_RTTI)
// RTTI: debug mode only!
assert(dynamic_cast<ToAsPointer>(&f) != NULL);
#endif
return *static_cast<ToAsPointer>(&f);
}
template<typename To, typename From>
inline To bit_cast(const From& from) {
GOOGLE_COMPILE_ASSERT(sizeof(From) == sizeof(To),
bit_cast_with_different_sizes);
To dest;
memcpy(&dest, &from, sizeof(dest));
return dest;
}
} // namespace internal
// We made these internal so that they would show up as such in the docs,
// but we don't want to stick "internal::" in front of them everywhere.
using internal::implicit_cast;
using internal::down_cast;
using internal::bit_cast;
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_CASTS_H__

View File

@ -0,0 +1,242 @@
// 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) and others
//
// Contains basic types and utilities used by the rest of the library.
#ifndef GOOGLE_PROTOBUF_COMMON_H__
#define GOOGLE_PROTOBUF_COMMON_H__
#include <algorithm>
#include <iostream>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>
#include <google/protobuf/stubs/port.h>
#include <google/protobuf/stubs/macros.h>
#include <google/protobuf/stubs/platform_macros.h>
// TODO(liujisi): Remove the following includes after the include clean-up.
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/mutex.h>
#include <google/protobuf/stubs/callback.h>
#ifndef PROTOBUF_USE_EXCEPTIONS
#if defined(_MSC_VER) && defined(_CPPUNWIND)
#define PROTOBUF_USE_EXCEPTIONS 1
#elif defined(__EXCEPTIONS)
#define PROTOBUF_USE_EXCEPTIONS 1
#else
#define PROTOBUF_USE_EXCEPTIONS 0
#endif
#endif
#if PROTOBUF_USE_EXCEPTIONS
#include <exception>
#endif
#if defined(__APPLE__)
#include <TargetConditionals.h> // for TARGET_OS_IPHONE
#endif
#if defined(__ANDROID__) || defined(GOOGLE_PROTOBUF_OS_ANDROID) || (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) || defined(GOOGLE_PROTOBUF_OS_IPHONE)
#include <pthread.h>
#endif
#if defined(_WIN32) && defined(GetMessage)
// Allow GetMessage to be used as a valid method name in protobuf classes.
// windows.h defines GetMessage() as a macro. Let's re-define it as an inline
// function. The inline function should be equivalent for C++ users.
inline BOOL GetMessage_Win32(
LPMSG lpMsg, HWND hWnd,
UINT wMsgFilterMin, UINT wMsgFilterMax) {
return GetMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax);
}
#undef GetMessage
inline BOOL GetMessage(
LPMSG lpMsg, HWND hWnd,
UINT wMsgFilterMin, UINT wMsgFilterMax) {
return GetMessage_Win32(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax);
}
#endif
namespace std {}
namespace google {
namespace protobuf {
namespace internal {
// Some of these constants are macros rather than const ints so that they can
// be used in #if directives.
// The current version, represented as a single integer to make comparison
// easier: major * 10^6 + minor * 10^3 + micro
#define GOOGLE_PROTOBUF_VERSION 3006001
// A suffix string for alpha, beta or rc releases. Empty for stable releases.
#define GOOGLE_PROTOBUF_VERSION_SUFFIX ""
// The minimum library version which works with the current version of the
// headers.
#define GOOGLE_PROTOBUF_MIN_LIBRARY_VERSION 3006001
// The minimum header version which works with the current version of
// the library. This constant should only be used by protoc's C++ code
// generator.
static const int kMinHeaderVersionForLibrary = 3006001;
// The minimum protoc version which works with the current version of the
// headers.
#define GOOGLE_PROTOBUF_MIN_PROTOC_VERSION 3006001
// The minimum header version which works with the current version of
// protoc. This constant should only be used in VerifyVersion().
static const int kMinHeaderVersionForProtoc = 3006001;
// Verifies that the headers and libraries are compatible. Use the macro
// below to call this.
void LIBPROTOBUF_EXPORT VerifyVersion(int headerVersion, int minLibraryVersion,
const char* filename);
// Converts a numeric version number to a string.
std::string LIBPROTOBUF_EXPORT VersionString(int version);
} // namespace internal
// Place this macro in your main() function (or somewhere before you attempt
// to use the protobuf library) to verify that the version you link against
// matches the headers you compiled against. If a version mismatch is
// detected, the process will abort.
#define GOOGLE_PROTOBUF_VERIFY_VERSION \
::google::protobuf::internal::VerifyVersion( \
GOOGLE_PROTOBUF_VERSION, GOOGLE_PROTOBUF_MIN_LIBRARY_VERSION, \
__FILE__)
// ===================================================================
// from google3/util/utf8/public/unilib.h
class StringPiece;
namespace internal {
// Checks if the buffer contains structurally-valid UTF-8. Implemented in
// structurally_valid.cc.
LIBPROTOBUF_EXPORT bool IsStructurallyValidUTF8(const char* buf, int len);
inline bool IsStructurallyValidUTF8(const std::string& str) {
return IsStructurallyValidUTF8(str.data(), static_cast<int>(str.length()));
}
// Returns initial number of bytes of structually valid UTF-8.
LIBPROTOBUF_EXPORT int UTF8SpnStructurallyValid(const StringPiece& str);
// Coerce UTF-8 byte string in src_str to be
// a structurally-valid equal-length string by selectively
// overwriting illegal bytes with replace_char (typically ' ' or '?').
// replace_char must be legal printable 7-bit Ascii 0x20..0x7e.
// src_str is read-only.
//
// Returns pointer to output buffer, src_str.data() if no changes were made,
// or idst if some bytes were changed. idst is allocated by the caller
// and must be at least as big as src_str
//
// Optimized for: all structurally valid and no byte copying is done.
//
LIBPROTOBUF_EXPORT char* UTF8CoerceToStructurallyValid(
const StringPiece& str, char* dst, char replace_char);
} // namespace internal
// ===================================================================
// Shutdown support.
// Shut down the entire protocol buffers library, deleting all static-duration
// objects allocated by the library or by generated .pb.cc files.
//
// There are two reasons you might want to call this:
// * You use a draconian definition of "memory leak" in which you expect
// every single malloc() to have a corresponding free(), even for objects
// which live until program exit.
// * You are writing a dynamically-loaded library which needs to clean up
// after itself when the library is unloaded.
//
// It is safe to call this multiple times. However, it is not safe to use
// any other part of the protocol buffers library after
// ShutdownProtobufLibrary() has been called. Furthermore this call is not
// thread safe, user needs to synchronize multiple calls.
LIBPROTOBUF_EXPORT void ShutdownProtobufLibrary();
namespace internal {
// Register a function to be called when ShutdownProtocolBuffers() is called.
LIBPROTOBUF_EXPORT void OnShutdown(void (*func)());
// Run an arbitrary function on an arg
LIBPROTOBUF_EXPORT void OnShutdownRun(void (*f)(const void*), const void* arg);
template <typename T>
T* OnShutdownDelete(T* p) {
OnShutdownRun([](const void* p) { delete static_cast<const T*>(p); }, p);
return p;
}
} // namespace internal
#if PROTOBUF_USE_EXCEPTIONS
class FatalException : public std::exception {
public:
FatalException(const char* filename, int line, const std::string& message)
: filename_(filename), line_(line), message_(message) {}
virtual ~FatalException() throw();
virtual const char* what() const throw();
const char* filename() const { return filename_; }
int line() const { return line_; }
const std::string& message() const { return message_; }
private:
const char* filename_;
const int line_;
const std::string message_;
};
#endif
// This is at the end of the file instead of the beginning to work around a bug
// in some versions of MSVC.
using std::string;
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_COMMON_H__

View File

@ -0,0 +1,153 @@
// 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.
// Fast memory copying and comparison routines.
// strings::fastmemcmp_inlined() replaces memcmp()
// strings::memcpy_inlined() replaces memcpy()
// strings::memeq(a, b, n) replaces memcmp(a, b, n) == 0
//
// strings::*_inlined() routines are inline versions of the
// routines exported by this module. Sometimes using the inlined
// versions is faster. Measure before using the inlined versions.
//
// Performance measurement:
// strings::fastmemcmp_inlined
// Analysis: memcmp, fastmemcmp_inlined, fastmemcmp
// 2012-01-30
#ifndef GOOGLE_PROTOBUF_STUBS_FASTMEM_H_
#define GOOGLE_PROTOBUF_STUBS_FASTMEM_H_
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <google/protobuf/stubs/common.h>
namespace google {
namespace protobuf {
namespace internal {
// Return true if the n bytes at a equal the n bytes at b.
// The regions are allowed to overlap.
//
// The performance is similar to the performance memcmp(), but faster for
// moderately-sized inputs, or inputs that share a common prefix and differ
// somewhere in their last 8 bytes. Further optimizations can be added later
// if it makes sense to do so.:w
inline bool memeq(const char* a, const char* b, size_t n) {
size_t n_rounded_down = n & ~static_cast<size_t>(7);
if (GOOGLE_PREDICT_FALSE(n_rounded_down == 0)) { // n <= 7
return memcmp(a, b, n) == 0;
}
// n >= 8
uint64 u = GOOGLE_UNALIGNED_LOAD64(a) ^ GOOGLE_UNALIGNED_LOAD64(b);
uint64 v = GOOGLE_UNALIGNED_LOAD64(a + n - 8) ^ GOOGLE_UNALIGNED_LOAD64(b + n - 8);
if ((u | v) != 0) { // The first or last 8 bytes differ.
return false;
}
a += 8;
b += 8;
n = n_rounded_down - 8;
if (n > 128) {
// As of 2012, memcmp on x86-64 uses a big unrolled loop with SSE2
// instructions, and while we could try to do something faster, it
// doesn't seem worth pursuing.
return memcmp(a, b, n) == 0;
}
for (; n >= 16; n -= 16) {
uint64 x = GOOGLE_UNALIGNED_LOAD64(a) ^ GOOGLE_UNALIGNED_LOAD64(b);
uint64 y = GOOGLE_UNALIGNED_LOAD64(a + 8) ^ GOOGLE_UNALIGNED_LOAD64(b + 8);
if ((x | y) != 0) {
return false;
}
a += 16;
b += 16;
}
// n must be 0 or 8 now because it was a multiple of 8 at the top of the loop.
return n == 0 || GOOGLE_UNALIGNED_LOAD64(a) == GOOGLE_UNALIGNED_LOAD64(b);
}
inline int fastmemcmp_inlined(const char *a, const char *b, size_t n) {
if (n >= 64) {
return memcmp(a, b, n);
}
const char* a_limit = a + n;
while (a + sizeof(uint64) <= a_limit &&
GOOGLE_UNALIGNED_LOAD64(a) == GOOGLE_UNALIGNED_LOAD64(b)) {
a += sizeof(uint64);
b += sizeof(uint64);
}
if (a + sizeof(uint32) <= a_limit &&
GOOGLE_UNALIGNED_LOAD32(a) == GOOGLE_UNALIGNED_LOAD32(b)) {
a += sizeof(uint32);
b += sizeof(uint32);
}
while (a < a_limit) {
int d =
static_cast<int>(static_cast<uint32>(*a++) - static_cast<uint32>(*b++));
if (d) return d;
}
return 0;
}
// The standard memcpy operation is slow for variable small sizes.
// This implementation inlines the optimal realization for sizes 1 to 16.
// To avoid code bloat don't use it in case of not performance-critical spots,
// nor when you don't expect very frequent values of size <= 16.
inline void memcpy_inlined(char *dst, const char *src, size_t size) {
// Compiler inlines code with minimal amount of data movement when third
// parameter of memcpy is a constant.
switch (size) {
case 1: memcpy(dst, src, 1); break;
case 2: memcpy(dst, src, 2); break;
case 3: memcpy(dst, src, 3); break;
case 4: memcpy(dst, src, 4); break;
case 5: memcpy(dst, src, 5); break;
case 6: memcpy(dst, src, 6); break;
case 7: memcpy(dst, src, 7); break;
case 8: memcpy(dst, src, 8); break;
case 9: memcpy(dst, src, 9); break;
case 10: memcpy(dst, src, 10); break;
case 11: memcpy(dst, src, 11); break;
case 12: memcpy(dst, src, 12); break;
case 13: memcpy(dst, src, 13); break;
case 14: memcpy(dst, src, 14); break;
case 15: memcpy(dst, src, 15); break;
case 16: memcpy(dst, src, 16); break;
default: memcpy(dst, src, size); break;
}
}
} // namespace internal
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_STUBS_FASTMEM_H_

View File

@ -0,0 +1,441 @@
// 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)
//
// Deals with the fact that hash_map is not defined everywhere.
#ifndef GOOGLE_PROTOBUF_STUBS_HASH_H__
#define GOOGLE_PROTOBUF_STUBS_HASH_H__
#include <string.h>
#include <google/protobuf/stubs/common.h>
#define GOOGLE_PROTOBUF_HAVE_HASH_MAP 1
#define GOOGLE_PROTOBUF_HAVE_HASH_SET 1
// Use C++11 unordered_{map|set} if available.
#if ((defined(_LIBCPP_STD_VER) && _LIBCPP_STD_VER >= 11) || \
(((__cplusplus >= 201103L) || defined(__GXX_EXPERIMENTAL_CXX0X)) && \
(__GLIBCXX__ > 20090421)))
# define GOOGLE_PROTOBUF_HAS_CXX11_HASH
// For XCode >= 4.6: the compiler is clang with libc++.
// For earlier XCode version: the compiler is gcc-4.2.1 with libstdc++.
// libc++ provides <unordered_map> and friends even in non C++11 mode,
// and it does not provide the tr1 library. Therefore the following macro
// checks against this special case.
// Note that we should not test the __APPLE_CC__ version number or the
// __clang__ macro, since the new compiler can still use -stdlib=libstdc++, in
// which case <unordered_map> is not compilable without -std=c++11
#elif defined(__APPLE_CC__)
# if __GNUC__ >= 4
# define GOOGLE_PROTOBUF_HAS_TR1
# else
// Not tested for gcc < 4... These setting can compile under 4.2.1 though.
# define GOOGLE_PROTOBUF_HASH_NAMESPACE __gnu_cxx
# include <ext/hash_map>
# define GOOGLE_PROTOBUF_HASH_MAP_CLASS hash_map
# include <ext/hash_set>
# define GOOGLE_PROTOBUF_HASH_SET_CLASS hash_set
# endif
// Version checks for gcc.
#elif defined(__GNUC__)
// For GCC 4.x+, use tr1::unordered_map/set; otherwise, follow the
// instructions from:
// https://gcc.gnu.org/onlinedocs/libstdc++/manual/backwards.html
# if __GNUC__ >= 4
# define GOOGLE_PROTOBUF_HAS_TR1
# elif __GNUC__ >= 3
# include <backward/hash_map>
# define GOOGLE_PROTOBUF_HASH_MAP_CLASS hash_map
# include <backward/hash_set>
# define GOOGLE_PROTOBUF_HASH_SET_CLASS hash_set
# if __GNUC__ == 3 && __GNUC_MINOR__ == 0
# define GOOGLE_PROTOBUF_HASH_NAMESPACE std // GCC 3.0
# else
# define GOOGLE_PROTOBUF_HASH_NAMESPACE __gnu_cxx // GCC 3.1 and later
# endif
# else
# define GOOGLE_PROTOBUF_HASH_NAMESPACE
# include <hash_map>
# define GOOGLE_PROTOBUF_HASH_MAP_CLASS hash_map
# include <hash_set>
# define GOOGLE_PROTOBUF_HASH_SET_CLASS hash_set
# endif
// GCC <= 4.1 does not define std::tr1::hash for `long long int` or `long long unsigned int`
# if __GNUC__ == 4 && defined(__GNUC_MINOR__) && __GNUC_MINOR__ <= 1
# undef GOOGLE_PROTOBUF_HAS_TR1
# undef GOOGLE_PROTOBUF_HAVE_HASH_MAP
# undef GOOGLE_PROTOBUF_HAVE_HASH_SET
# endif
// Version checks for MSC.
// Apparently Microsoft decided to move hash_map *back* to the std namespace in
// MSVC 2010:
// http://blogs.msdn.com/vcblog/archive/2009/05/25/stl-breaking-changes-in-visual-studio-2010-beta-1.aspx
// And.. they are moved back to stdext in MSVC 2013 (haven't checked 2012). That
// said, use unordered_map for MSVC 2010 and beyond is our safest bet.
#elif defined(_MSC_VER)
# if _MSC_VER >= 1600 // Since Visual Studio 2010
# define GOOGLE_PROTOBUF_HAS_CXX11_HASH
# define GOOGLE_PROTOBUF_HASH_COMPARE std::hash_compare
# elif _MSC_VER >= 1500 // Since Visual Studio 2008
# define GOOGLE_PROTOBUF_HASH_NAMESPACE stdext
# include <hash_map>
# define GOOGLE_PROTOBUF_HASH_MAP_CLASS hash_map
# include <hash_set>
# define GOOGLE_PROTOBUF_HASH_SET_CLASS hash_set
# define GOOGLE_PROTOBUF_HASH_COMPARE stdext::hash_compare
# define GOOGLE_PROTOBUF_CONTAINERS_NEED_HASH_COMPARE
# elif _MSC_VER >= 1310
# define GOOGLE_PROTOBUF_HASH_NAMESPACE stdext
# include <hash_map>
# define GOOGLE_PROTOBUF_HASH_MAP_CLASS hash_map
# include <hash_set>
# define GOOGLE_PROTOBUF_HASH_SET_CLASS hash_set
# define GOOGLE_PROTOBUF_HASH_COMPARE stdext::hash_compare
# else
# define GOOGLE_PROTOBUF_HASH_NAMESPACE std
# include <hash_map>
# define GOOGLE_PROTOBUF_HASH_MAP_CLASS hash_map
# include <hash_set>
# define GOOGLE_PROTOBUF_HASH_SET_CLASS hash_set
# define GOOGLE_PROTOBUF_HASH_COMPARE stdext::hash_compare
# endif
// **ADD NEW COMPILERS SUPPORT HERE.**
// For other compilers, undefine the macro and fallback to use std::map, in
// google/protobuf/stubs/hash.h
#else
# undef GOOGLE_PROTOBUF_HAVE_HASH_MAP
# undef GOOGLE_PROTOBUF_HAVE_HASH_SET
#endif
#if defined(GOOGLE_PROTOBUF_HAS_CXX11_HASH)
# define GOOGLE_PROTOBUF_HASH_NAMESPACE std
# include <unordered_map>
# define GOOGLE_PROTOBUF_HASH_MAP_CLASS unordered_map
# include <unordered_set>
# define GOOGLE_PROTOBUF_HASH_SET_CLASS unordered_set
#elif defined(GOOGLE_PROTOBUF_HAS_TR1)
# define GOOGLE_PROTOBUF_HASH_NAMESPACE std::tr1
# include <tr1/unordered_map>
# define GOOGLE_PROTOBUF_HASH_MAP_CLASS unordered_map
# include <tr1/unordered_set>
# define GOOGLE_PROTOBUF_HASH_SET_CLASS unordered_set
#endif
# define GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_START \
namespace google { \
namespace protobuf {
# define GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_END }}
#undef GOOGLE_PROTOBUF_HAS_CXX11_HASH
#undef GOOGLE_PROTOBUF_HAS_TR1
#if defined(GOOGLE_PROTOBUF_HAVE_HASH_MAP) && \
defined(GOOGLE_PROTOBUF_HAVE_HASH_SET)
#else
#define GOOGLE_PROTOBUF_MISSING_HASH
#include <map>
#include <set>
#endif
namespace google {
namespace protobuf {
#ifdef GOOGLE_PROTOBUF_MISSING_HASH
#undef GOOGLE_PROTOBUF_MISSING_HASH
// This system doesn't have hash_map or hash_set. Emulate them using map and
// set.
// Make hash<T> be the same as less<T>. Note that everywhere where custom
// hash functions are defined in the protobuf code, they are also defined such
// that they can be used as "less" functions, which is required by MSVC anyway.
template <typename Key>
struct hash {
// Dummy, just to make derivative hash functions compile.
int operator()(const Key& key) {
GOOGLE_LOG(FATAL) << "Should never be called.";
return 0;
}
inline bool operator()(const Key& a, const Key& b) const {
return a < b;
}
};
// Make sure char* is compared by value.
template <>
struct hash<const char*> {
// Dummy, just to make derivative hash functions compile.
int operator()(const char* key) {
GOOGLE_LOG(FATAL) << "Should never be called.";
return 0;
}
inline bool operator()(const char* a, const char* b) const {
return strcmp(a, b) < 0;
}
};
template <typename Key, typename Data,
typename HashFcn = hash<Key>,
typename EqualKey = std::equal_to<Key>,
typename Alloc = std::allocator< std::pair<const Key, Data> > >
class hash_map : public std::map<Key, Data, HashFcn, Alloc> {
typedef std::map<Key, Data, HashFcn, Alloc> BaseClass;
public:
hash_map(int a = 0, const HashFcn& b = HashFcn(),
const EqualKey& c = EqualKey(),
const Alloc& d = Alloc()) : BaseClass(b, d) {}
HashFcn hash_function() const { return HashFcn(); }
};
template <typename Key,
typename HashFcn = hash<Key>,
typename EqualKey = std::equal_to<Key> >
class hash_set : public std::set<Key, HashFcn> {
public:
hash_set(int = 0) {}
HashFcn hash_function() const { return HashFcn(); }
};
#elif defined(_MSC_VER) && !defined(_STLPORT_VERSION) && \
!(defined(_LIBCPP_STD_VER) && _LIBCPP_STD_VER >= 11)
template <typename Key>
struct hash : public GOOGLE_PROTOBUF_HASH_COMPARE<Key> {
};
// MSVC's hash_compare<const char*> hashes based on the string contents but
// compares based on the string pointer. WTF?
class CstringLess {
public:
inline bool operator()(const char* a, const char* b) const {
return strcmp(a, b) < 0;
}
};
template <>
struct hash<const char*>
: public GOOGLE_PROTOBUF_HASH_COMPARE<const char*, CstringLess> {};
#ifdef GOOGLE_PROTOBUF_CONTAINERS_NEED_HASH_COMPARE
template <typename Key, typename HashFcn, typename EqualKey>
struct InternalHashCompare : public GOOGLE_PROTOBUF_HASH_COMPARE<Key> {
InternalHashCompare() {}
InternalHashCompare(HashFcn hashfcn, EqualKey equalkey)
: hashfcn_(hashfcn), equalkey_(equalkey) {}
size_t operator()(const Key& key) const { return hashfcn_(key); }
bool operator()(const Key& key1, const Key& key2) const {
return !equalkey_(key1, key2);
}
HashFcn hashfcn_;
EqualKey equalkey_;
};
template <typename Key, typename Data,
typename HashFcn = hash<Key>,
typename EqualKey = std::equal_to<Key>,
typename Alloc = std::allocator< std::pair<const Key, Data> > >
class hash_map
: public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS<
Key, Data, InternalHashCompare<Key, HashFcn, EqualKey>, Alloc> {
typedef GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS<
Key, Data, InternalHashCompare<Key, HashFcn, EqualKey>, Alloc> BaseClass;
public:
hash_map(int a = 0, const HashFcn& b = HashFcn(),
const EqualKey& c = EqualKey(), const Alloc& d = Alloc())
: BaseClass(InternalHashCompare<Key, HashFcn, EqualKey>(b, c), d) {}
HashFcn hash_function() const { return HashFcn(); }
};
template <typename Key, typename HashFcn = hash<Key>,
typename EqualKey = std::equal_to<Key> >
class hash_set
: public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_SET_CLASS<
Key, InternalHashCompare<Key, HashFcn, EqualKey> > {
public:
hash_set(int = 0) {}
HashFcn hash_function() const { return HashFcn(); }
};
#else // GOOGLE_PROTOBUF_CONTAINERS_NEED_HASH_COMPARE
template <typename Key, typename Data,
typename HashFcn = hash<Key>,
typename EqualKey = std::equal_to<Key>,
typename Alloc = std::allocator< std::pair<const Key, Data> > >
class hash_map
: public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS<
Key, Data, HashFcn, EqualKey, Alloc> {
typedef GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS<
Key, Data, HashFcn, EqualKey, Alloc> BaseClass;
public:
hash_map(int a = 0, const HashFcn& b = HashFcn(),
const EqualKey& c = EqualKey(),
const Alloc& d = Alloc()) : BaseClass(a, b, c, d) {}
HashFcn hash_function() const { return HashFcn(); }
};
template <typename Key, typename HashFcn = hash<Key>,
typename EqualKey = std::equal_to<Key> >
class hash_set
: public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_SET_CLASS<
Key, HashFcn, EqualKey> {
public:
hash_set(int = 0) {}
HashFcn hash_function() const { return HashFcn(); }
};
#endif // GOOGLE_PROTOBUF_CONTAINERS_NEED_HASH_COMPARE
#else // defined(_MSC_VER) && !defined(_STLPORT_VERSION)
template <typename Key>
struct hash : public GOOGLE_PROTOBUF_HASH_NAMESPACE::hash<Key> {
};
template <typename Key>
struct hash<const Key*> {
inline size_t operator()(const Key* key) const {
return reinterpret_cast<size_t>(key);
}
};
// Unlike the old SGI version, the TR1 "hash" does not special-case char*. So,
// we go ahead and provide our own implementation.
template <>
struct hash<const char*> {
inline size_t operator()(const char* str) const {
size_t result = 0;
for (; *str != '\0'; str++) {
result = 5 * result + static_cast<size_t>(*str);
}
return result;
}
};
template<>
struct hash<bool> {
size_t operator()(bool x) const {
return static_cast<size_t>(x);
}
};
template <typename Key, typename Data,
typename HashFcn = hash<Key>,
typename EqualKey = std::equal_to<Key>,
typename Alloc = std::allocator< std::pair<const Key, Data> > >
class hash_map
: public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS<
Key, Data, HashFcn, EqualKey, Alloc> {
typedef GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS<
Key, Data, HashFcn, EqualKey, Alloc> BaseClass;
public:
hash_map(int a = 0, const HashFcn& b = HashFcn(),
const EqualKey& c = EqualKey(),
const Alloc& d = Alloc()) : BaseClass(a, b, c, d) {}
HashFcn hash_function() const { return HashFcn(); }
};
template <typename Key, typename HashFcn = hash<Key>,
typename EqualKey = std::equal_to<Key> >
class hash_set
: public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_SET_CLASS<
Key, HashFcn, EqualKey> {
public:
hash_set(int = 0) {}
HashFcn hash_function() const { return HashFcn(); }
};
#endif // !GOOGLE_PROTOBUF_MISSING_HASH
template <>
struct hash<string> {
inline size_t operator()(const string& key) const {
return hash<const char*>()(key.c_str());
}
static const size_t bucket_size = 4;
static const size_t min_buckets = 8;
inline bool operator()(const string& a, const string& b) const {
return a < b;
}
};
template <typename First, typename Second>
struct hash<std::pair<First, Second> > {
inline size_t operator()(const std::pair<First, Second>& key) const {
size_t first_hash = hash<First>()(key.first);
size_t second_hash = hash<Second>()(key.second);
// FIXME(kenton): What is the best way to compute this hash? I have
// no idea! This seems a bit better than an XOR.
return first_hash * ((1 << 16) - 1) + second_hash;
}
static const size_t bucket_size = 4;
static const size_t min_buckets = 8;
inline bool operator()(const std::pair<First, Second>& a,
const std::pair<First, Second>& b) const {
return a < b;
}
};
// Used by GCC/SGI STL only. (Why isn't this provided by the standard
// library? :( )
struct streq {
inline bool operator()(const char* a, const char* b) const {
return strcmp(a, b) == 0;
}
};
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_STUBS_HASH_H__

View File

@ -0,0 +1,383 @@
// 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_STUBS_INT128_H_
#define GOOGLE_PROTOBUF_STUBS_INT128_H_
#include <google/protobuf/stubs/common.h>
#include <iosfwd>
namespace google {
namespace protobuf {
struct uint128_pod;
// TODO(xiaofeng): Define GOOGLE_PROTOBUF_HAS_CONSTEXPR when constexpr is
// available.
#ifdef GOOGLE_PROTOBUF_HAS_CONSTEXPR
# define UINT128_CONSTEXPR constexpr
#else
# define UINT128_CONSTEXPR
#endif
// An unsigned 128-bit integer type. Thread-compatible.
class LIBPROTOBUF_EXPORT uint128 {
public:
UINT128_CONSTEXPR uint128(); // Sets to 0, but don't trust on this behavior.
UINT128_CONSTEXPR uint128(uint64 top, uint64 bottom);
#ifndef SWIG
UINT128_CONSTEXPR uint128(int bottom);
UINT128_CONSTEXPR uint128(uint32 bottom); // Top 96 bits = 0
#endif
UINT128_CONSTEXPR uint128(uint64 bottom); // hi_ = 0
UINT128_CONSTEXPR uint128(const uint128_pod &val);
// Trivial copy constructor, assignment operator and destructor.
void Initialize(uint64 top, uint64 bottom);
// Arithmetic operators.
uint128& operator+=(const uint128& b);
uint128& operator-=(const uint128& b);
uint128& operator*=(const uint128& b);
// Long division/modulo for uint128.
uint128& operator/=(const uint128& b);
uint128& operator%=(const uint128& b);
uint128 operator++(int);
uint128 operator--(int);
uint128& operator<<=(int);
uint128& operator>>=(int);
uint128& operator&=(const uint128& b);
uint128& operator|=(const uint128& b);
uint128& operator^=(const uint128& b);
uint128& operator++();
uint128& operator--();
friend uint64 Uint128Low64(const uint128& v);
friend uint64 Uint128High64(const uint128& v);
// We add "std::" to avoid including all of port.h.
LIBPROTOBUF_EXPORT friend std::ostream& operator<<(std::ostream& o,
const uint128& b);
private:
static void DivModImpl(uint128 dividend, uint128 divisor,
uint128* quotient_ret, uint128* remainder_ret);
// Little-endian memory order optimizations can benefit from
// having lo_ first, hi_ last.
// See util/endian/endian.h and Load128/Store128 for storing a uint128.
uint64 lo_;
uint64 hi_;
// Not implemented, just declared for catching automatic type conversions.
uint128(uint8);
uint128(uint16);
uint128(float v);
uint128(double v);
};
// This is a POD form of uint128 which can be used for static variables which
// need to be operated on as uint128.
struct uint128_pod {
// Note: The ordering of fields is different than 'class uint128' but the
// same as its 2-arg constructor. This enables more obvious initialization
// of static instances, which is the primary reason for this struct in the
// first place. This does not seem to defeat any optimizations wrt
// operations involving this struct.
uint64 hi;
uint64 lo;
};
LIBPROTOBUF_EXPORT extern const uint128_pod kuint128max;
// allow uint128 to be logged
LIBPROTOBUF_EXPORT extern std::ostream& operator<<(std::ostream& o,
const uint128& b);
// Methods to access low and high pieces of 128-bit value.
// Defined externally from uint128 to facilitate conversion
// to native 128-bit types when compilers support them.
inline uint64 Uint128Low64(const uint128& v) { return v.lo_; }
inline uint64 Uint128High64(const uint128& v) { return v.hi_; }
// TODO: perhaps it would be nice to have int128, a signed 128-bit type?
// --------------------------------------------------------------------------
// Implementation details follow
// --------------------------------------------------------------------------
inline bool operator==(const uint128& lhs, const uint128& rhs) {
return (Uint128Low64(lhs) == Uint128Low64(rhs) &&
Uint128High64(lhs) == Uint128High64(rhs));
}
inline bool operator!=(const uint128& lhs, const uint128& rhs) {
return !(lhs == rhs);
}
inline UINT128_CONSTEXPR uint128::uint128() : lo_(0), hi_(0) {}
inline UINT128_CONSTEXPR uint128::uint128(uint64 top, uint64 bottom)
: lo_(bottom), hi_(top) {}
inline UINT128_CONSTEXPR uint128::uint128(const uint128_pod& v)
: lo_(v.lo), hi_(v.hi) {}
inline UINT128_CONSTEXPR uint128::uint128(uint64 bottom)
: lo_(bottom), hi_(0) {}
#ifndef SWIG
inline UINT128_CONSTEXPR uint128::uint128(uint32 bottom)
: lo_(bottom), hi_(0) {}
inline UINT128_CONSTEXPR uint128::uint128(int bottom)
: lo_(bottom), hi_(static_cast<int64>((bottom < 0) ? -1 : 0)) {}
#endif
#undef UINT128_CONSTEXPR
inline void uint128::Initialize(uint64 top, uint64 bottom) {
hi_ = top;
lo_ = bottom;
}
// Comparison operators.
#define CMP128(op) \
inline bool operator op(const uint128& lhs, const uint128& rhs) { \
return (Uint128High64(lhs) == Uint128High64(rhs)) ? \
(Uint128Low64(lhs) op Uint128Low64(rhs)) : \
(Uint128High64(lhs) op Uint128High64(rhs)); \
}
CMP128(<)
CMP128(>)
CMP128(>=)
CMP128(<=)
#undef CMP128
// Unary operators
inline uint128 operator-(const uint128& val) {
const uint64 hi_flip = ~Uint128High64(val);
const uint64 lo_flip = ~Uint128Low64(val);
const uint64 lo_add = lo_flip + 1;
if (lo_add < lo_flip) {
return uint128(hi_flip + 1, lo_add);
}
return uint128(hi_flip, lo_add);
}
inline bool operator!(const uint128& val) {
return !Uint128High64(val) && !Uint128Low64(val);
}
// Logical operators.
inline uint128 operator~(const uint128& val) {
return uint128(~Uint128High64(val), ~Uint128Low64(val));
}
#define LOGIC128(op) \
inline uint128 operator op(const uint128& lhs, const uint128& rhs) { \
return uint128(Uint128High64(lhs) op Uint128High64(rhs), \
Uint128Low64(lhs) op Uint128Low64(rhs)); \
}
LOGIC128(|)
LOGIC128(&)
LOGIC128(^)
#undef LOGIC128
#define LOGICASSIGN128(op) \
inline uint128& uint128::operator op(const uint128& other) { \
hi_ op other.hi_; \
lo_ op other.lo_; \
return *this; \
}
LOGICASSIGN128(|=)
LOGICASSIGN128(&=)
LOGICASSIGN128(^=)
#undef LOGICASSIGN128
// Shift operators.
inline uint128 operator<<(const uint128& val, int amount) {
// uint64 shifts of >= 64 are undefined, so we will need some special-casing.
if (amount < 64) {
if (amount == 0) {
return val;
}
uint64 new_hi = (Uint128High64(val) << amount) |
(Uint128Low64(val) >> (64 - amount));
uint64 new_lo = Uint128Low64(val) << amount;
return uint128(new_hi, new_lo);
} else if (amount < 128) {
return uint128(Uint128Low64(val) << (amount - 64), 0);
} else {
return uint128(0, 0);
}
}
inline uint128 operator>>(const uint128& val, int amount) {
// uint64 shifts of >= 64 are undefined, so we will need some special-casing.
if (amount < 64) {
if (amount == 0) {
return val;
}
uint64 new_hi = Uint128High64(val) >> amount;
uint64 new_lo = (Uint128Low64(val) >> amount) |
(Uint128High64(val) << (64 - amount));
return uint128(new_hi, new_lo);
} else if (amount < 128) {
return uint128(0, Uint128High64(val) >> (amount - 64));
} else {
return uint128(0, 0);
}
}
inline uint128& uint128::operator<<=(int amount) {
// uint64 shifts of >= 64 are undefined, so we will need some special-casing.
if (amount < 64) {
if (amount != 0) {
hi_ = (hi_ << amount) | (lo_ >> (64 - amount));
lo_ = lo_ << amount;
}
} else if (amount < 128) {
hi_ = lo_ << (amount - 64);
lo_ = 0;
} else {
hi_ = 0;
lo_ = 0;
}
return *this;
}
inline uint128& uint128::operator>>=(int amount) {
// uint64 shifts of >= 64 are undefined, so we will need some special-casing.
if (amount < 64) {
if (amount != 0) {
lo_ = (lo_ >> amount) | (hi_ << (64 - amount));
hi_ = hi_ >> amount;
}
} else if (amount < 128) {
lo_ = hi_ >> (amount - 64);
hi_ = 0;
} else {
lo_ = 0;
hi_ = 0;
}
return *this;
}
inline uint128 operator+(const uint128& lhs, const uint128& rhs) {
return uint128(lhs) += rhs;
}
inline uint128 operator-(const uint128& lhs, const uint128& rhs) {
return uint128(lhs) -= rhs;
}
inline uint128 operator*(const uint128& lhs, const uint128& rhs) {
return uint128(lhs) *= rhs;
}
inline uint128 operator/(const uint128& lhs, const uint128& rhs) {
return uint128(lhs) /= rhs;
}
inline uint128 operator%(const uint128& lhs, const uint128& rhs) {
return uint128(lhs) %= rhs;
}
inline uint128& uint128::operator+=(const uint128& b) {
hi_ += b.hi_;
uint64 lolo = lo_ + b.lo_;
if (lolo < lo_)
++hi_;
lo_ = lolo;
return *this;
}
inline uint128& uint128::operator-=(const uint128& b) {
hi_ -= b.hi_;
if (b.lo_ > lo_)
--hi_;
lo_ -= b.lo_;
return *this;
}
inline uint128& uint128::operator*=(const uint128& b) {
uint64 a96 = hi_ >> 32;
uint64 a64 = hi_ & 0xffffffffu;
uint64 a32 = lo_ >> 32;
uint64 a00 = lo_ & 0xffffffffu;
uint64 b96 = b.hi_ >> 32;
uint64 b64 = b.hi_ & 0xffffffffu;
uint64 b32 = b.lo_ >> 32;
uint64 b00 = b.lo_ & 0xffffffffu;
// multiply [a96 .. a00] x [b96 .. b00]
// terms higher than c96 disappear off the high side
// terms c96 and c64 are safe to ignore carry bit
uint64 c96 = a96 * b00 + a64 * b32 + a32 * b64 + a00 * b96;
uint64 c64 = a64 * b00 + a32 * b32 + a00 * b64;
this->hi_ = (c96 << 32) + c64;
this->lo_ = 0;
// add terms after this one at a time to capture carry
*this += uint128(a32 * b00) << 32;
*this += uint128(a00 * b32) << 32;
*this += a00 * b00;
return *this;
}
inline uint128 uint128::operator++(int) {
uint128 tmp(*this);
*this += 1;
return tmp;
}
inline uint128 uint128::operator--(int) {
uint128 tmp(*this);
*this -= 1;
return tmp;
}
inline uint128& uint128::operator++() {
*this += 1;
return *this;
}
inline uint128& uint128::operator--() {
*this -= 1;
return *this;
}
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_STUBS_INT128_H_

View File

@ -0,0 +1,115 @@
// 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: laszlocsomor@google.com (Laszlo Csomor)
//
// This file contains the declarations for Windows implementations of
// commonly used POSIX functions such as open(2) and access(2), as well
// as macro definitions for flags of these functions.
//
// By including this file you'll redefine open/access/etc. to
// ::google::protobuf::internal::win32::{open/access/etc.}.
// Make sure you don't include a header that attempts to redeclare or
// redefine these functions, that'll lead to confusing compilation
// errors. It's best to #include this file as the last one to ensure that.
//
// This file is only used on Windows, it's empty on other platforms.
#ifndef GOOGLE_PROTOBUF_STUBS_IO_WIN32_H__
#define GOOGLE_PROTOBUF_STUBS_IO_WIN32_H__
#if defined(_WIN32)
#include <string>
#include <google/protobuf/stubs/port.h>
// Compilers on Windows other than MSVC (e.g. Cygwin, MinGW32) define the
// following functions already, except for mkdir.
namespace google {
namespace protobuf {
namespace internal {
namespace win32 {
LIBPROTOBUF_EXPORT FILE* fopen(const char* path, const char* mode);
LIBPROTOBUF_EXPORT int access(const char* path, int mode);
LIBPROTOBUF_EXPORT int chdir(const char* path);
LIBPROTOBUF_EXPORT int close(int fd);
LIBPROTOBUF_EXPORT int dup(int fd);
LIBPROTOBUF_EXPORT int dup2(int fd1, int fd2);
LIBPROTOBUF_EXPORT int mkdir(const char* path, int _mode);
LIBPROTOBUF_EXPORT int open(const char* path, int flags, int mode = 0);
LIBPROTOBUF_EXPORT int read(int fd, void* buffer, size_t size);
LIBPROTOBUF_EXPORT int setmode(int fd, int mode);
LIBPROTOBUF_EXPORT int stat(const char* path, struct _stat* buffer);
LIBPROTOBUF_EXPORT int write(int fd, const void* buffer, size_t size);
LIBPROTOBUF_EXPORT std::wstring testonly_utf8_to_winpath(const char* path);
namespace strings {
// Convert from UTF-16 to Active-Code-Page-encoded or to UTF-8-encoded text.
LIBPROTOBUF_EXPORT bool wcs_to_mbs(
const wchar_t* s, std::string* out, bool outUtf8);
// Convert from Active-Code-Page-encoded or UTF-8-encoded text to UTF-16.
LIBPROTOBUF_EXPORT bool mbs_to_wcs(
const char* s, std::wstring* out, bool inUtf8);
// Convert from UTF-8-encoded text to UTF-16.
LIBPROTOBUF_EXPORT bool utf8_to_wcs(const char* input, std::wstring* out);
// Convert from UTF-16-encoded text to UTF-8.
LIBPROTOBUF_EXPORT bool wcs_to_utf8(const wchar_t* input, std::string* out);
} // namespace strings
} // namespace win32
} // namespace internal
} // namespace protobuf
} // namespace google
#ifndef W_OK
#define W_OK 02 // not defined by MSVC for whatever reason
#endif
#ifndef F_OK
#define F_OK 00 // not defined by MSVC for whatever reason
#endif
#ifndef STDIN_FILENO
#define STDIN_FILENO 0
#endif
#ifndef STDOUT_FILENO
#define STDOUT_FILENO 1
#endif
#endif // defined(_WIN32)
#endif // GOOGLE_PROTOBUF_STUBS_IO_WIN32_H__

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.
#ifndef GOOGLE_PROTOBUF_STUBS_LOGGING_H_
#define GOOGLE_PROTOBUF_STUBS_LOGGING_H_
#include <google/protobuf/stubs/macros.h>
#include <google/protobuf/stubs/port.h>
// ===================================================================
// emulates google3/base/logging.h
namespace google {
namespace protobuf {
enum LogLevel {
LOGLEVEL_INFO, // Informational. This is never actually used by
// libprotobuf.
LOGLEVEL_WARNING, // Warns about issues that, although not technically a
// problem now, could cause problems in the future. For
// example, a // warning will be printed when parsing a
// message that is near the message size limit.
LOGLEVEL_ERROR, // An error occurred which should never happen during
// normal use.
LOGLEVEL_FATAL, // An error occurred from which the library cannot
// recover. This usually indicates a programming error
// in the code which calls the library, especially when
// compiled in debug mode.
#ifdef NDEBUG
LOGLEVEL_DFATAL = LOGLEVEL_ERROR
#else
LOGLEVEL_DFATAL = LOGLEVEL_FATAL
#endif
};
class StringPiece;
namespace util {
class Status;
}
class uint128;
namespace internal {
class LogFinisher;
class LIBPROTOBUF_EXPORT LogMessage {
public:
LogMessage(LogLevel level, const char* filename, int line);
~LogMessage();
LogMessage& operator<<(const std::string& value);
LogMessage& operator<<(const char* value);
LogMessage& operator<<(char value);
LogMessage& operator<<(int value);
LogMessage& operator<<(uint value);
LogMessage& operator<<(long value);
LogMessage& operator<<(unsigned long value);
LogMessage& operator<<(long long value);
LogMessage& operator<<(unsigned long long value);
LogMessage& operator<<(double value);
LogMessage& operator<<(void* value);
LogMessage& operator<<(const StringPiece& value);
LogMessage& operator<<(const ::google::protobuf::util::Status& status);
LogMessage& operator<<(const uint128& value);
private:
friend class LogFinisher;
void Finish();
LogLevel level_;
const char* filename_;
int line_;
std::string message_;
};
// Used to make the entire "LOG(BLAH) << etc." expression have a void return
// type and print a newline after each message.
class LIBPROTOBUF_EXPORT LogFinisher {
public:
void operator=(LogMessage& other);
};
template<typename T>
bool IsOk(T status) { return status.ok(); }
template<>
inline bool IsOk(bool status) { return status; }
} // namespace internal
// Undef everything in case we're being mixed with some other Google library
// which already defined them itself. Presumably all Google libraries will
// support the same syntax for these so it should not be a big deal if they
// end up using our definitions instead.
#undef GOOGLE_LOG
#undef GOOGLE_LOG_IF
#undef GOOGLE_CHECK
#undef GOOGLE_CHECK_OK
#undef GOOGLE_CHECK_EQ
#undef GOOGLE_CHECK_NE
#undef GOOGLE_CHECK_LT
#undef GOOGLE_CHECK_LE
#undef GOOGLE_CHECK_GT
#undef GOOGLE_CHECK_GE
#undef GOOGLE_CHECK_NOTNULL
#undef GOOGLE_DLOG
#undef GOOGLE_DCHECK
#undef GOOGLE_DCHECK_OK
#undef GOOGLE_DCHECK_EQ
#undef GOOGLE_DCHECK_NE
#undef GOOGLE_DCHECK_LT
#undef GOOGLE_DCHECK_LE
#undef GOOGLE_DCHECK_GT
#undef GOOGLE_DCHECK_GE
#define GOOGLE_LOG(LEVEL) \
::google::protobuf::internal::LogFinisher() = \
::google::protobuf::internal::LogMessage( \
::google::protobuf::LOGLEVEL_##LEVEL, __FILE__, __LINE__)
#define GOOGLE_LOG_IF(LEVEL, CONDITION) \
!(CONDITION) ? (void)0 : GOOGLE_LOG(LEVEL)
#define GOOGLE_CHECK(EXPRESSION) \
GOOGLE_LOG_IF(FATAL, !(EXPRESSION)) << "CHECK failed: " #EXPRESSION ": "
#define GOOGLE_CHECK_OK(A) GOOGLE_CHECK(::google::protobuf::internal::IsOk(A))
#define GOOGLE_CHECK_EQ(A, B) GOOGLE_CHECK((A) == (B))
#define GOOGLE_CHECK_NE(A, B) GOOGLE_CHECK((A) != (B))
#define GOOGLE_CHECK_LT(A, B) GOOGLE_CHECK((A) < (B))
#define GOOGLE_CHECK_LE(A, B) GOOGLE_CHECK((A) <= (B))
#define GOOGLE_CHECK_GT(A, B) GOOGLE_CHECK((A) > (B))
#define GOOGLE_CHECK_GE(A, B) GOOGLE_CHECK((A) >= (B))
namespace internal {
template<typename T>
T* CheckNotNull(const char* /* file */, int /* line */,
const char* name, T* val) {
if (val == NULL) {
GOOGLE_LOG(FATAL) << name;
}
return val;
}
} // namespace internal
#define GOOGLE_CHECK_NOTNULL(A) \
::google::protobuf::internal::CheckNotNull(\
__FILE__, __LINE__, "'" #A "' must not be NULL", (A))
#ifdef NDEBUG
#define GOOGLE_DLOG(LEVEL) GOOGLE_LOG_IF(LEVEL, false)
#define GOOGLE_DCHECK(EXPRESSION) while(false) GOOGLE_CHECK(EXPRESSION)
#define GOOGLE_DCHECK_OK(E) GOOGLE_DCHECK(::google::protobuf::internal::IsOk(E))
#define GOOGLE_DCHECK_EQ(A, B) GOOGLE_DCHECK((A) == (B))
#define GOOGLE_DCHECK_NE(A, B) GOOGLE_DCHECK((A) != (B))
#define GOOGLE_DCHECK_LT(A, B) GOOGLE_DCHECK((A) < (B))
#define GOOGLE_DCHECK_LE(A, B) GOOGLE_DCHECK((A) <= (B))
#define GOOGLE_DCHECK_GT(A, B) GOOGLE_DCHECK((A) > (B))
#define GOOGLE_DCHECK_GE(A, B) GOOGLE_DCHECK((A) >= (B))
#else // NDEBUG
#define GOOGLE_DLOG GOOGLE_LOG
#define GOOGLE_DCHECK GOOGLE_CHECK
#define GOOGLE_DCHECK_OK GOOGLE_CHECK_OK
#define GOOGLE_DCHECK_EQ GOOGLE_CHECK_EQ
#define GOOGLE_DCHECK_NE GOOGLE_CHECK_NE
#define GOOGLE_DCHECK_LT GOOGLE_CHECK_LT
#define GOOGLE_DCHECK_LE GOOGLE_CHECK_LE
#define GOOGLE_DCHECK_GT GOOGLE_CHECK_GT
#define GOOGLE_DCHECK_GE GOOGLE_CHECK_GE
#endif // !NDEBUG
typedef void LogHandler(LogLevel level, const char* filename, int line,
const std::string& message);
// The protobuf library sometimes writes warning and error messages to
// stderr. These messages are primarily useful for developers, but may
// also help end users figure out a problem. If you would prefer that
// these messages be sent somewhere other than stderr, call SetLogHandler()
// to set your own handler. This returns the old handler. Set the handler
// to NULL to ignore log messages (but see also LogSilencer, below).
//
// Obviously, SetLogHandler is not thread-safe. You should only call it
// at initialization time, and probably not from library code. If you
// simply want to suppress log messages temporarily (e.g. because you
// have some code that tends to trigger them frequently and you know
// the warnings are not important to you), use the LogSilencer class
// below.
LIBPROTOBUF_EXPORT LogHandler* SetLogHandler(LogHandler* new_func);
// Create a LogSilencer if you want to temporarily suppress all log
// messages. As long as any LogSilencer objects exist, non-fatal
// log messages will be discarded (the current LogHandler will *not*
// be called). Constructing a LogSilencer is thread-safe. You may
// accidentally suppress log messages occurring in another thread, but
// since messages are generally for debugging purposes only, this isn't
// a big deal. If you want to intercept log messages, use SetLogHandler().
class LIBPROTOBUF_EXPORT LogSilencer {
public:
LogSilencer();
~LogSilencer();
};
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_STUBS_LOGGING_H_

View File

@ -0,0 +1,168 @@
// 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_MACROS_H__
#define GOOGLE_PROTOBUF_MACROS_H__
#include <google/protobuf/stubs/port.h>
namespace google {
namespace protobuf {
#undef GOOGLE_DISALLOW_EVIL_CONSTRUCTORS
#define GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TypeName) \
TypeName(const TypeName&); \
void operator=(const TypeName&)
#undef GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS
#define GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
TypeName(); \
TypeName(const TypeName&); \
void operator=(const TypeName&)
// ===================================================================
// from google3/base/basictypes.h
// The GOOGLE_ARRAYSIZE(arr) macro returns the # of elements in an array arr.
// The expression is a compile-time constant, and therefore can be
// used in defining new arrays, for example.
//
// GOOGLE_ARRAYSIZE catches a few type errors. If you see a compiler error
//
// "warning: division by zero in ..."
//
// when using GOOGLE_ARRAYSIZE, you are (wrongfully) giving it a pointer.
// You should only use GOOGLE_ARRAYSIZE on statically allocated arrays.
//
// The following comments are on the implementation details, and can
// be ignored by the users.
//
// ARRAYSIZE(arr) works by inspecting sizeof(arr) (the # of bytes in
// the array) and sizeof(*(arr)) (the # of bytes in one array
// element). If the former is divisible by the latter, perhaps arr is
// indeed an array, in which case the division result is the # of
// elements in the array. Otherwise, arr cannot possibly be an array,
// and we generate a compiler error to prevent the code from
// compiling.
//
// Since the size of bool is implementation-defined, we need to cast
// !(sizeof(a) & sizeof(*(a))) to size_t in order to ensure the final
// result has type size_t.
//
// This macro is not perfect as it wrongfully accepts certain
// pointers, namely where the pointer size is divisible by the pointee
// size. Since all our code has to go through a 32-bit compiler,
// where a pointer is 4 bytes, this means all pointers to a type whose
// size is 3 or greater than 4 will be (righteously) rejected.
//
// Kudos to Jorg Brown for this simple and elegant implementation.
#undef GOOGLE_ARRAYSIZE
#define GOOGLE_ARRAYSIZE(a) \
((sizeof(a) / sizeof(*(a))) / \
static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
// The COMPILE_ASSERT macro can be used to verify that a compile time
// expression is true. For example, you could use it to verify the
// size of a static array:
//
// COMPILE_ASSERT(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES,
// content_type_names_incorrect_size);
//
// or to make sure a struct is smaller than a certain size:
//
// COMPILE_ASSERT(sizeof(foo) < 128, foo_too_large);
//
// The second argument to the macro is the name of the variable. If
// the expression is false, most compilers will issue a warning/error
// containing the name of the variable.
namespace internal {
template <bool>
struct CompileAssert {
};
} // namespace internal
#undef GOOGLE_COMPILE_ASSERT
#if __cplusplus >= 201103L
#define GOOGLE_COMPILE_ASSERT(expr, msg) static_assert(expr, #msg)
#else
#define GOOGLE_COMPILE_ASSERT(expr, msg) \
::google::protobuf::internal::CompileAssert<(bool(expr))> \
msg[bool(expr) ? 1 : -1]; \
(void)msg
// Implementation details of COMPILE_ASSERT:
//
// - COMPILE_ASSERT works by defining an array type that has -1
// elements (and thus is invalid) when the expression is false.
//
// - The simpler definition
//
// #define COMPILE_ASSERT(expr, msg) typedef char msg[(expr) ? 1 : -1]
//
// does not work, as gcc supports variable-length arrays whose sizes
// are determined at run-time (this is gcc's extension and not part
// of the C++ standard). As a result, gcc fails to reject the
// following code with the simple definition:
//
// int foo;
// COMPILE_ASSERT(foo, msg); // not supposed to compile as foo is
// // not a compile-time constant.
//
// - By using the type CompileAssert<(bool(expr))>, we ensures that
// expr is a compile-time constant. (Template arguments must be
// determined at compile-time.)
//
// - The outter parentheses in CompileAssert<(bool(expr))> are necessary
// to work around a bug in gcc 3.4.4 and 4.0.1. If we had written
//
// CompileAssert<bool(expr)>
//
// instead, these compilers will refuse to compile
//
// COMPILE_ASSERT(5 > 0, some_message);
//
// (They seem to think the ">" in "5 > 0" marks the end of the
// template argument list.)
//
// - The array size is (bool(expr) ? 1 : -1), instead of simply
//
// ((expr) ? 1 : -1).
//
// This is to avoid running into a bug in MS VC 7.1, which
// causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1.
#endif // __cplusplus >= 201103L
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_MACROS_H__

View File

@ -0,0 +1,771 @@
// 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.
// from google3/util/gtl/map_util.h
// Author: Anton Carver
#ifndef GOOGLE_PROTOBUF_STUBS_MAP_UTIL_H__
#define GOOGLE_PROTOBUF_STUBS_MAP_UTIL_H__
#include <stddef.h>
#include <iterator>
#include <string>
#include <utility>
#include <vector>
#include <google/protobuf/stubs/common.h>
namespace google {
namespace protobuf {
namespace internal {
// Local implementation of RemoveConst to avoid including base/type_traits.h.
template <class T> struct RemoveConst { typedef T type; };
template <class T> struct RemoveConst<const T> : RemoveConst<T> {};
} // namespace internal
//
// Find*()
//
// Returns a const reference to the value associated with the given key if it
// exists. Crashes otherwise.
//
// This is intended as a replacement for operator[] as an rvalue (for reading)
// when the key is guaranteed to exist.
//
// operator[] for lookup is discouraged for several reasons:
// * It has a side-effect of inserting missing keys
// * It is not thread-safe (even when it is not inserting, it can still
// choose to resize the underlying storage)
// * It invalidates iterators (when it chooses to resize)
// * It default constructs a value object even if it doesn't need to
//
// This version assumes the key is printable, and includes it in the fatal log
// message.
template <class Collection>
const typename Collection::value_type::second_type&
FindOrDie(const Collection& collection,
const typename Collection::value_type::first_type& key) {
typename Collection::const_iterator it = collection.find(key);
GOOGLE_CHECK(it != collection.end()) << "Map key not found: " << key;
return it->second;
}
// Same as above, but returns a non-const reference.
template <class Collection>
typename Collection::value_type::second_type&
FindOrDie(Collection& collection, // NOLINT
const typename Collection::value_type::first_type& key) {
typename Collection::iterator it = collection.find(key);
GOOGLE_CHECK(it != collection.end()) << "Map key not found: " << key;
return it->second;
}
// Same as FindOrDie above, but doesn't log the key on failure.
template <class Collection>
const typename Collection::value_type::second_type&
FindOrDieNoPrint(const Collection& collection,
const typename Collection::value_type::first_type& key) {
typename Collection::const_iterator it = collection.find(key);
GOOGLE_CHECK(it != collection.end()) << "Map key not found";
return it->second;
}
// Same as above, but returns a non-const reference.
template <class Collection>
typename Collection::value_type::second_type&
FindOrDieNoPrint(Collection& collection, // NOLINT
const typename Collection::value_type::first_type& key) {
typename Collection::iterator it = collection.find(key);
GOOGLE_CHECK(it != collection.end()) << "Map key not found";
return it->second;
}
// Returns a const reference to the value associated with the given key if it
// exists, otherwise returns a const reference to the provided default value.
//
// WARNING: If a temporary object is passed as the default "value,"
// this function will return a reference to that temporary object,
// which will be destroyed at the end of the statement. A common
// example: if you have a map with string values, and you pass a char*
// as the default "value," either use the returned value immediately
// or store it in a string (not string&).
// Details: http://go/findwithdefault
template <class Collection>
const typename Collection::value_type::second_type&
FindWithDefault(const Collection& collection,
const typename Collection::value_type::first_type& key,
const typename Collection::value_type::second_type& value) {
typename Collection::const_iterator it = collection.find(key);
if (it == collection.end()) {
return value;
}
return it->second;
}
// Returns a pointer to the const value associated with the given key if it
// exists, or NULL otherwise.
template <class Collection>
const typename Collection::value_type::second_type*
FindOrNull(const Collection& collection,
const typename Collection::value_type::first_type& key) {
typename Collection::const_iterator it = collection.find(key);
if (it == collection.end()) {
return 0;
}
return &it->second;
}
// Same as above but returns a pointer to the non-const value.
template <class Collection>
typename Collection::value_type::second_type*
FindOrNull(Collection& collection, // NOLINT
const typename Collection::value_type::first_type& key) {
typename Collection::iterator it = collection.find(key);
if (it == collection.end()) {
return 0;
}
return &it->second;
}
// Returns the pointer value associated with the given key. If none is found,
// NULL is returned. The function is designed to be used with a map of keys to
// pointers.
//
// This function does not distinguish between a missing key and a key mapped
// to a NULL value.
template <class Collection>
typename Collection::value_type::second_type
FindPtrOrNull(const Collection& collection,
const typename Collection::value_type::first_type& key) {
typename Collection::const_iterator it = collection.find(key);
if (it == collection.end()) {
return typename Collection::value_type::second_type();
}
return it->second;
}
// Same as above, except takes non-const reference to collection.
//
// This function is needed for containers that propagate constness to the
// pointee, such as boost::ptr_map.
template <class Collection>
typename Collection::value_type::second_type
FindPtrOrNull(Collection& collection, // NOLINT
const typename Collection::value_type::first_type& key) {
typename Collection::iterator it = collection.find(key);
if (it == collection.end()) {
return typename Collection::value_type::second_type();
}
return it->second;
}
// Finds the pointer value associated with the given key in a map whose values
// are linked_ptrs. Returns NULL if key is not found.
template <class Collection>
typename Collection::value_type::second_type::element_type*
FindLinkedPtrOrNull(const Collection& collection,
const typename Collection::value_type::first_type& key) {
typename Collection::const_iterator it = collection.find(key);
if (it == collection.end()) {
return 0;
}
// Since linked_ptr::get() is a const member returning a non const,
// we do not need a version of this function taking a non const collection.
return it->second.get();
}
// Same as above, but dies if the key is not found.
template <class Collection>
typename Collection::value_type::second_type::element_type&
FindLinkedPtrOrDie(const Collection& collection,
const typename Collection::value_type::first_type& key) {
typename Collection::const_iterator it = collection.find(key);
GOOGLE_CHECK(it != collection.end()) << "key not found: " << key;
// Since linked_ptr::operator*() is a const member returning a non const,
// we do not need a version of this function taking a non const collection.
return *it->second;
}
// Finds the value associated with the given key and copies it to *value (if not
// NULL). Returns false if the key was not found, true otherwise.
template <class Collection, class Key, class Value>
bool FindCopy(const Collection& collection,
const Key& key,
Value* const value) {
typename Collection::const_iterator it = collection.find(key);
if (it == collection.end()) {
return false;
}
if (value) {
*value = it->second;
}
return true;
}
//
// Contains*()
//
// Returns true if and only if the given collection contains the given key.
template <class Collection, class Key>
bool ContainsKey(const Collection& collection, const Key& key) {
return collection.find(key) != collection.end();
}
// Returns true if and only if the given collection contains the given key-value
// pair.
template <class Collection, class Key, class Value>
bool ContainsKeyValuePair(const Collection& collection,
const Key& key,
const Value& value) {
typedef typename Collection::const_iterator const_iterator;
std::pair<const_iterator, const_iterator> range = collection.equal_range(key);
for (const_iterator it = range.first; it != range.second; ++it) {
if (it->second == value) {
return true;
}
}
return false;
}
//
// Insert*()
//
// Inserts the given key-value pair into the collection. Returns true if and
// only if the key from the given pair didn't previously exist. Otherwise, the
// value in the map is replaced with the value from the given pair.
template <class Collection>
bool InsertOrUpdate(Collection* const collection,
const typename Collection::value_type& vt) {
std::pair<typename Collection::iterator, bool> ret = collection->insert(vt);
if (!ret.second) {
// update
ret.first->second = vt.second;
return false;
}
return true;
}
// Same as above, except that the key and value are passed separately.
template <class Collection>
bool InsertOrUpdate(Collection* const collection,
const typename Collection::value_type::first_type& key,
const typename Collection::value_type::second_type& value) {
return InsertOrUpdate(
collection, typename Collection::value_type(key, value));
}
// Inserts/updates all the key-value pairs from the range defined by the
// iterators "first" and "last" into the given collection.
template <class Collection, class InputIterator>
void InsertOrUpdateMany(Collection* const collection,
InputIterator first, InputIterator last) {
for (; first != last; ++first) {
InsertOrUpdate(collection, *first);
}
}
// Change the value associated with a particular key in a map or hash_map
// of the form map<Key, Value*> which owns the objects pointed to by the
// value pointers. If there was an existing value for the key, it is deleted.
// True indicates an insert took place, false indicates an update + delete.
template <class Collection>
bool InsertAndDeleteExisting(
Collection* const collection,
const typename Collection::value_type::first_type& key,
const typename Collection::value_type::second_type& value) {
std::pair<typename Collection::iterator, bool> ret =
collection->insert(typename Collection::value_type(key, value));
if (!ret.second) {
delete ret.first->second;
ret.first->second = value;
return false;
}
return true;
}
// Inserts the given key and value into the given collection if and only if the
// given key did NOT already exist in the collection. If the key previously
// existed in the collection, the value is not changed. Returns true if the
// key-value pair was inserted; returns false if the key was already present.
template <class Collection>
bool InsertIfNotPresent(Collection* const collection,
const typename Collection::value_type& vt) {
return collection->insert(vt).second;
}
// Same as above except the key and value are passed separately.
template <class Collection>
bool InsertIfNotPresent(
Collection* const collection,
const typename Collection::value_type::first_type& key,
const typename Collection::value_type::second_type& value) {
return InsertIfNotPresent(
collection, typename Collection::value_type(key, value));
}
// Same as above except dies if the key already exists in the collection.
template <class Collection>
void InsertOrDie(Collection* const collection,
const typename Collection::value_type& value) {
GOOGLE_CHECK(InsertIfNotPresent(collection, value))
<< "duplicate value: " << value;
}
// Same as above except doesn't log the value on error.
template <class Collection>
void InsertOrDieNoPrint(Collection* const collection,
const typename Collection::value_type& value) {
GOOGLE_CHECK(InsertIfNotPresent(collection, value)) << "duplicate value.";
}
// Inserts the key-value pair into the collection. Dies if key was already
// present.
template <class Collection>
void InsertOrDie(Collection* const collection,
const typename Collection::value_type::first_type& key,
const typename Collection::value_type::second_type& data) {
GOOGLE_CHECK(InsertIfNotPresent(collection, key, data))
<< "duplicate key: " << key;
}
// Same as above except doesn't log the key on error.
template <class Collection>
void InsertOrDieNoPrint(
Collection* const collection,
const typename Collection::value_type::first_type& key,
const typename Collection::value_type::second_type& data) {
GOOGLE_CHECK(InsertIfNotPresent(collection, key, data)) << "duplicate key.";
}
// Inserts a new key and default-initialized value. Dies if the key was already
// present. Returns a reference to the value. Example usage:
//
// map<int, SomeProto> m;
// SomeProto& proto = InsertKeyOrDie(&m, 3);
// proto.set_field("foo");
template <class Collection>
typename Collection::value_type::second_type& InsertKeyOrDie(
Collection* const collection,
const typename Collection::value_type::first_type& key) {
typedef typename Collection::value_type value_type;
std::pair<typename Collection::iterator, bool> res =
collection->insert(value_type(key, typename value_type::second_type()));
GOOGLE_CHECK(res.second) << "duplicate key: " << key;
return res.first->second;
}
//
// Lookup*()
//
// Looks up a given key and value pair in a collection and inserts the key-value
// pair if it's not already present. Returns a reference to the value associated
// with the key.
template <class Collection>
typename Collection::value_type::second_type&
LookupOrInsert(Collection* const collection,
const typename Collection::value_type& vt) {
return collection->insert(vt).first->second;
}
// Same as above except the key-value are passed separately.
template <class Collection>
typename Collection::value_type::second_type&
LookupOrInsert(Collection* const collection,
const typename Collection::value_type::first_type& key,
const typename Collection::value_type::second_type& value) {
return LookupOrInsert(
collection, typename Collection::value_type(key, value));
}
// Counts the number of equivalent elements in the given "sequence", and stores
// the results in "count_map" with element as the key and count as the value.
//
// Example:
// vector<string> v = {"a", "b", "c", "a", "b"};
// map<string, int> m;
// AddTokenCounts(v, 1, &m);
// assert(m["a"] == 2);
// assert(m["b"] == 2);
// assert(m["c"] == 1);
template <typename Sequence, typename Collection>
void AddTokenCounts(
const Sequence& sequence,
const typename Collection::value_type::second_type& increment,
Collection* const count_map) {
for (typename Sequence::const_iterator it = sequence.begin();
it != sequence.end(); ++it) {
typename Collection::value_type::second_type& value =
LookupOrInsert(count_map, *it,
typename Collection::value_type::second_type());
value += increment;
}
}
// Returns a reference to the value associated with key. If not found, a value
// is default constructed on the heap and added to the map.
//
// This function is useful for containers of the form map<Key, Value*>, where
// inserting a new key, value pair involves constructing a new heap-allocated
// Value, and storing a pointer to that in the collection.
template <class Collection>
typename Collection::value_type::second_type&
LookupOrInsertNew(Collection* const collection,
const typename Collection::value_type::first_type& key) {
typedef typename std::iterator_traits<
typename Collection::value_type::second_type>::value_type Element;
std::pair<typename Collection::iterator, bool> ret =
collection->insert(typename Collection::value_type(
key,
static_cast<typename Collection::value_type::second_type>(NULL)));
if (ret.second) {
ret.first->second = new Element();
}
return ret.first->second;
}
// Same as above but constructs the value using the single-argument constructor
// and the given "arg".
template <class Collection, class Arg>
typename Collection::value_type::second_type&
LookupOrInsertNew(Collection* const collection,
const typename Collection::value_type::first_type& key,
const Arg& arg) {
typedef typename std::iterator_traits<
typename Collection::value_type::second_type>::value_type Element;
std::pair<typename Collection::iterator, bool> ret =
collection->insert(typename Collection::value_type(
key,
static_cast<typename Collection::value_type::second_type>(NULL)));
if (ret.second) {
ret.first->second = new Element(arg);
}
return ret.first->second;
}
// Lookup of linked/shared pointers is used in two scenarios:
//
// Use LookupOrInsertNewLinkedPtr if the container owns the elements.
// In this case it is fine working with the raw pointer as long as it is
// guaranteed that no other thread can delete/update an accessed element.
// A mutex will need to lock the container operation as well as the use
// of the returned elements. Finding an element may be performed using
// FindLinkedPtr*().
//
// Use LookupOrInsertNewSharedPtr if the container does not own the elements
// for their whole lifetime. This is typically the case when a reader allows
// parallel updates to the container. In this case a Mutex only needs to lock
// container operations, but all element operations must be performed on the
// shared pointer. Finding an element must be performed using FindPtr*() and
// cannot be done with FindLinkedPtr*() even though it compiles.
// Lookup a key in a map or hash_map whose values are linked_ptrs. If it is
// missing, set collection[key].reset(new Value::element_type) and return that.
// Value::element_type must be default constructable.
template <class Collection>
typename Collection::value_type::second_type::element_type*
LookupOrInsertNewLinkedPtr(
Collection* const collection,
const typename Collection::value_type::first_type& key) {
typedef typename Collection::value_type::second_type Value;
std::pair<typename Collection::iterator, bool> ret =
collection->insert(typename Collection::value_type(key, Value()));
if (ret.second) {
ret.first->second.reset(new typename Value::element_type);
}
return ret.first->second.get();
}
// A variant of LookupOrInsertNewLinkedPtr where the value is constructed using
// a single-parameter constructor. Note: the constructor argument is computed
// even if it will not be used, so only values cheap to compute should be passed
// here. On the other hand it does not matter how expensive the construction of
// the actual stored value is, as that only occurs if necessary.
template <class Collection, class Arg>
typename Collection::value_type::second_type::element_type*
LookupOrInsertNewLinkedPtr(
Collection* const collection,
const typename Collection::value_type::first_type& key,
const Arg& arg) {
typedef typename Collection::value_type::second_type Value;
std::pair<typename Collection::iterator, bool> ret =
collection->insert(typename Collection::value_type(key, Value()));
if (ret.second) {
ret.first->second.reset(new typename Value::element_type(arg));
}
return ret.first->second.get();
}
// Lookup a key in a map or hash_map whose values are shared_ptrs. If it is
// missing, set collection[key].reset(new Value::element_type). Unlike
// LookupOrInsertNewLinkedPtr, this function returns the shared_ptr instead of
// the raw pointer. Value::element_type must be default constructable.
template <class Collection>
typename Collection::value_type::second_type&
LookupOrInsertNewSharedPtr(
Collection* const collection,
const typename Collection::value_type::first_type& key) {
typedef typename Collection::value_type::second_type SharedPtr;
typedef typename Collection::value_type::second_type::element_type Element;
std::pair<typename Collection::iterator, bool> ret =
collection->insert(typename Collection::value_type(key, SharedPtr()));
if (ret.second) {
ret.first->second.reset(new Element());
}
return ret.first->second;
}
// A variant of LookupOrInsertNewSharedPtr where the value is constructed using
// a single-parameter constructor. Note: the constructor argument is computed
// even if it will not be used, so only values cheap to compute should be passed
// here. On the other hand it does not matter how expensive the construction of
// the actual stored value is, as that only occurs if necessary.
template <class Collection, class Arg>
typename Collection::value_type::second_type&
LookupOrInsertNewSharedPtr(
Collection* const collection,
const typename Collection::value_type::first_type& key,
const Arg& arg) {
typedef typename Collection::value_type::second_type SharedPtr;
typedef typename Collection::value_type::second_type::element_type Element;
std::pair<typename Collection::iterator, bool> ret =
collection->insert(typename Collection::value_type(key, SharedPtr()));
if (ret.second) {
ret.first->second.reset(new Element(arg));
}
return ret.first->second;
}
//
// Misc Utility Functions
//
// Updates the value associated with the given key. If the key was not already
// present, then the key-value pair are inserted and "previous" is unchanged. If
// the key was already present, the value is updated and "*previous" will
// contain a copy of the old value.
//
// InsertOrReturnExisting has complementary behavior that returns the
// address of an already existing value, rather than updating it.
template <class Collection>
bool UpdateReturnCopy(Collection* const collection,
const typename Collection::value_type::first_type& key,
const typename Collection::value_type::second_type& value,
typename Collection::value_type::second_type* previous) {
std::pair<typename Collection::iterator, bool> ret =
collection->insert(typename Collection::value_type(key, value));
if (!ret.second) {
// update
if (previous) {
*previous = ret.first->second;
}
ret.first->second = value;
return true;
}
return false;
}
// Same as above except that the key and value are passed as a pair.
template <class Collection>
bool UpdateReturnCopy(Collection* const collection,
const typename Collection::value_type& vt,
typename Collection::value_type::second_type* previous) {
std::pair<typename Collection::iterator, bool> ret = collection->insert(vt);
if (!ret.second) {
// update
if (previous) {
*previous = ret.first->second;
}
ret.first->second = vt.second;
return true;
}
return false;
}
// Tries to insert the given key-value pair into the collection. Returns NULL if
// the insert succeeds. Otherwise, returns a pointer to the existing value.
//
// This complements UpdateReturnCopy in that it allows to update only after
// verifying the old value and still insert quickly without having to look up
// twice. Unlike UpdateReturnCopy this also does not come with the issue of an
// undefined previous* in case new data was inserted.
template <class Collection>
typename Collection::value_type::second_type* const
InsertOrReturnExisting(Collection* const collection,
const typename Collection::value_type& vt) {
std::pair<typename Collection::iterator, bool> ret = collection->insert(vt);
if (ret.second) {
return NULL; // Inserted, no existing previous value.
} else {
return &ret.first->second; // Return address of already existing value.
}
}
// Same as above, except for explicit key and data.
template <class Collection>
typename Collection::value_type::second_type* const
InsertOrReturnExisting(
Collection* const collection,
const typename Collection::value_type::first_type& key,
const typename Collection::value_type::second_type& data) {
return InsertOrReturnExisting(collection,
typename Collection::value_type(key, data));
}
// Erases the collection item identified by the given key, and returns the value
// associated with that key. It is assumed that the value (i.e., the
// mapped_type) is a pointer. Returns NULL if the key was not found in the
// collection.
//
// Examples:
// map<string, MyType*> my_map;
//
// One line cleanup:
// delete EraseKeyReturnValuePtr(&my_map, "abc");
//
// Use returned value:
// std::unique_ptr<MyType> value_ptr(
// EraseKeyReturnValuePtr(&my_map, "abc"));
// if (value_ptr.get())
// value_ptr->DoSomething();
//
template <class Collection>
typename Collection::value_type::second_type EraseKeyReturnValuePtr(
Collection* const collection,
const typename Collection::value_type::first_type& key) {
typename Collection::iterator it = collection->find(key);
if (it == collection->end()) {
return NULL;
}
typename Collection::value_type::second_type v = it->second;
collection->erase(it);
return v;
}
// Inserts all the keys from map_container into key_container, which must
// support insert(MapContainer::key_type).
//
// Note: any initial contents of the key_container are not cleared.
template <class MapContainer, class KeyContainer>
void InsertKeysFromMap(const MapContainer& map_container,
KeyContainer* key_container) {
GOOGLE_CHECK(key_container != NULL);
for (typename MapContainer::const_iterator it = map_container.begin();
it != map_container.end(); ++it) {
key_container->insert(it->first);
}
}
// Appends all the keys from map_container into key_container, which must
// support push_back(MapContainer::key_type).
//
// Note: any initial contents of the key_container are not cleared.
template <class MapContainer, class KeyContainer>
void AppendKeysFromMap(const MapContainer& map_container,
KeyContainer* key_container) {
GOOGLE_CHECK(key_container != NULL);
for (typename MapContainer::const_iterator it = map_container.begin();
it != map_container.end(); ++it) {
key_container->push_back(it->first);
}
}
// A more specialized overload of AppendKeysFromMap to optimize reallocations
// for the common case in which we're appending keys to a vector and hence can
// (and sometimes should) call reserve() first.
//
// (It would be possible to play SFINAE games to call reserve() for any
// container that supports it, but this seems to get us 99% of what we need
// without the complexity of a SFINAE-based solution.)
template <class MapContainer, class KeyType>
void AppendKeysFromMap(const MapContainer& map_container,
std::vector<KeyType>* key_container) {
GOOGLE_CHECK(key_container != NULL);
// We now have the opportunity to call reserve(). Calling reserve() every
// time is a bad idea for some use cases: libstdc++'s implementation of
// vector<>::reserve() resizes the vector's backing store to exactly the
// given size (unless it's already at least that big). Because of this,
// the use case that involves appending a lot of small maps (total size
// N) one by one to a vector would be O(N^2). But never calling reserve()
// loses the opportunity to improve the use case of adding from a large
// map to an empty vector (this improves performance by up to 33%). A
// number of heuristics are possible; see the discussion in
// cl/34081696. Here we use the simplest one.
if (key_container->empty()) {
key_container->reserve(map_container.size());
}
for (typename MapContainer::const_iterator it = map_container.begin();
it != map_container.end(); ++it) {
key_container->push_back(it->first);
}
}
// Inserts all the values from map_container into value_container, which must
// support push_back(MapContainer::mapped_type).
//
// Note: any initial contents of the value_container are not cleared.
template <class MapContainer, class ValueContainer>
void AppendValuesFromMap(const MapContainer& map_container,
ValueContainer* value_container) {
GOOGLE_CHECK(value_container != NULL);
for (typename MapContainer::const_iterator it = map_container.begin();
it != map_container.end(); ++it) {
value_container->push_back(it->second);
}
}
// A more specialized overload of AppendValuesFromMap to optimize reallocations
// for the common case in which we're appending values to a vector and hence
// can (and sometimes should) call reserve() first.
//
// (It would be possible to play SFINAE games to call reserve() for any
// container that supports it, but this seems to get us 99% of what we need
// without the complexity of a SFINAE-based solution.)
template <class MapContainer, class ValueType>
void AppendValuesFromMap(const MapContainer& map_container,
std::vector<ValueType>* value_container) {
GOOGLE_CHECK(value_container != NULL);
// See AppendKeysFromMap for why this is done.
if (value_container->empty()) {
value_container->reserve(map_container.size());
}
for (typename MapContainer::const_iterator it = map_container.begin();
it != map_container.end(); ++it) {
value_container->push_back(it->second);
}
}
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_STUBS_MAP_UTIL_H__

View File

@ -0,0 +1,303 @@
// 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.
// All Rights Reserved.
//
// Author: Maxim Lifantsev
//
// Useful integer and floating point limits and type traits.
//
// This partially replaces/duplictes numeric_limits<> from <limits>.
// We get a Google-style class that we have a greater control over
// and thus can add new features to it or fix whatever happens to be broken in
// numeric_limits for the compilers we use.
//
#ifndef UTIL_MATH_MATHLIMITS_H__
#define UTIL_MATH_MATHLIMITS_H__
// Note that for Windows we do something different because it does not support
// the plain isinf and isnan.
#if __cplusplus >= 201103L
// GCC 4.9 has a bug that makes isinf and isnan ambigious when both <math.h>
// and <cmath> get pulled into the same translation unit. We use the ones in
// std:: namespace explicitly for C++11
#include <cmath>
#define GOOGLE_PROTOBUF_USE_STD_CMATH
#elif _GLIBCXX_USE_C99_MATH && !_GLIBCXX_USE_C99_FP_MACROS_DYNAMIC
// libstdc++ <cmath> header undefines the global macros and put functions in
// std:: namespace even before C++11. Use the ones in std:: instead too.
#include <cmath>
#define GOOGLE_PROTOBUF_USE_STD_CMATH
#else
#include <math.h>
#endif
#include <string.h>
#include <cfloat>
#include <google/protobuf/stubs/common.h>
// ========================================================================= //
// Useful integer and floating point limits and type traits.
// This is just for the documentation;
// real members are defined in our specializations below.
namespace google {
namespace protobuf {
template<typename T> struct MathLimits {
// Type name.
typedef T Type;
// Unsigned version of the Type with the same byte size.
// Same as Type for floating point and unsigned types.
typedef T UnsignedType;
// If the type supports negative values.
static const bool kIsSigned;
// If the type supports only integer values.
static const bool kIsInteger;
// Magnitude-wise smallest representable positive value.
static const Type kPosMin;
// Magnitude-wise largest representable positive value.
static const Type kPosMax;
// Smallest representable value.
static const Type kMin;
// Largest representable value.
static const Type kMax;
// Magnitude-wise smallest representable negative value.
// Present only if kIsSigned.
static const Type kNegMin;
// Magnitude-wise largest representable negative value.
// Present only if kIsSigned.
static const Type kNegMax;
// Smallest integer x such that 10^x is representable.
static const int kMin10Exp;
// Largest integer x such that 10^x is representable.
static const int kMax10Exp;
// Smallest positive value such that Type(1) + kEpsilon != Type(1)
static const Type kEpsilon;
// Typical rounding error that is enough to cover
// a few simple floating-point operations.
// Slightly larger than kEpsilon to account for a few rounding errors.
// Is zero if kIsInteger.
static const Type kStdError;
// Number of decimal digits of mantissa precision.
// Present only if !kIsInteger.
static const int kPrecisionDigits;
// Not a number, i.e. result of 0/0.
// Present only if !kIsInteger.
static const Type kNaN;
// Positive infinity, i.e. result of 1/0.
// Present only if !kIsInteger.
static const Type kPosInf;
// Negative infinity, i.e. result of -1/0.
// Present only if !kIsInteger.
static const Type kNegInf;
// NOTE: Special floating point values behave
// in a special (but mathematically-logical) way
// in terms of (in)equalty comparison and mathematical operations
// -- see out unittest for examples.
// Special floating point value testers.
// Present in integer types for convenience.
static bool IsFinite(const Type x);
static bool IsNaN(const Type x);
static bool IsInf(const Type x);
static bool IsPosInf(const Type x);
static bool IsNegInf(const Type x);
};
// ========================================================================= //
// All #define-s below are simply to refactor the declarations of
// MathLimits template specializations.
// They are all #undef-ined below.
// The hoop-jumping in *_INT_(MAX|MIN) below is so that the compiler does not
// get an overflow while computing the constants.
#define SIGNED_INT_MAX(Type) \
(((Type(1) << (sizeof(Type)*8 - 2)) - 1) + (Type(1) << (sizeof(Type)*8 - 2)))
#define SIGNED_INT_MIN(Type) \
(-(Type(1) << (sizeof(Type)*8 - 2)) - (Type(1) << (sizeof(Type)*8 - 2)))
#define UNSIGNED_INT_MAX(Type) \
(((Type(1) << (sizeof(Type)*8 - 1)) - 1) + (Type(1) << (sizeof(Type)*8 - 1)))
// Compile-time selected log10-related constants for integer types.
#define SIGNED_MAX_10_EXP(Type) \
(sizeof(Type) == 1 ? 2 : ( \
sizeof(Type) == 2 ? 4 : ( \
sizeof(Type) == 4 ? 9 : ( \
sizeof(Type) == 8 ? 18 : -1))))
#define UNSIGNED_MAX_10_EXP(Type) \
(sizeof(Type) == 1 ? 2 : ( \
sizeof(Type) == 2 ? 4 : ( \
sizeof(Type) == 4 ? 9 : ( \
sizeof(Type) == 8 ? 19 : -1))))
#define DECL_INT_LIMIT_FUNCS \
static bool IsFinite(const Type /*x*/) { return true; } \
static bool IsNaN(const Type /*x*/) { return false; } \
static bool IsInf(const Type /*x*/) { return false; } \
static bool IsPosInf(const Type /*x*/) { return false; } \
static bool IsNegInf(const Type /*x*/) { return false; }
#define DECL_SIGNED_INT_LIMITS(IntType, UnsignedIntType) \
template<> \
struct LIBPROTOBUF_EXPORT MathLimits<IntType> { \
typedef IntType Type; \
typedef UnsignedIntType UnsignedType; \
static const bool kIsSigned = true; \
static const bool kIsInteger = true; \
static const Type kPosMin = 1; \
static const Type kPosMax = SIGNED_INT_MAX(Type); \
static const Type kMin = SIGNED_INT_MIN(Type); \
static const Type kMax = kPosMax; \
static const Type kNegMin = -1; \
static const Type kNegMax = kMin; \
static const int kMin10Exp = 0; \
static const int kMax10Exp = SIGNED_MAX_10_EXP(Type); \
static const Type kEpsilon = 1; \
static const Type kStdError = 0; \
DECL_INT_LIMIT_FUNCS \
};
#define DECL_UNSIGNED_INT_LIMITS(IntType) \
template<> \
struct LIBPROTOBUF_EXPORT MathLimits<IntType> { \
typedef IntType Type; \
typedef IntType UnsignedType; \
static const bool kIsSigned = false; \
static const bool kIsInteger = true; \
static const Type kPosMin = 1; \
static const Type kPosMax = UNSIGNED_INT_MAX(Type); \
static const Type kMin = 0; \
static const Type kMax = kPosMax; \
static const int kMin10Exp = 0; \
static const int kMax10Exp = UNSIGNED_MAX_10_EXP(Type); \
static const Type kEpsilon = 1; \
static const Type kStdError = 0; \
DECL_INT_LIMIT_FUNCS \
};
DECL_SIGNED_INT_LIMITS(signed char, unsigned char)
DECL_SIGNED_INT_LIMITS(signed short int, unsigned short int)
DECL_SIGNED_INT_LIMITS(signed int, unsigned int)
DECL_SIGNED_INT_LIMITS(signed long int, unsigned long int)
DECL_SIGNED_INT_LIMITS(signed long long int, unsigned long long int)
DECL_UNSIGNED_INT_LIMITS(unsigned char)
DECL_UNSIGNED_INT_LIMITS(unsigned short int)
DECL_UNSIGNED_INT_LIMITS(unsigned int)
DECL_UNSIGNED_INT_LIMITS(unsigned long int)
DECL_UNSIGNED_INT_LIMITS(unsigned long long int)
#undef DECL_SIGNED_INT_LIMITS
#undef DECL_UNSIGNED_INT_LIMITS
#undef SIGNED_INT_MAX
#undef SIGNED_INT_MIN
#undef UNSIGNED_INT_MAX
#undef SIGNED_MAX_10_EXP
#undef UNSIGNED_MAX_10_EXP
#undef DECL_INT_LIMIT_FUNCS
// For non-Windows builds we use the std:: versions of isinf and isnan if they
// are available; see the comment about <cmath> at the top of this file for the
// details on why we need to do this.
#ifdef GOOGLE_PROTOBUF_USE_STD_CMATH
#define ISINF std::isinf
#define ISNAN std::isnan
#else
#define ISINF isinf
#define ISNAN isnan
#endif
// ========================================================================= //
#if WIN32 && !__MINGW32__ // Lacks built-in isnan() and isinf()
#define DECL_FP_LIMIT_FUNCS \
static bool IsFinite(const Type x) { return _finite(x); } \
static bool IsNaN(const Type x) { return _isnan(x); } \
static bool IsInf(const Type x) { return (_fpclass(x) & (_FPCLASS_NINF | _FPCLASS_PINF)) != 0; } \
static bool IsPosInf(const Type x) { return _fpclass(x) == _FPCLASS_PINF; } \
static bool IsNegInf(const Type x) { return _fpclass(x) == _FPCLASS_NINF; }
#else
#define DECL_FP_LIMIT_FUNCS \
static bool IsFinite(const Type x) { return !ISINF(x) && !ISNAN(x); } \
static bool IsNaN(const Type x) { return ISNAN(x); } \
static bool IsInf(const Type x) { return ISINF(x); } \
static bool IsPosInf(const Type x) { return ISINF(x) && x > 0; } \
static bool IsNegInf(const Type x) { return ISINF(x) && x < 0; }
#endif
// We can't put floating-point constant values in the header here because
// such constants are not considered to be primitive-type constants by gcc.
// CAVEAT: Hence, they are going to be initialized only during
// the global objects construction time.
#define DECL_FP_LIMITS(FP_Type, PREFIX) \
template<> \
struct LIBPROTOBUF_EXPORT MathLimits<FP_Type> { \
typedef FP_Type Type; \
typedef FP_Type UnsignedType; \
static const bool kIsSigned = true; \
static const bool kIsInteger = false; \
static const Type kPosMin; \
static const Type kPosMax; \
static const Type kMin; \
static const Type kMax; \
static const Type kNegMin; \
static const Type kNegMax; \
static const int kMin10Exp = PREFIX##_MIN_10_EXP; \
static const int kMax10Exp = PREFIX##_MAX_10_EXP; \
static const Type kEpsilon; \
static const Type kStdError; \
static const int kPrecisionDigits = PREFIX##_DIG; \
static const Type kNaN; \
static const Type kPosInf; \
static const Type kNegInf; \
DECL_FP_LIMIT_FUNCS \
};
DECL_FP_LIMITS(float, FLT)
DECL_FP_LIMITS(double, DBL)
DECL_FP_LIMITS(long double, LDBL)
#undef ISINF
#undef ISNAN
#undef DECL_FP_LIMITS
#undef DECL_FP_LIMIT_FUNCS
// ========================================================================= //
} // namespace protobuf
} // namespace google
#endif // UTIL_MATH_MATHLIMITS_H__

View File

@ -0,0 +1,130 @@
// Copyright (c) 2006, Google Inc.
// All rights reserved.
//
// 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_STUBS_MUTEX_H_
#define GOOGLE_PROTOBUF_STUBS_MUTEX_H_
#include <mutex>
#include <google/protobuf/stubs/macros.h>
// ===================================================================
// emulates google3/base/mutex.h
namespace google {
namespace protobuf {
namespace internal {
#define GOOGLE_PROTOBUF_LINKER_INITIALIZED
// Mutex is a natural type to wrap. As both google and other organization have
// specialized mutexes. gRPC also provides an injection mechanism for custom
// mutexes.
class LIBPROTOBUF_EXPORT WrappedMutex {
public:
WrappedMutex() = default;
void Lock() { mu_.lock(); }
void Unlock() { mu_.unlock(); }
// Crash if this Mutex is not held exclusively by this thread.
// May fail to crash when it should; will never crash when it should not.
void AssertHeld() const {}
private:
std::mutex mu_;
};
using Mutex = WrappedMutex;
// MutexLock(mu) acquires mu when constructed and releases it when destroyed.
class LIBPROTOBUF_EXPORT MutexLock {
public:
explicit MutexLock(Mutex *mu) : mu_(mu) { this->mu_->Lock(); }
~MutexLock() { this->mu_->Unlock(); }
private:
Mutex *const mu_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MutexLock);
};
// TODO(kenton): Implement these? Hard to implement portably.
typedef MutexLock ReaderMutexLock;
typedef MutexLock WriterMutexLock;
// MutexLockMaybe is like MutexLock, but is a no-op when mu is NULL.
class LIBPROTOBUF_EXPORT MutexLockMaybe {
public:
explicit MutexLockMaybe(Mutex *mu) :
mu_(mu) { if (this->mu_ != NULL) { this->mu_->Lock(); } }
~MutexLockMaybe() { if (this->mu_ != NULL) { this->mu_->Unlock(); } }
private:
Mutex *const mu_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MutexLockMaybe);
};
#if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
template<typename T>
class ThreadLocalStorage {
public:
ThreadLocalStorage() {
pthread_key_create(&key_, &ThreadLocalStorage::Delete);
}
~ThreadLocalStorage() {
pthread_key_delete(key_);
}
T* Get() {
T* result = static_cast<T*>(pthread_getspecific(key_));
if (result == NULL) {
result = new T();
pthread_setspecific(key_, result);
}
return result;
}
private:
static void Delete(void* value) {
delete static_cast<T*>(value);
}
pthread_key_t key_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ThreadLocalStorage);
};
#endif
} // namespace internal
// We made these internal so that they would show up as such in the docs,
// but we don't want to stick "internal::" in front of them everywhere.
using internal::Mutex;
using internal::MutexLock;
using internal::ReaderMutexLock;
using internal::WriterMutexLock;
using internal::MutexLockMaybe;
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_STUBS_MUTEX_H_

View File

@ -0,0 +1,157 @@
// 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)
//
// emulates google3/base/once.h
//
// This header is intended to be included only by internal .cc files and
// generated .pb.cc files. Users should not use this directly.
//
// This is basically a portable version of pthread_once().
//
// This header declares:
// * A type called ProtobufOnceType.
// * A macro GOOGLE_PROTOBUF_DECLARE_ONCE() which declares a variable of type
// ProtobufOnceType. This is the only legal way to declare such a variable.
// The macro may only be used at the global scope (you cannot create local or
// class member variables of this type).
// * A function GoogleOnceInit(ProtobufOnceType* once, void (*init_func)()).
// This function, when invoked multiple times given the same ProtobufOnceType
// object, will invoke init_func on the first call only, and will make sure
// none of the calls return before that first call to init_func has finished.
// * The user can provide a parameter which GoogleOnceInit() forwards to the
// user-provided function when it is called. Usage example:
// int a = 10;
// GoogleOnceInit(&my_once, &MyFunctionExpectingIntArgument, &a);
// * This implementation guarantees that ProtobufOnceType is a POD (i.e. no
// static initializer generated).
//
// This implements a way to perform lazy initialization. It's more efficient
// than using mutexes as no lock is needed if initialization has already
// happened.
//
// Example usage:
// void Init();
// GOOGLE_PROTOBUF_DECLARE_ONCE(once_init);
//
// // Calls Init() exactly once.
// void InitOnce() {
// GoogleOnceInit(&once_init, &Init);
// }
//
// Note that if GoogleOnceInit() is called before main() has begun, it must
// only be called by the thread that will eventually call main() -- that is,
// the thread that performs dynamic initialization. In general this is a safe
// assumption since people don't usually construct threads before main() starts,
// but it is technically not guaranteed. Unfortunately, Win32 provides no way
// whatsoever to statically-initialize its synchronization primitives, so our
// only choice is to assume that dynamic initialization is single-threaded.
#ifndef GOOGLE_PROTOBUF_STUBS_ONCE_H__
#define GOOGLE_PROTOBUF_STUBS_ONCE_H__
#include <sched.h>
#include <atomic>
#include <mutex>
#include <utility>
namespace google {
namespace protobuf {
namespace internal {
using once_flag = std::atomic<int>;
template <typename Callable, typename... Args>
void my_call_once(once_flag& once, Callable&& fn, Args&&... args) {
enum CallOnceState {
ONCE_INIT = 0,
ONCE_RUNNING = 1,
ONCE_DONE = 2,
};
int expected_state = ONCE_INIT;
if (once.compare_exchange_strong(expected_state, ONCE_RUNNING)) {
fn(std::forward<Args>(args)...);
once.store(ONCE_DONE);
return;
}
if (expected_state == ONCE_DONE) {
return;
}
while (once.load() == ONCE_RUNNING) {
sched_yield();
}
}
template <typename... Args>
void call_once(Args&&... args) {
my_call_once(std::forward<Args>(args)...);
}
} // namespace internal
// TODO(gerbens) remove this once third_party is fully extracted
using ProtobufOnceType = internal::once_flag;
inline void GoogleOnceInit(ProtobufOnceType* once, void (*init_func)()) {
internal::my_call_once(*once, init_func);
}
template <typename Arg>
inline void GoogleOnceInitArg(ProtobufOnceType* once, void (*init_func)(Arg*),
Arg* arg) {
internal::my_call_once(*once, init_func, arg);
}
class GoogleOnceDynamic {
public:
// If this->Init() has not been called before by any thread,
// execute (*func_with_arg)(arg) then return.
// Otherwise, wait until that prior invocation has finished
// executing its function, then return.
template <typename T>
void Init(void (*func_with_arg)(T*), T* arg) {
GoogleOnceInitArg<T>(&this->state_, func_with_arg, arg);
}
private:
ProtobufOnceType state_;
};
#define GOOGLE_PROTOBUF_ONCE_TYPE ::google::protobuf::ProtobufOnceType
#define GOOGLE_PROTOBUF_DECLARE_ONCE(NAME) \
::google::protobuf::ProtobufOnceType NAME
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_STUBS_ONCE_H__

View File

@ -0,0 +1,130 @@
// 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)
//
// emulates google3/base/once.h
//
// This header is intended to be included only by internal .cc files and
// generated .pb.cc files. Users should not use this directly.
//
// This is basically a portable version of pthread_once().
//
// This header declares:
// * A type called ProtobufOnceType.
// * A macro GOOGLE_PROTOBUF_DECLARE_ONCE() which declares a variable of type
// ProtobufOnceType. This is the only legal way to declare such a variable.
// The macro may only be used at the global scope (you cannot create local or
// class member variables of this type).
// * A function GoogleOnceInit(ProtobufOnceType* once, void (*init_func)()).
// This function, when invoked multiple times given the same ProtobufOnceType
// object, will invoke init_func on the first call only, and will make sure
// none of the calls return before that first call to init_func has finished.
// * The user can provide a parameter which GoogleOnceInit() forwards to the
// user-provided function when it is called. Usage example:
// int a = 10;
// GoogleOnceInit(&my_once, &MyFunctionExpectingIntArgument, &a);
// * This implementation guarantees that ProtobufOnceType is a POD (i.e. no
// static initializer generated).
//
// This implements a way to perform lazy initialization. It's more efficient
// than using mutexes as no lock is needed if initialization has already
// happened.
//
// Example usage:
// void Init();
// GOOGLE_PROTOBUF_DECLARE_ONCE(once_init);
//
// // Calls Init() exactly once.
// void InitOnce() {
// GoogleOnceInit(&once_init, &Init);
// }
//
// Note that if GoogleOnceInit() is called before main() has begun, it must
// only be called by the thread that will eventually call main() -- that is,
// the thread that performs dynamic initialization. In general this is a safe
// assumption since people don't usually construct threads before main() starts,
// but it is technically not guaranteed. Unfortunately, Win32 provides no way
// whatsoever to statically-initialize its synchronization primitives, so our
// only choice is to assume that dynamic initialization is single-threaded.
#ifndef GOOGLE_PROTOBUF_STUBS_ONCE_H__
#define GOOGLE_PROTOBUF_STUBS_ONCE_H__
#include <mutex>
#include <utility>
namespace google {
namespace protobuf {
namespace internal {
using once_flag = std::once_flag;
template <typename... Args>
void call_once(Args&&... args ) {
std::call_once(std::forward<Args>(args)...);
}
} // namespace internal
// TODO(gerbens) remove this once third_party is fully extracted
using ProtobufOnceType = internal::once_flag;
inline void GoogleOnceInit(ProtobufOnceType* once, void (*init_func)()) {
std::call_once(*once, init_func);
}
template <typename Arg>
inline void GoogleOnceInitArg(ProtobufOnceType* once, void (*init_func)(Arg*),
Arg* arg) {
std::call_once(*once, init_func, arg);
}
class GoogleOnceDynamic {
public:
// If this->Init() has not been called before by any thread,
// execute (*func_with_arg)(arg) then return.
// Otherwise, wait until that prior invocation has finished
// executing its function, then return.
template<typename T>
void Init(void (*func_with_arg)(T*), T* arg) {
GoogleOnceInitArg<T>(&this->state_, func_with_arg, arg);
}
private:
ProtobufOnceType state_;
};
#define GOOGLE_PROTOBUF_ONCE_TYPE ::google::protobuf::ProtobufOnceType
#define GOOGLE_PROTOBUF_DECLARE_ONCE(NAME) \
::google::protobuf::ProtobufOnceType NAME
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_STUBS_ONCE_H__

View File

@ -0,0 +1,128 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2012 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_PLATFORM_MACROS_H_
#define GOOGLE_PROTOBUF_PLATFORM_MACROS_H_
#define GOOGLE_PROTOBUF_PLATFORM_ERROR \
#error "Host platform was not detected as supported by protobuf"
// Processor architecture detection. For more info on what's defined, see:
// http://msdn.microsoft.com/en-us/library/b0084kay.aspx
// http://www.agner.org/optimize/calling_conventions.pdf
// or with gcc, run: "echo | gcc -E -dM -"
#if defined(_M_X64) || defined(__x86_64__)
#define GOOGLE_PROTOBUF_ARCH_X64 1
#define GOOGLE_PROTOBUF_ARCH_64_BIT 1
#elif defined(_M_IX86) || defined(__i386__)
#define GOOGLE_PROTOBUF_ARCH_IA32 1
#define GOOGLE_PROTOBUF_ARCH_32_BIT 1
#elif defined(__QNX__)
#define GOOGLE_PROTOBUF_ARCH_ARM_QNX 1
#define GOOGLE_PROTOBUF_ARCH_32_BIT 1
#elif defined(_M_ARM) || defined(__ARMEL__)
#define GOOGLE_PROTOBUF_ARCH_ARM 1
#define GOOGLE_PROTOBUF_ARCH_32_BIT 1
#elif defined(_M_ARM64)
#define GOOGLE_PROTOBUF_ARCH_ARM 1
#define GOOGLE_PROTOBUF_ARCH_64_BIT 1
#elif defined(__aarch64__)
#define GOOGLE_PROTOBUF_ARCH_AARCH64 1
#define GOOGLE_PROTOBUF_ARCH_64_BIT 1
#elif defined(__MIPSEL__)
#if defined(__LP64__)
#define GOOGLE_PROTOBUF_ARCH_MIPS64 1
#define GOOGLE_PROTOBUF_ARCH_64_BIT 1
#else
#define GOOGLE_PROTOBUF_ARCH_MIPS 1
#define GOOGLE_PROTOBUF_ARCH_32_BIT 1
#endif
#elif defined(__pnacl__)
#define GOOGLE_PROTOBUF_ARCH_32_BIT 1
#elif defined(sparc)
#define GOOGLE_PROTOBUF_ARCH_SPARC 1
#if defined(__sparc_v9__) || defined(__sparcv9) || defined(__arch64__)
#define GOOGLE_PROTOBUF_ARCH_64_BIT 1
#else
#define GOOGLE_PROTOBUF_ARCH_32_BIT 1
#endif
#elif defined(_POWER) || defined(__powerpc64__) || defined(__PPC64__)
#define GOOGLE_PROTOBUF_ARCH_POWER 1
#define GOOGLE_PROTOBUF_ARCH_64_BIT 1
#elif defined(__PPC__)
#define GOOGLE_PROTOBUF_ARCH_PPC 1
#define GOOGLE_PROTOBUF_ARCH_32_BIT 1
#elif defined(__GNUC__)
# if (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4))
// We fallback to the generic Clang/GCC >= 4.7 implementation in atomicops.h
# elif defined(__clang__)
# if !__has_extension(c_atomic)
GOOGLE_PROTOBUF_PLATFORM_ERROR
# endif
// We fallback to the generic Clang/GCC >= 4.7 implementation in atomicops.h
# endif
# if __LP64__
# define GOOGLE_PROTOBUF_ARCH_64_BIT 1
# else
# define GOOGLE_PROTOBUF_ARCH_32_BIT 1
# endif
#else
GOOGLE_PROTOBUF_PLATFORM_ERROR
#endif
#if defined(__APPLE__)
#define GOOGLE_PROTOBUF_OS_APPLE
#include <TargetConditionals.h>
#if TARGET_OS_IPHONE
#define GOOGLE_PROTOBUF_OS_IPHONE
#endif
#elif defined(__EMSCRIPTEN__)
#define GOOGLE_PROTOBUF_OS_EMSCRIPTEN
#elif defined(__native_client__)
#define GOOGLE_PROTOBUF_OS_NACL
#elif defined(sun)
#define GOOGLE_PROTOBUF_OS_SOLARIS
#elif defined(_AIX)
#define GOOGLE_PROTOBUF_OS_AIX
#elif defined(__ANDROID__)
#define GOOGLE_PROTOBUF_OS_ANDROID
#endif
#undef GOOGLE_PROTOBUF_PLATFORM_ERROR
#if defined(GOOGLE_PROTOBUF_OS_ANDROID) || defined(GOOGLE_PROTOBUF_OS_IPHONE) || defined(__OpenBSD__)
// Android ndk does not support the __thread keyword very well yet. Here
// we use pthread_key_create()/pthread_getspecific()/... methods for
// TLS support on android.
// iOS and OpenBSD also do not support the __thread keyword.
#define GOOGLE_PROTOBUF_NO_THREADLOCAL
#endif
#endif // GOOGLE_PROTOBUF_PLATFORM_MACROS_H_

View File

@ -0,0 +1,542 @@
// 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_STUBS_PORT_H_
#define GOOGLE_PROTOBUF_STUBS_PORT_H_
#include <assert.h>
#include <stdlib.h>
#include <cstddef>
#include <string>
#include <string.h>
#if defined(__osf__)
// Tru64 lacks stdint.h, but has inttypes.h which defines a superset of
// what stdint.h would define.
#include <inttypes.h>
#elif !defined(_MSC_VER)
#include <stdint.h>
#endif
#include <google/protobuf/stubs/platform_macros.h>
#undef PROTOBUF_LITTLE_ENDIAN
#ifdef _WIN32
// Assuming windows is always little-endian.
// TODO(xiaofeng): The PROTOBUF_LITTLE_ENDIAN is not only used for
// optimization but also for correctness. We should define an
// different macro to test the big-endian code path in coded_stream.
#if !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST)
#define PROTOBUF_LITTLE_ENDIAN 1
#endif
#if _MSC_VER >= 1300 && !defined(__INTEL_COMPILER)
// If MSVC has "/RTCc" set, it will complain about truncating casts at
// runtime. This file contains some intentional truncating casts.
#pragma runtime_checks("c", off)
#endif
#else
#include <sys/param.h> // __BYTE_ORDER
#if defined(__OpenBSD__)
#include <endian.h>
#endif
#if ((defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)) || \
(defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN) || \
(defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN)) && \
!defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST)
#define PROTOBUF_LITTLE_ENDIAN 1
#endif
#endif
#if defined(_MSC_VER) && defined(PROTOBUF_USE_DLLS)
#ifdef LIBPROTOBUF_EXPORTS
#define LIBPROTOBUF_EXPORT __declspec(dllexport)
#else
#define LIBPROTOBUF_EXPORT __declspec(dllimport)
#endif
#ifdef LIBPROTOC_EXPORTS
#define LIBPROTOC_EXPORT __declspec(dllexport)
#else
#define LIBPROTOC_EXPORT __declspec(dllimport)
#endif
#else
#define LIBPROTOBUF_EXPORT
#define LIBPROTOC_EXPORT
#endif
// These #includes are for the byte swap functions declared later on.
#ifdef _MSC_VER
#include <stdlib.h> // NOLINT(build/include)
#include <intrin.h>
#elif defined(__APPLE__)
#include <libkern/OSByteOrder.h>
#elif defined(__GLIBC__) || defined(__BIONIC__) || defined(__CYGWIN__)
#include <byteswap.h> // IWYU pragma: export
#endif
#define PROTOBUF_RUNTIME_DEPRECATED(message)
// ===================================================================
// from google3/base/port.h
#if (defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L || \
(defined(_MSC_VER) && _MSC_VER >= 1900))
// Define this to 1 if the code is compiled in C++11 mode; leave it
// undefined otherwise. Do NOT define it to 0 -- that causes
// '#ifdef LANG_CXX11' to behave differently from '#if LANG_CXX11'.
#define LANG_CXX11 1
#endif
#if LANG_CXX11 && !defined(__NVCC__)
#define PROTOBUF_CXX11 1
#else
#define PROTOBUF_CXX11 0
#endif
#if PROTOBUF_CXX11
#define PROTOBUF_FINAL final
#else
#define PROTOBUF_FINAL
#endif
namespace google {
namespace protobuf {
typedef unsigned int uint;
#ifdef _MSC_VER
typedef signed __int8 int8;
typedef __int16 int16;
typedef __int32 int32;
typedef __int64 int64;
typedef unsigned __int8 uint8;
typedef unsigned __int16 uint16;
typedef unsigned __int32 uint32;
typedef unsigned __int64 uint64;
#else
typedef int8_t int8;
typedef int16_t int16;
typedef int32_t int32;
typedef int64_t int64;
typedef uint8_t uint8;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
#endif
// long long macros to be used because gcc and vc++ use different suffixes,
// and different size specifiers in format strings
#undef GOOGLE_LONGLONG
#undef GOOGLE_ULONGLONG
#undef GOOGLE_LL_FORMAT
#ifdef _MSC_VER
#define GOOGLE_LONGLONG(x) x##I64
#define GOOGLE_ULONGLONG(x) x##UI64
#define GOOGLE_LL_FORMAT "I64" // As in printf("%I64d", ...)
#else
// By long long, we actually mean int64.
#define GOOGLE_LONGLONG(x) x##LL
#define GOOGLE_ULONGLONG(x) x##ULL
// Used to format real long long integers.
#define GOOGLE_LL_FORMAT "ll" // As in "%lld". Note that "q" is poor form also.
#endif
static const int32 kint32max = 0x7FFFFFFF;
static const int32 kint32min = -kint32max - 1;
static const int64 kint64max = GOOGLE_LONGLONG(0x7FFFFFFFFFFFFFFF);
static const int64 kint64min = -kint64max - 1;
static const uint32 kuint32max = 0xFFFFFFFFu;
static const uint64 kuint64max = GOOGLE_ULONGLONG(0xFFFFFFFFFFFFFFFF);
// -------------------------------------------------------------------
// Annotations: Some parts of the code have been annotated in ways that might
// be useful to some compilers or tools, but are not supported universally.
// You can #define these annotations yourself if the default implementation
// is not right for you.
#ifndef GOOGLE_ATTRIBUTE_ALWAYS_INLINE
#if defined(__GNUC__) && (__GNUC__ > 3 ||(__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
// For functions we want to force inline.
// Introduced in gcc 3.1.
#define GOOGLE_ATTRIBUTE_ALWAYS_INLINE __attribute__ ((always_inline))
#else
// Other compilers will have to figure it out for themselves.
#define GOOGLE_ATTRIBUTE_ALWAYS_INLINE
#endif
#endif
#define GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE GOOGLE_ATTRIBUTE_ALWAYS_INLINE
#ifndef GOOGLE_ATTRIBUTE_NOINLINE
#if defined(__GNUC__) && (__GNUC__ > 3 ||(__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
// For functions we want to force not inline.
// Introduced in gcc 3.1.
#define GOOGLE_ATTRIBUTE_NOINLINE __attribute__ ((noinline))
#elif defined(_MSC_VER) && (_MSC_VER >= 1400)
// Seems to have been around since at least Visual Studio 2005
#define GOOGLE_ATTRIBUTE_NOINLINE __declspec(noinline)
#else
// Other compilers will have to figure it out for themselves.
#define GOOGLE_ATTRIBUTE_NOINLINE
#endif
#endif
#define GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE GOOGLE_ATTRIBUTE_NOINLINE
#ifndef GOOGLE_ATTRIBUTE_FUNC_ALIGN
#if defined(__clang__) || \
defined(__GNUC__) && (__GNUC__ > 4 ||(__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
// Function alignment attribute introduced in gcc 4.3
#define GOOGLE_ATTRIBUTE_FUNC_ALIGN(bytes) __attribute__ ((aligned(bytes)))
#else
#define GOOGLE_ATTRIBUTE_FUNC_ALIGN(bytes)
#endif
#endif
#define GOOGLE_PROTOBUF_ATTRIBUTE_FUNC_ALIGN(bytes) \
GOOGLE_ATTRIBUTE_FUNC_ALIGN(bytes)
#ifndef GOOGLE_PREDICT_TRUE
#ifdef __GNUC__
// Provided at least since GCC 3.0.
#define GOOGLE_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
#else
#define GOOGLE_PREDICT_TRUE(x) (x)
#endif
#endif
#ifndef GOOGLE_PREDICT_FALSE
#ifdef __GNUC__
// Provided at least since GCC 3.0.
#define GOOGLE_PREDICT_FALSE(x) (__builtin_expect(x, 0))
#else
#define GOOGLE_PREDICT_FALSE(x) (x)
#endif
#endif
#ifndef GOOGLE_PROTOBUF_ATTRIBUTE_RETURNS_NONNULL
#ifdef __GNUC__
#define GOOGLE_PROTOBUF_ATTRIBUTE_RETURNS_NONNULL \
__attribute__((returns_nonnull))
#endif
#endif
// Delimits a block of code which may write to memory which is simultaneously
// written by other threads, but which has been determined to be thread-safe
// (e.g. because it is an idempotent write).
#ifndef GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN
#define GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN()
#endif
#ifndef GOOGLE_SAFE_CONCURRENT_WRITES_END
#define GOOGLE_SAFE_CONCURRENT_WRITES_END()
#endif
#define GOOGLE_GUARDED_BY(x)
#define GOOGLE_ATTRIBUTE_COLD
#ifdef GOOGLE_PROTOBUF_DONT_USE_UNALIGNED
# define GOOGLE_PROTOBUF_USE_UNALIGNED 0
#else
# if defined(_M_X64) || defined(__x86_64__) || defined(_M_IX86) || defined(__i386__)
# define GOOGLE_PROTOBUF_USE_UNALIGNED 1
# else
# define GOOGLE_PROTOBUF_USE_UNALIGNED 0
# endif
#endif
#define GOOGLE_PROTOBUF_ATTRIBUTE_COLD GOOGLE_ATTRIBUTE_COLD
#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) ||\
defined(MEMORY_SANITIZER)
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
uint16_t __sanitizer_unaligned_load16(const void *p);
uint32_t __sanitizer_unaligned_load32(const void *p);
uint64_t __sanitizer_unaligned_load64(const void *p);
void __sanitizer_unaligned_store16(void *p, uint16_t v);
void __sanitizer_unaligned_store32(void *p, uint32_t v);
void __sanitizer_unaligned_store64(void *p, uint64_t v);
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
inline uint16 GOOGLE_UNALIGNED_LOAD16(const void *p) {
return __sanitizer_unaligned_load16(p);
}
inline uint32 GOOGLE_UNALIGNED_LOAD32(const void *p) {
return __sanitizer_unaligned_load32(p);
}
inline uint64 GOOGLE_UNALIGNED_LOAD64(const void *p) {
return __sanitizer_unaligned_load64(p);
}
inline void GOOGLE_UNALIGNED_STORE16(void *p, uint16 v) {
__sanitizer_unaligned_store16(p, v);
}
inline void GOOGLE_UNALIGNED_STORE32(void *p, uint32 v) {
__sanitizer_unaligned_store32(p, v);
}
inline void GOOGLE_UNALIGNED_STORE64(void *p, uint64 v) {
__sanitizer_unaligned_store64(p, v);
}
#elif GOOGLE_PROTOBUF_USE_UNALIGNED
#define GOOGLE_UNALIGNED_LOAD16(_p) (*reinterpret_cast<const uint16 *>(_p))
#define GOOGLE_UNALIGNED_LOAD32(_p) (*reinterpret_cast<const uint32 *>(_p))
#define GOOGLE_UNALIGNED_LOAD64(_p) (*reinterpret_cast<const uint64 *>(_p))
#define GOOGLE_UNALIGNED_STORE16(_p, _val) (*reinterpret_cast<uint16 *>(_p) = (_val))
#define GOOGLE_UNALIGNED_STORE32(_p, _val) (*reinterpret_cast<uint32 *>(_p) = (_val))
#define GOOGLE_UNALIGNED_STORE64(_p, _val) (*reinterpret_cast<uint64 *>(_p) = (_val))
#else
inline uint16 GOOGLE_UNALIGNED_LOAD16(const void *p) {
uint16 t;
memcpy(&t, p, sizeof t);
return t;
}
inline uint32 GOOGLE_UNALIGNED_LOAD32(const void *p) {
uint32 t;
memcpy(&t, p, sizeof t);
return t;
}
inline uint64 GOOGLE_UNALIGNED_LOAD64(const void *p) {
uint64 t;
memcpy(&t, p, sizeof t);
return t;
}
inline void GOOGLE_UNALIGNED_STORE16(void *p, uint16 v) {
memcpy(p, &v, sizeof v);
}
inline void GOOGLE_UNALIGNED_STORE32(void *p, uint32 v) {
memcpy(p, &v, sizeof v);
}
inline void GOOGLE_UNALIGNED_STORE64(void *p, uint64 v) {
memcpy(p, &v, sizeof v);
}
#endif
#if defined(GOOGLE_PROTOBUF_OS_NACL) \
|| (defined(__ANDROID__) && defined(__clang__) \
&& (__clang_major__ == 3 && __clang_minor__ == 8) \
&& (__clang_patchlevel__ < 275480))
# define GOOGLE_PROTOBUF_USE_PORTABLE_LOG2
#endif
#if defined(_MSC_VER)
#define GOOGLE_THREAD_LOCAL __declspec(thread)
#else
#define GOOGLE_THREAD_LOCAL __thread
#endif
// The following guarantees declaration of the byte swap functions.
#ifdef _MSC_VER
#define bswap_16(x) _byteswap_ushort(x)
#define bswap_32(x) _byteswap_ulong(x)
#define bswap_64(x) _byteswap_uint64(x)
#elif defined(__APPLE__)
// Mac OS X / Darwin features
#define bswap_16(x) OSSwapInt16(x)
#define bswap_32(x) OSSwapInt32(x)
#define bswap_64(x) OSSwapInt64(x)
#elif !defined(__GLIBC__) && !defined(__BIONIC__) && !defined(__CYGWIN__)
static inline uint16 bswap_16(uint16 x) {
return static_cast<uint16>(((x & 0xFF) << 8) | ((x & 0xFF00) >> 8));
}
#define bswap_16(x) bswap_16(x)
static inline uint32 bswap_32(uint32 x) {
return (((x & 0xFF) << 24) |
((x & 0xFF00) << 8) |
((x & 0xFF0000) >> 8) |
((x & 0xFF000000) >> 24));
}
#define bswap_32(x) bswap_32(x)
static inline uint64 bswap_64(uint64 x) {
return (((x & GOOGLE_ULONGLONG(0xFF)) << 56) |
((x & GOOGLE_ULONGLONG(0xFF00)) << 40) |
((x & GOOGLE_ULONGLONG(0xFF0000)) << 24) |
((x & GOOGLE_ULONGLONG(0xFF000000)) << 8) |
((x & GOOGLE_ULONGLONG(0xFF00000000)) >> 8) |
((x & GOOGLE_ULONGLONG(0xFF0000000000)) >> 24) |
((x & GOOGLE_ULONGLONG(0xFF000000000000)) >> 40) |
((x & GOOGLE_ULONGLONG(0xFF00000000000000)) >> 56));
}
#define bswap_64(x) bswap_64(x)
#endif
// ===================================================================
// from google3/util/bits/bits.h
class Bits {
public:
static uint32 Log2FloorNonZero(uint32 n) {
#if defined(__GNUC__)
return 31 ^ static_cast<uint32>(__builtin_clz(n));
#elif defined(_MSC_VER)
unsigned long where;
_BitScanReverse(&where, n);
return where;
#else
return Log2FloorNonZero_Portable(n);
#endif
}
static uint32 Log2FloorNonZero64(uint64 n) {
// Older versions of clang run into an instruction-selection failure when
// it encounters __builtin_clzll:
// https://bugs.chromium.org/p/nativeclient/issues/detail?id=4395
// This includes arm-nacl-clang and clang in older Android NDK versions.
// To work around this, when we build with those we use the portable
// implementation instead.
#if defined(__GNUC__) && !defined(GOOGLE_PROTOBUF_USE_PORTABLE_LOG2)
return 63 ^ static_cast<uint32>(__builtin_clzll(n));
#elif defined(_MSC_VER) && defined(_M_X64)
unsigned long where;
_BitScanReverse64(&where, n);
return where;
#else
return Log2FloorNonZero64_Portable(n);
#endif
}
private:
static int Log2FloorNonZero_Portable(uint32 n) {
if (n == 0)
return -1;
int log = 0;
uint32 value = n;
for (int i = 4; i >= 0; --i) {
int shift = (1 << i);
uint32 x = value >> shift;
if (x != 0) {
value = x;
log += shift;
}
}
assert(value == 1);
return log;
}
static int Log2FloorNonZero64_Portable(uint64 n) {
const uint32 topbits = static_cast<uint32>(n >> 32);
if (topbits == 0) {
// Top bits are zero, so scan in bottom bits
return static_cast<int>(Log2FloorNonZero(static_cast<uint32>(n)));
} else {
return 32 + static_cast<int>(Log2FloorNonZero(topbits));
}
}
};
// ===================================================================
// from google3/util/endian/endian.h
LIBPROTOBUF_EXPORT uint32 ghtonl(uint32 x);
class BigEndian {
public:
#ifdef PROTOBUF_LITTLE_ENDIAN
static uint16 FromHost16(uint16 x) { return bswap_16(x); }
static uint16 ToHost16(uint16 x) { return bswap_16(x); }
static uint32 FromHost32(uint32 x) { return bswap_32(x); }
static uint32 ToHost32(uint32 x) { return bswap_32(x); }
static uint64 FromHost64(uint64 x) { return bswap_64(x); }
static uint64 ToHost64(uint64 x) { return bswap_64(x); }
static bool IsLittleEndian() { return true; }
#else
static uint16 FromHost16(uint16 x) { return x; }
static uint16 ToHost16(uint16 x) { return x; }
static uint32 FromHost32(uint32 x) { return x; }
static uint32 ToHost32(uint32 x) { return x; }
static uint64 FromHost64(uint64 x) { return x; }
static uint64 ToHost64(uint64 x) { return x; }
static bool IsLittleEndian() { return false; }
#endif /* ENDIAN */
// Functions to do unaligned loads and stores in big-endian order.
static uint16 Load16(const void *p) {
return ToHost16(GOOGLE_UNALIGNED_LOAD16(p));
}
static void Store16(void *p, uint16 v) {
GOOGLE_UNALIGNED_STORE16(p, FromHost16(v));
}
static uint32 Load32(const void *p) {
return ToHost32(GOOGLE_UNALIGNED_LOAD32(p));
}
static void Store32(void *p, uint32 v) {
GOOGLE_UNALIGNED_STORE32(p, FromHost32(v));
}
static uint64 Load64(const void *p) {
return ToHost64(GOOGLE_UNALIGNED_LOAD64(p));
}
static void Store64(void *p, uint64 v) {
GOOGLE_UNALIGNED_STORE64(p, FromHost64(v));
}
};
#ifndef GOOGLE_ATTRIBUTE_SECTION_VARIABLE
#define GOOGLE_ATTRIBUTE_SECTION_VARIABLE(name)
#endif
#define GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(name)
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_STUBS_PORT_H_

View File

@ -0,0 +1,116 @@
// 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_STUBS_STATUS_H_
#define GOOGLE_PROTOBUF_STUBS_STATUS_H_
#include <iosfwd>
#include <string>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/stringpiece.h>
namespace google {
namespace protobuf {
namespace util {
namespace error {
// These values must match error codes defined in google/rpc/code.proto.
enum Code {
OK = 0,
CANCELLED = 1,
UNKNOWN = 2,
INVALID_ARGUMENT = 3,
DEADLINE_EXCEEDED = 4,
NOT_FOUND = 5,
ALREADY_EXISTS = 6,
PERMISSION_DENIED = 7,
UNAUTHENTICATED = 16,
RESOURCE_EXHAUSTED = 8,
FAILED_PRECONDITION = 9,
ABORTED = 10,
OUT_OF_RANGE = 11,
UNIMPLEMENTED = 12,
INTERNAL = 13,
UNAVAILABLE = 14,
DATA_LOSS = 15,
};
} // namespace error
class LIBPROTOBUF_EXPORT Status {
public:
// Creates a "successful" status.
Status();
// Create a status in the canonical error space with the specified
// code, and error message. If "code == 0", error_message is
// ignored and a Status object identical to Status::OK is
// constructed.
Status(error::Code error_code, StringPiece error_message);
Status(const Status&);
Status& operator=(const Status& x);
~Status() {}
// Some pre-defined Status objects
static const Status OK; // Identical to 0-arg constructor
static const Status CANCELLED;
static const Status UNKNOWN;
// Accessor
bool ok() const {
return error_code_ == error::OK;
}
int error_code() const {
return error_code_;
}
StringPiece error_message() const {
return error_message_;
}
bool operator==(const Status& x) const;
bool operator!=(const Status& x) const {
return !operator==(x);
}
// Return a combination of the error code name and message.
string ToString() const;
private:
error::Code error_code_;
string error_message_;
};
// Prints a human-readable representation of 'x' to 'os'.
LIBPROTOBUF_EXPORT std::ostream& operator<<(std::ostream& os, const Status& x);
#define EXPECT_OK(value) EXPECT_TRUE((value).ok())
} // namespace util
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_STUBS_STATUS_H_

View File

@ -0,0 +1,259 @@
// 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.
// StatusOr<T> is the union of a Status object and a T
// object. StatusOr models the concept of an object that is either a
// usable value, or an error Status explaining why such a value is
// not present. To this end, StatusOr<T> does not allow its Status
// value to be Status::OK. Further, StatusOr<T*> does not allow the
// contained pointer to be NULL.
//
// The primary use-case for StatusOr<T> is as the return value of a
// function which may fail.
//
// Example client usage for a StatusOr<T>, where T is not a pointer:
//
// StatusOr<float> result = DoBigCalculationThatCouldFail();
// if (result.ok()) {
// float answer = result.ValueOrDie();
// printf("Big calculation yielded: %f", answer);
// } else {
// LOG(ERROR) << result.status();
// }
//
// Example client usage for a StatusOr<T*>:
//
// StatusOr<Foo*> result = FooFactory::MakeNewFoo(arg);
// if (result.ok()) {
// std::unique_ptr<Foo> foo(result.ValueOrDie());
// foo->DoSomethingCool();
// } else {
// LOG(ERROR) << result.status();
// }
//
// Example client usage for a StatusOr<std::unique_ptr<T>>:
//
// StatusOr<std::unique_ptr<Foo>> result = FooFactory::MakeNewFoo(arg);
// if (result.ok()) {
// std::unique_ptr<Foo> foo = result.ConsumeValueOrDie();
// foo->DoSomethingCool();
// } else {
// LOG(ERROR) << result.status();
// }
//
// Example factory implementation returning StatusOr<T*>:
//
// StatusOr<Foo*> FooFactory::MakeNewFoo(int arg) {
// if (arg <= 0) {
// return ::util::Status(::util::error::INVALID_ARGUMENT,
// "Arg must be positive");
// } else {
// return new Foo(arg);
// }
// }
//
#ifndef GOOGLE_PROTOBUF_STUBS_STATUSOR_H_
#define GOOGLE_PROTOBUF_STUBS_STATUSOR_H_
#include <new>
#include <string>
#include <utility>
#include <google/protobuf/stubs/status.h>
namespace google {
namespace protobuf {
namespace util {
template<typename T>
class StatusOr {
template<typename U> friend class StatusOr;
public:
// Construct a new StatusOr with Status::UNKNOWN status
StatusOr();
// Construct a new StatusOr with the given non-ok status. After calling
// this constructor, calls to ValueOrDie() will CHECK-fail.
//
// NOTE: Not explicit - we want to use StatusOr<T> as a return
// value, so it is convenient and sensible to be able to do 'return
// Status()' when the return type is StatusOr<T>.
//
// REQUIRES: status != Status::OK. This requirement is DCHECKed.
// In optimized builds, passing Status::OK here will have the effect
// of passing PosixErrorSpace::EINVAL as a fallback.
StatusOr(const Status& status); // NOLINT
// Construct a new StatusOr with the given value. If T is a plain pointer,
// value must not be NULL. After calling this constructor, calls to
// ValueOrDie() will succeed, and calls to status() will return OK.
//
// NOTE: Not explicit - we want to use StatusOr<T> as a return type
// so it is convenient and sensible to be able to do 'return T()'
// when when the return type is StatusOr<T>.
//
// REQUIRES: if T is a plain pointer, value != NULL. This requirement is
// DCHECKed. In optimized builds, passing a NULL pointer here will have
// the effect of passing PosixErrorSpace::EINVAL as a fallback.
StatusOr(const T& value); // NOLINT
// Copy constructor.
StatusOr(const StatusOr& other);
// Conversion copy constructor, T must be copy constructible from U
template<typename U>
StatusOr(const StatusOr<U>& other);
// Assignment operator.
StatusOr& operator=(const StatusOr& other);
// Conversion assignment operator, T must be assignable from U
template<typename U>
StatusOr& operator=(const StatusOr<U>& other);
// Returns a reference to our status. If this contains a T, then
// returns Status::OK.
const Status& status() const;
// Returns this->status().ok()
bool ok() const;
// Returns a reference to our current value, or CHECK-fails if !this->ok().
// If you need to initialize a T object from the stored value,
// ConsumeValueOrDie() may be more efficient.
const T& ValueOrDie() const;
private:
Status status_;
T value_;
};
////////////////////////////////////////////////////////////////////////////////
// Implementation details for StatusOr<T>
namespace internal {
class LIBPROTOBUF_EXPORT StatusOrHelper {
public:
// Move type-agnostic error handling to the .cc.
static void Crash(const util::Status& status);
// Customized behavior for StatusOr<T> vs. StatusOr<T*>
template<typename T>
struct Specialize;
};
template<typename T>
struct StatusOrHelper::Specialize {
// For non-pointer T, a reference can never be NULL.
static inline bool IsValueNull(const T& t) { return false; }
};
template<typename T>
struct StatusOrHelper::Specialize<T*> {
static inline bool IsValueNull(const T* t) { return t == NULL; }
};
} // namespace internal
template<typename T>
inline StatusOr<T>::StatusOr()
: status_(util::Status::UNKNOWN) {
}
template<typename T>
inline StatusOr<T>::StatusOr(const Status& status) {
if (status.ok()) {
status_ = Status(error::INTERNAL, "Status::OK is not a valid argument.");
} else {
status_ = status;
}
}
template<typename T>
inline StatusOr<T>::StatusOr(const T& value) {
if (internal::StatusOrHelper::Specialize<T>::IsValueNull(value)) {
status_ = Status(error::INTERNAL, "NULL is not a vaild argument.");
} else {
status_ = Status::OK;
value_ = value;
}
}
template<typename T>
inline StatusOr<T>::StatusOr(const StatusOr<T>& other)
: status_(other.status_), value_(other.value_) {
}
template<typename T>
inline StatusOr<T>& StatusOr<T>::operator=(const StatusOr<T>& other) {
status_ = other.status_;
value_ = other.value_;
return *this;
}
template<typename T>
template<typename U>
inline StatusOr<T>::StatusOr(const StatusOr<U>& other)
: status_(other.status_), value_(other.status_.ok() ? other.value_ : T()) {
}
template<typename T>
template<typename U>
inline StatusOr<T>& StatusOr<T>::operator=(const StatusOr<U>& other) {
status_ = other.status_;
if (status_.ok()) value_ = other.value_;
return *this;
}
template<typename T>
inline const Status& StatusOr<T>::status() const {
return status_;
}
template<typename T>
inline bool StatusOr<T>::ok() const {
return status().ok();
}
template<typename T>
inline const T& StatusOr<T>::ValueOrDie() const {
if (!status_.ok()) {
internal::StatusOrHelper::Crash(status_);
}
return value_;
}
} // namespace util
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_STUBS_STATUSOR_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.
// from google3/util/gtl/stl_util.h
#ifndef GOOGLE_PROTOBUF_STUBS_STL_UTIL_H__
#define GOOGLE_PROTOBUF_STUBS_STL_UTIL_H__
#include <google/protobuf/stubs/common.h>
namespace google {
namespace protobuf {
// STLDeleteContainerPointers()
// For a range within a container of pointers, calls delete
// (non-array version) on these pointers.
// NOTE: for these three functions, we could just implement a DeleteObject
// functor and then call for_each() on the range and functor, but this
// requires us to pull in all of algorithm.h, which seems expensive.
// For hash_[multi]set, it is important that this deletes behind the iterator
// because the hash_set may call the hash function on the iterator when it is
// advanced, which could result in the hash function trying to deference a
// stale pointer.
template <class ForwardIterator>
void STLDeleteContainerPointers(ForwardIterator begin,
ForwardIterator end) {
while (begin != end) {
ForwardIterator temp = begin;
++begin;
delete *temp;
}
}
// Inside Google, this function implements a horrible, disgusting hack in which
// we reach into the string's private implementation and resize it without
// initializing the new bytes. In some cases doing this can significantly
// improve performance. However, since it's totally non-portable it has no
// place in open source code. Feel free to fill this function in with your
// own disgusting hack if you want the perf boost.
inline void STLStringResizeUninitialized(string* s, size_t new_size) {
s->resize(new_size);
}
// Return a mutable char* pointing to a string's internal buffer,
// which may not be null-terminated. Writing through this pointer will
// modify the string.
//
// string_as_array(&str)[i] is valid for 0 <= i < str.size() until the
// next call to a string method that invalidates iterators.
//
// As of 2006-04, there is no standard-blessed way of getting a
// mutable reference to a string's internal buffer. However, issue 530
// (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-active.html#530)
// proposes this as the method. According to Matt Austern, this should
// already work on all current implementations.
inline char* string_as_array(string* str) {
// DO NOT USE const_cast<char*>(str->data())! See the unittest for why.
return str->empty() ? NULL : &*str->begin();
}
// STLDeleteElements() deletes all the elements in an STL container and clears
// the container. This function is suitable for use with a vector, set,
// hash_set, or any other STL container which defines sensible begin(), end(),
// and clear() methods.
//
// If container is NULL, this function is a no-op.
//
// As an alternative to calling STLDeleteElements() directly, consider
// ElementDeleter (defined below), which ensures that your container's elements
// are deleted when the ElementDeleter goes out of scope.
template <class T>
void STLDeleteElements(T *container) {
if (!container) return;
STLDeleteContainerPointers(container->begin(), container->end());
container->clear();
}
// Given an STL container consisting of (key, value) pairs, STLDeleteValues
// deletes all the "value" components and clears the container. Does nothing
// in the case it's given a NULL pointer.
template <class T>
void STLDeleteValues(T *v) {
if (!v) return;
for (typename T::iterator i = v->begin(); i != v->end(); ++i) {
delete i->second;
}
v->clear();
}
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_STUBS_STL_UTIL_H__

View File

@ -0,0 +1,487 @@
// 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.
// A StringPiece points to part or all of a string, Cord, double-quoted string
// literal, or other string-like object. A StringPiece does *not* own the
// string to which it points. A StringPiece is not null-terminated.
//
// You can use StringPiece as a function or method parameter. A StringPiece
// parameter can receive a double-quoted string literal argument, a "const
// char*" argument, a string argument, or a StringPiece argument with no data
// copying. Systematic use of StringPiece for arguments reduces data
// copies and strlen() calls.
//
// Prefer passing StringPieces by value:
// void MyFunction(StringPiece arg);
// If circumstances require, you may also pass by const reference:
// void MyFunction(const StringPiece& arg); // not preferred
// Both of these have the same lifetime semantics. Passing by value
// generates slightly smaller code. For more discussion, see the thread
// go/stringpiecebyvalue on c-users.
//
// StringPiece is also suitable for local variables if you know that
// the lifetime of the underlying object is longer than the lifetime
// of your StringPiece variable.
//
// Beware of binding a StringPiece to a temporary:
// StringPiece sp = obj.MethodReturningString(); // BAD: lifetime problem
//
// This code is okay:
// string str = obj.MethodReturningString(); // str owns its contents
// StringPiece sp(str); // GOOD, because str outlives sp
//
// StringPiece is sometimes a poor choice for a return value and usually a poor
// choice for a data member. If you do use a StringPiece this way, it is your
// responsibility to ensure that the object pointed to by the StringPiece
// outlives the StringPiece.
//
// A StringPiece may represent just part of a string; thus the name "Piece".
// For example, when splitting a string, vector<StringPiece> is a natural data
// type for the output. For another example, a Cord is a non-contiguous,
// potentially very long string-like object. The Cord class has an interface
// that iteratively provides StringPiece objects that point to the
// successive pieces of a Cord object.
//
// A StringPiece is not null-terminated. If you write code that scans a
// StringPiece, you must check its length before reading any characters.
// Common idioms that work on null-terminated strings do not work on
// StringPiece objects.
//
// There are several ways to create a null StringPiece:
// StringPiece()
// StringPiece(NULL)
// StringPiece(NULL, 0)
// For all of the above, sp.data() == NULL, sp.length() == 0,
// and sp.empty() == true. Also, if you create a StringPiece with
// a non-NULL pointer then sp.data() != NULL. Once created,
// sp.data() will stay either NULL or not-NULL, except if you call
// sp.clear() or sp.set().
//
// Thus, you can use StringPiece(NULL) to signal an out-of-band value
// that is different from other StringPiece values. This is similar
// to the way that const char* p1 = NULL; is different from
// const char* p2 = "";.
//
// There are many ways to create an empty StringPiece:
// StringPiece()
// StringPiece(NULL)
// StringPiece(NULL, 0)
// StringPiece("")
// StringPiece("", 0)
// StringPiece("abcdef", 0)
// StringPiece("abcdef"+6, 0)
// For all of the above, sp.length() will be 0 and sp.empty() will be true.
// For some empty StringPiece values, sp.data() will be NULL.
// For some empty StringPiece values, sp.data() will not be NULL.
//
// Be careful not to confuse: null StringPiece and empty StringPiece.
// The set of empty StringPieces properly includes the set of null StringPieces.
// That is, every null StringPiece is an empty StringPiece,
// but some non-null StringPieces are empty Stringpieces too.
//
// All empty StringPiece values compare equal to each other.
// Even a null StringPieces compares equal to a non-null empty StringPiece:
// StringPiece() == StringPiece("", 0)
// StringPiece(NULL) == StringPiece("abc", 0)
// StringPiece(NULL, 0) == StringPiece("abcdef"+6, 0)
//
// Look carefully at this example:
// StringPiece("") == NULL
// True or false? TRUE, because StringPiece::operator== converts
// the right-hand side from NULL to StringPiece(NULL),
// and then compares two zero-length spans of characters.
// However, we are working to make this example produce a compile error.
//
// Suppose you want to write:
// bool TestWhat?(StringPiece sp) { return sp == NULL; } // BAD
// Do not do that. Write one of these instead:
// bool TestNull(StringPiece sp) { return sp.data() == NULL; }
// bool TestEmpty(StringPiece sp) { return sp.empty(); }
// The intent of TestWhat? is unclear. Did you mean TestNull or TestEmpty?
// Right now, TestWhat? behaves likes TestEmpty.
// We are working to make TestWhat? produce a compile error.
// TestNull is good to test for an out-of-band signal.
// TestEmpty is good to test for an empty StringPiece.
//
// Caveats (again):
// (1) The lifetime of the pointed-to string (or piece of a string)
// must be longer than the lifetime of the StringPiece.
// (2) There may or may not be a '\0' character after the end of
// StringPiece data.
// (3) A null StringPiece is empty.
// An empty StringPiece may or may not be a null StringPiece.
#ifndef GOOGLE_PROTOBUF_STUBS_STRINGPIECE_H_
#define GOOGLE_PROTOBUF_STUBS_STRINGPIECE_H_
#include <assert.h>
#include <stddef.h>
#include <string.h>
#include <iosfwd>
#include <limits>
#include <string>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/hash.h>
namespace google {
namespace protobuf {
// StringPiece has *two* size types.
// StringPiece::size_type
// is unsigned
// is 32 bits in LP32, 64 bits in LP64, 64 bits in LLP64
// no future changes intended
// stringpiece_ssize_type
// is signed
// is 32 bits in LP32, 64 bits in LP64, 64 bits in LLP64
// future changes intended: http://go/64BitStringPiece
//
typedef string::difference_type stringpiece_ssize_type;
// STRINGPIECE_CHECK_SIZE protects us from 32-bit overflows.
// TODO(mec): delete this after stringpiece_ssize_type goes 64 bit.
#if !defined(NDEBUG)
#define STRINGPIECE_CHECK_SIZE 1
#elif defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE > 0
#define STRINGPIECE_CHECK_SIZE 1
#else
#define STRINGPIECE_CHECK_SIZE 0
#endif
class LIBPROTOBUF_EXPORT StringPiece {
private:
const char* ptr_;
stringpiece_ssize_type length_;
// Prevent overflow in debug mode or fortified mode.
// sizeof(stringpiece_ssize_type) may be smaller than sizeof(size_t).
static stringpiece_ssize_type CheckedSsizeTFromSizeT(size_t size) {
#if STRINGPIECE_CHECK_SIZE > 0
#ifdef max
#undef max
#endif
if (size > static_cast<size_t>(
std::numeric_limits<stringpiece_ssize_type>::max())) {
// Some people grep for this message in logs
// so take care if you ever change it.
LogFatalSizeTooBig(size, "size_t to int conversion");
}
#endif
return static_cast<stringpiece_ssize_type>(size);
}
// Out-of-line error path.
static void LogFatalSizeTooBig(size_t size, const char* details);
public:
// We provide non-explicit singleton constructors so users can pass
// in a "const char*" or a "string" wherever a "StringPiece" is
// expected.
//
// Style guide exception granted:
// http://goto/style-guide-exception-20978288
StringPiece() : ptr_(NULL), length_(0) {}
StringPiece(const char* str) // NOLINT(runtime/explicit)
: ptr_(str), length_(0) {
if (str != NULL) {
length_ = CheckedSsizeTFromSizeT(strlen(str));
}
}
template <class Allocator>
StringPiece( // NOLINT(runtime/explicit)
const std::basic_string<char, std::char_traits<char>, Allocator>& str)
: ptr_(str.data()), length_(0) {
length_ = CheckedSsizeTFromSizeT(str.size());
}
StringPiece(const char* offset, stringpiece_ssize_type len)
: ptr_(offset), length_(len) {
assert(len >= 0);
}
// Substring of another StringPiece.
// pos must be non-negative and <= x.length().
StringPiece(StringPiece x, stringpiece_ssize_type pos);
// Substring of another StringPiece.
// pos must be non-negative and <= x.length().
// len must be non-negative and will be pinned to at most x.length() - pos.
StringPiece(StringPiece x,
stringpiece_ssize_type pos,
stringpiece_ssize_type len);
// data() may return a pointer to a buffer with embedded NULs, and the
// returned buffer may or may not be null terminated. Therefore it is
// typically a mistake to pass data() to a routine that expects a NUL
// terminated string.
const char* data() const { return ptr_; }
stringpiece_ssize_type size() const { return length_; }
stringpiece_ssize_type length() const { return length_; }
bool empty() const { return length_ == 0; }
void clear() {
ptr_ = NULL;
length_ = 0;
}
void set(const char* data, stringpiece_ssize_type len) {
assert(len >= 0);
ptr_ = data;
length_ = len;
}
void set(const char* str) {
ptr_ = str;
if (str != NULL)
length_ = CheckedSsizeTFromSizeT(strlen(str));
else
length_ = 0;
}
void set(const void* data, stringpiece_ssize_type len) {
ptr_ = reinterpret_cast<const char*>(data);
length_ = len;
}
char operator[](stringpiece_ssize_type i) const {
assert(0 <= i);
assert(i < length_);
return ptr_[i];
}
void remove_prefix(stringpiece_ssize_type n) {
assert(length_ >= n);
ptr_ += n;
length_ -= n;
}
void remove_suffix(stringpiece_ssize_type n) {
assert(length_ >= n);
length_ -= n;
}
// returns {-1, 0, 1}
int compare(StringPiece x) const {
const stringpiece_ssize_type min_size =
length_ < x.length_ ? length_ : x.length_;
int r = memcmp(ptr_, x.ptr_, static_cast<size_t>(min_size));
if (r < 0) return -1;
if (r > 0) return 1;
if (length_ < x.length_) return -1;
if (length_ > x.length_) return 1;
return 0;
}
string as_string() const {
return ToString();
}
// We also define ToString() here, since many other string-like
// interfaces name the routine that converts to a C++ string
// "ToString", and it's confusing to have the method that does that
// for a StringPiece be called "as_string()". We also leave the
// "as_string()" method defined here for existing code.
string ToString() const {
if (ptr_ == NULL) return string();
return string(data(), static_cast<size_type>(size()));
}
operator string() const {
return ToString();
}
void CopyToString(string* target) const;
void AppendToString(string* target) const;
bool starts_with(StringPiece x) const {
return (length_ >= x.length_) &&
(memcmp(ptr_, x.ptr_, static_cast<size_t>(x.length_)) == 0);
}
bool ends_with(StringPiece x) const {
return ((length_ >= x.length_) &&
(memcmp(ptr_ + (length_-x.length_), x.ptr_,
static_cast<size_t>(x.length_)) == 0));
}
// Checks whether StringPiece starts with x and if so advances the beginning
// of it to past the match. It's basically a shortcut for starts_with
// followed by remove_prefix.
bool Consume(StringPiece x);
// Like above but for the end of the string.
bool ConsumeFromEnd(StringPiece x);
// standard STL container boilerplate
typedef char value_type;
typedef const char* pointer;
typedef const char& reference;
typedef const char& const_reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
static const size_type npos;
typedef const char* const_iterator;
typedef const char* iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
iterator begin() const { return ptr_; }
iterator end() const { return ptr_ + length_; }
const_reverse_iterator rbegin() const {
return const_reverse_iterator(ptr_ + length_);
}
const_reverse_iterator rend() const {
return const_reverse_iterator(ptr_);
}
stringpiece_ssize_type max_size() const { return length_; }
stringpiece_ssize_type capacity() const { return length_; }
// cpplint.py emits a false positive [build/include_what_you_use]
stringpiece_ssize_type copy(char* buf, size_type n, size_type pos = 0) const; // NOLINT
bool contains(StringPiece s) const;
stringpiece_ssize_type find(StringPiece s, size_type pos = 0) const;
stringpiece_ssize_type find(char c, size_type pos = 0) const;
stringpiece_ssize_type rfind(StringPiece s, size_type pos = npos) const;
stringpiece_ssize_type rfind(char c, size_type pos = npos) const;
stringpiece_ssize_type find_first_of(StringPiece s, size_type pos = 0) const;
stringpiece_ssize_type find_first_of(char c, size_type pos = 0) const {
return find(c, pos);
}
stringpiece_ssize_type find_first_not_of(StringPiece s,
size_type pos = 0) const;
stringpiece_ssize_type find_first_not_of(char c, size_type pos = 0) const;
stringpiece_ssize_type find_last_of(StringPiece s,
size_type pos = npos) const;
stringpiece_ssize_type find_last_of(char c, size_type pos = npos) const {
return rfind(c, pos);
}
stringpiece_ssize_type find_last_not_of(StringPiece s,
size_type pos = npos) const;
stringpiece_ssize_type find_last_not_of(char c, size_type pos = npos) const;
StringPiece substr(size_type pos, size_type n = npos) const;
};
// This large function is defined inline so that in a fairly common case where
// one of the arguments is a literal, the compiler can elide a lot of the
// following comparisons.
inline bool operator==(StringPiece x, StringPiece y) {
stringpiece_ssize_type len = x.size();
if (len != y.size()) {
return false;
}
return x.data() == y.data() || len <= 0 ||
memcmp(x.data(), y.data(), static_cast<size_t>(len)) == 0;
}
inline bool operator!=(StringPiece x, StringPiece y) {
return !(x == y);
}
inline bool operator<(StringPiece x, StringPiece y) {
const stringpiece_ssize_type min_size =
x.size() < y.size() ? x.size() : y.size();
const int r = memcmp(x.data(), y.data(), static_cast<size_t>(min_size));
return (r < 0) || (r == 0 && x.size() < y.size());
}
inline bool operator>(StringPiece x, StringPiece y) {
return y < x;
}
inline bool operator<=(StringPiece x, StringPiece y) {
return !(x > y);
}
inline bool operator>=(StringPiece x, StringPiece y) {
return !(x < y);
}
// allow StringPiece to be logged
extern std::ostream& operator<<(std::ostream& o, StringPiece piece);
namespace internal {
// StringPiece is not a POD and can not be used in an union (pre C++11). We
// need a POD version of it.
struct StringPiecePod {
// Create from a StringPiece.
static StringPiecePod CreateFromStringPiece(StringPiece str) {
StringPiecePod pod;
pod.data_ = str.data();
pod.size_ = str.size();
return pod;
}
// Cast to StringPiece.
operator StringPiece() const { return StringPiece(data_, size_); }
bool operator==(const char* value) const {
return StringPiece(data_, size_) == StringPiece(value);
}
char operator[](stringpiece_ssize_type i) const {
assert(0 <= i);
assert(i < size_);
return data_[i];
}
const char* data() const { return data_; }
stringpiece_ssize_type size() const {
return size_;
}
std::string ToString() const {
return std::string(data_, static_cast<size_t>(size_));
}
private:
const char* data_;
stringpiece_ssize_type size_;
};
} // namespace internal
} // namespace protobuf
} // namespace google
GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_START
template<> struct hash<StringPiece> {
size_t operator()(const StringPiece& s) const {
size_t result = 0;
for (const char *str = s.data(), *end = str + s.size(); str < end; str++) {
result = 5 * result + static_cast<size_t>(*str);
}
return result;
}
};
GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_END
#endif // STRINGS_STRINGPIECE_H_

View File

@ -0,0 +1,76 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2012 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.
// from google3/base/stringprintf.h
//
// Printf variants that place their output in a C++ string.
//
// Usage:
// string result = StringPrintf("%d %s\n", 10, "hello");
// SStringPrintf(&result, "%d %s\n", 10, "hello");
// StringAppendF(&result, "%d %s\n", 20, "there");
#ifndef GOOGLE_PROTOBUF_STUBS_STRINGPRINTF_H
#define GOOGLE_PROTOBUF_STUBS_STRINGPRINTF_H
#include <stdarg.h>
#include <string>
#include <vector>
#include <google/protobuf/stubs/common.h>
namespace google {
namespace protobuf {
// Return a C++ string
LIBPROTOBUF_EXPORT extern string StringPrintf(const char* format, ...);
// Store result into a supplied string and return it
LIBPROTOBUF_EXPORT extern const string& SStringPrintf(string* dst, const char* format, ...);
// Append result to a supplied string
LIBPROTOBUF_EXPORT extern void StringAppendF(string* dst, const char* format, ...);
// Lower-level routine that takes a va_list and appends to a specified
// string. All other routines are just convenience wrappers around it.
LIBPROTOBUF_EXPORT extern void StringAppendV(string* dst, const char* format, va_list ap);
// The max arguments supported by StringPrintfVector
LIBPROTOBUF_EXPORT extern const int kStringPrintfVectorMaxArgs;
// You can use this version when all your arguments are strings, but
// you don't know how many arguments you'll have at compile time.
// StringPrintfVector will LOG(FATAL) if v.size() > kStringPrintfVectorMaxArgs
LIBPROTOBUF_EXPORT extern string StringPrintfVector(const char* format, const std::vector<string>& v);
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_STUBS_STRINGPRINTF_H

View File

@ -0,0 +1,878 @@
// 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.
// from google3/strings/strutil.h
#ifndef GOOGLE_PROTOBUF_STUBS_STRUTIL_H__
#define GOOGLE_PROTOBUF_STUBS_STRUTIL_H__
#include <stdlib.h>
#include <vector>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/stringpiece.h>
namespace google {
namespace protobuf {
#ifdef _MSC_VER
#define strtoll _strtoi64
#define strtoull _strtoui64
#elif defined(__DECCXX) && defined(__osf__)
// HP C++ on Tru64 does not have strtoll, but strtol is already 64-bit.
#define strtoll strtol
#define strtoull strtoul
#endif
// ----------------------------------------------------------------------
// ascii_isalnum()
// Check if an ASCII character is alphanumeric. We can't use ctype's
// isalnum() because it is affected by locale. This function is applied
// to identifiers in the protocol buffer language, not to natural-language
// strings, so locale should not be taken into account.
// ascii_isdigit()
// Like above, but only accepts digits.
// ascii_isspace()
// Check if the character is a space character.
// ----------------------------------------------------------------------
inline bool ascii_isalnum(char c) {
return ('a' <= c && c <= 'z') ||
('A' <= c && c <= 'Z') ||
('0' <= c && c <= '9');
}
inline bool ascii_isdigit(char c) {
return ('0' <= c && c <= '9');
}
inline bool ascii_isspace(char c) {
return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' ||
c == '\r';
}
inline bool ascii_isupper(char c) {
return c >= 'A' && c <= 'Z';
}
inline bool ascii_islower(char c) {
return c >= 'a' && c <= 'z';
}
inline char ascii_toupper(char c) {
return ascii_islower(c) ? c - ('a' - 'A') : c;
}
inline char ascii_tolower(char c) {
return ascii_isupper(c) ? c + ('a' - 'A') : c;
}
inline int hex_digit_to_int(char c) {
/* Assume ASCII. */
int x = static_cast<unsigned char>(c);
if (x > '9') {
x += 9;
}
return x & 0xf;
}
// ----------------------------------------------------------------------
// HasPrefixString()
// Check if a string begins with a given prefix.
// StripPrefixString()
// Given a string and a putative prefix, returns the string minus the
// prefix string if the prefix matches, otherwise the original
// string.
// ----------------------------------------------------------------------
inline bool HasPrefixString(const string& str,
const string& prefix) {
return str.size() >= prefix.size() &&
str.compare(0, prefix.size(), prefix) == 0;
}
inline string StripPrefixString(const string& str, const string& prefix) {
if (HasPrefixString(str, prefix)) {
return str.substr(prefix.size());
} else {
return str;
}
}
// ----------------------------------------------------------------------
// HasSuffixString()
// Return true if str ends in suffix.
// StripSuffixString()
// Given a string and a putative suffix, returns the string minus the
// suffix string if the suffix matches, otherwise the original
// string.
// ----------------------------------------------------------------------
inline bool HasSuffixString(const string& str,
const string& suffix) {
return str.size() >= suffix.size() &&
str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
}
inline string StripSuffixString(const string& str, const string& suffix) {
if (HasSuffixString(str, suffix)) {
return str.substr(0, str.size() - suffix.size());
} else {
return str;
}
}
// ----------------------------------------------------------------------
// ReplaceCharacters
// Replaces any occurrence of the character 'remove' (or the characters
// in 'remove') with the character 'replacewith'.
// Good for keeping html characters or protocol characters (\t) out
// of places where they might cause a problem.
// StripWhitespace
// Removes whitespaces from both ends of the given string.
// ----------------------------------------------------------------------
LIBPROTOBUF_EXPORT void ReplaceCharacters(string* s, const char* remove,
char replacewith);
LIBPROTOBUF_EXPORT void StripString(string* s, const char* remove,
char replacewith);
LIBPROTOBUF_EXPORT void StripWhitespace(string* s);
// ----------------------------------------------------------------------
// LowerString()
// UpperString()
// ToUpper()
// Convert the characters in "s" to lowercase or uppercase. ASCII-only:
// these functions intentionally ignore locale because they are applied to
// identifiers used in the Protocol Buffer language, not to natural-language
// strings.
// ----------------------------------------------------------------------
inline void LowerString(string * s) {
string::iterator end = s->end();
for (string::iterator i = s->begin(); i != end; ++i) {
// tolower() changes based on locale. We don't want this!
if ('A' <= *i && *i <= 'Z') *i += 'a' - 'A';
}
}
inline void UpperString(string * s) {
string::iterator end = s->end();
for (string::iterator i = s->begin(); i != end; ++i) {
// toupper() changes based on locale. We don't want this!
if ('a' <= *i && *i <= 'z') *i += 'A' - 'a';
}
}
inline string ToUpper(const string& s) {
string out = s;
UpperString(&out);
return out;
}
// ----------------------------------------------------------------------
// StringReplace()
// Give me a string and two patterns "old" and "new", and I replace
// the first instance of "old" in the string with "new", if it
// exists. RETURN a new string, regardless of whether the replacement
// happened or not.
// ----------------------------------------------------------------------
LIBPROTOBUF_EXPORT string StringReplace(const string& s, const string& oldsub,
const string& newsub, bool replace_all);
// ----------------------------------------------------------------------
// SplitStringUsing()
// Split a string using a character delimiter. Append the components
// to 'result'. If there are consecutive delimiters, this function skips
// over all of them.
// ----------------------------------------------------------------------
LIBPROTOBUF_EXPORT void SplitStringUsing(const string& full, const char* delim,
std::vector<string>* res);
// Split a string using one or more byte delimiters, presented
// as a nul-terminated c string. Append the components to 'result'.
// If there are consecutive delimiters, this function will return
// corresponding empty strings. If you want to drop the empty
// strings, try SplitStringUsing().
//
// If "full" is the empty string, yields an empty string as the only value.
// ----------------------------------------------------------------------
LIBPROTOBUF_EXPORT void SplitStringAllowEmpty(const string& full,
const char* delim,
std::vector<string>* result);
// ----------------------------------------------------------------------
// Split()
// Split a string using a character delimiter.
// ----------------------------------------------------------------------
inline std::vector<string> Split(
const string& full, const char* delim, bool skip_empty = true) {
std::vector<string> result;
if (skip_empty) {
SplitStringUsing(full, delim, &result);
} else {
SplitStringAllowEmpty(full, delim, &result);
}
return result;
}
// ----------------------------------------------------------------------
// JoinStrings()
// These methods concatenate a vector of strings into a C++ string, using
// the C-string "delim" as a separator between components. There are two
// flavors of the function, one flavor returns the concatenated string,
// another takes a pointer to the target string. In the latter case the
// target string is cleared and overwritten.
// ----------------------------------------------------------------------
LIBPROTOBUF_EXPORT void JoinStrings(const std::vector<string>& components,
const char* delim, string* result);
inline string JoinStrings(const std::vector<string>& components,
const char* delim) {
string result;
JoinStrings(components, delim, &result);
return result;
}
// ----------------------------------------------------------------------
// UnescapeCEscapeSequences()
// Copies "source" to "dest", rewriting C-style escape sequences
// -- '\n', '\r', '\\', '\ooo', etc -- to their ASCII
// equivalents. "dest" must be sufficiently large to hold all
// the characters in the rewritten string (i.e. at least as large
// as strlen(source) + 1 should be safe, since the replacements
// are always shorter than the original escaped sequences). It's
// safe for source and dest to be the same. RETURNS the length
// of dest.
//
// It allows hex sequences \xhh, or generally \xhhhhh with an
// arbitrary number of hex digits, but all of them together must
// specify a value of a single byte (e.g. \x0045 is equivalent
// to \x45, and \x1234 is erroneous).
//
// It also allows escape sequences of the form \uhhhh (exactly four
// hex digits, upper or lower case) or \Uhhhhhhhh (exactly eight
// hex digits, upper or lower case) to specify a Unicode code
// point. The dest array will contain the UTF8-encoded version of
// that code-point (e.g., if source contains \u2019, then dest will
// contain the three bytes 0xE2, 0x80, and 0x99).
//
// Errors: In the first form of the call, errors are reported with
// LOG(ERROR). The same is true for the second form of the call if
// the pointer to the string std::vector is NULL; otherwise, error
// messages are stored in the std::vector. In either case, the effect on
// the dest array is not defined, but rest of the source will be
// processed.
// ----------------------------------------------------------------------
LIBPROTOBUF_EXPORT int UnescapeCEscapeSequences(const char* source, char* dest);
LIBPROTOBUF_EXPORT int UnescapeCEscapeSequences(const char* source, char* dest,
std::vector<string> *errors);
// ----------------------------------------------------------------------
// UnescapeCEscapeString()
// This does the same thing as UnescapeCEscapeSequences, but creates
// a new string. The caller does not need to worry about allocating
// a dest buffer. This should be used for non performance critical
// tasks such as printing debug messages. It is safe for src and dest
// to be the same.
//
// The second call stores its errors in a supplied string vector.
// If the string vector pointer is NULL, it reports the errors with LOG().
//
// In the first and second calls, the length of dest is returned. In the
// the third call, the new string is returned.
// ----------------------------------------------------------------------
LIBPROTOBUF_EXPORT int UnescapeCEscapeString(const string& src, string* dest);
LIBPROTOBUF_EXPORT int UnescapeCEscapeString(const string& src, string* dest,
std::vector<string> *errors);
LIBPROTOBUF_EXPORT string UnescapeCEscapeString(const string& src);
// ----------------------------------------------------------------------
// CEscape()
// Escapes 'src' using C-style escape sequences and returns the resulting
// string.
//
// Escaped chars: \n, \r, \t, ", ', \, and !isprint().
// ----------------------------------------------------------------------
LIBPROTOBUF_EXPORT string CEscape(const string& src);
// ----------------------------------------------------------------------
// CEscapeAndAppend()
// Escapes 'src' using C-style escape sequences, and appends the escaped
// string to 'dest'.
// ----------------------------------------------------------------------
LIBPROTOBUF_EXPORT void CEscapeAndAppend(StringPiece src, string* dest);
namespace strings {
// Like CEscape() but does not escape bytes with the upper bit set.
LIBPROTOBUF_EXPORT string Utf8SafeCEscape(const string& src);
// Like CEscape() but uses hex (\x) escapes instead of octals.
LIBPROTOBUF_EXPORT string CHexEscape(const string& src);
} // namespace strings
// ----------------------------------------------------------------------
// strto32()
// strtou32()
// strto64()
// strtou64()
// Architecture-neutral plug compatible replacements for strtol() and
// strtoul(). Long's have different lengths on ILP-32 and LP-64
// platforms, so using these is safer, from the point of view of
// overflow behavior, than using the standard libc functions.
// ----------------------------------------------------------------------
LIBPROTOBUF_EXPORT int32 strto32_adaptor(const char *nptr, char **endptr,
int base);
LIBPROTOBUF_EXPORT uint32 strtou32_adaptor(const char *nptr, char **endptr,
int base);
inline int32 strto32(const char *nptr, char **endptr, int base) {
if (sizeof(int32) == sizeof(long))
return strtol(nptr, endptr, base);
else
return strto32_adaptor(nptr, endptr, base);
}
inline uint32 strtou32(const char *nptr, char **endptr, int base) {
if (sizeof(uint32) == sizeof(unsigned long))
return strtoul(nptr, endptr, base);
else
return strtou32_adaptor(nptr, endptr, base);
}
// For now, long long is 64-bit on all the platforms we care about, so these
// functions can simply pass the call to strto[u]ll.
inline int64 strto64(const char *nptr, char **endptr, int base) {
GOOGLE_COMPILE_ASSERT(sizeof(int64) == sizeof(long long),
sizeof_int64_is_not_sizeof_long_long);
return strtoll(nptr, endptr, base);
}
inline uint64 strtou64(const char *nptr, char **endptr, int base) {
GOOGLE_COMPILE_ASSERT(sizeof(uint64) == sizeof(unsigned long long),
sizeof_uint64_is_not_sizeof_long_long);
return strtoull(nptr, endptr, base);
}
// ----------------------------------------------------------------------
// safe_strtob()
// safe_strto32()
// safe_strtou32()
// safe_strto64()
// safe_strtou64()
// safe_strtof()
// safe_strtod()
// ----------------------------------------------------------------------
LIBPROTOBUF_EXPORT bool safe_strtob(StringPiece str, bool* value);
LIBPROTOBUF_EXPORT bool safe_strto32(const string& str, int32* value);
LIBPROTOBUF_EXPORT bool safe_strtou32(const string& str, uint32* value);
inline bool safe_strto32(const char* str, int32* value) {
return safe_strto32(string(str), value);
}
inline bool safe_strto32(StringPiece str, int32* value) {
return safe_strto32(str.ToString(), value);
}
inline bool safe_strtou32(const char* str, uint32* value) {
return safe_strtou32(string(str), value);
}
inline bool safe_strtou32(StringPiece str, uint32* value) {
return safe_strtou32(str.ToString(), value);
}
LIBPROTOBUF_EXPORT bool safe_strto64(const string& str, int64* value);
LIBPROTOBUF_EXPORT bool safe_strtou64(const string& str, uint64* value);
inline bool safe_strto64(const char* str, int64* value) {
return safe_strto64(string(str), value);
}
inline bool safe_strto64(StringPiece str, int64* value) {
return safe_strto64(str.ToString(), value);
}
inline bool safe_strtou64(const char* str, uint64* value) {
return safe_strtou64(string(str), value);
}
inline bool safe_strtou64(StringPiece str, uint64* value) {
return safe_strtou64(str.ToString(), value);
}
LIBPROTOBUF_EXPORT bool safe_strtof(const char* str, float* value);
LIBPROTOBUF_EXPORT bool safe_strtod(const char* str, double* value);
inline bool safe_strtof(const string& str, float* value) {
return safe_strtof(str.c_str(), value);
}
inline bool safe_strtod(const string& str, double* value) {
return safe_strtod(str.c_str(), value);
}
inline bool safe_strtof(StringPiece str, float* value) {
return safe_strtof(str.ToString(), value);
}
inline bool safe_strtod(StringPiece str, double* value) {
return safe_strtod(str.ToString(), value);
}
// ----------------------------------------------------------------------
// FastIntToBuffer()
// FastHexToBuffer()
// FastHex64ToBuffer()
// FastHex32ToBuffer()
// FastTimeToBuffer()
// These are intended for speed. FastIntToBuffer() assumes the
// integer is non-negative. FastHexToBuffer() puts output in
// hex rather than decimal. FastTimeToBuffer() puts the output
// into RFC822 format.
//
// FastHex64ToBuffer() puts a 64-bit unsigned value in hex-format,
// padded to exactly 16 bytes (plus one byte for '\0')
//
// FastHex32ToBuffer() puts a 32-bit unsigned value in hex-format,
// padded to exactly 8 bytes (plus one byte for '\0')
//
// All functions take the output buffer as an arg.
// They all return a pointer to the beginning of the output,
// which may not be the beginning of the input buffer.
// ----------------------------------------------------------------------
// Suggested buffer size for FastToBuffer functions. Also works with
// DoubleToBuffer() and FloatToBuffer().
static const int kFastToBufferSize = 32;
LIBPROTOBUF_EXPORT char* FastInt32ToBuffer(int32 i, char* buffer);
LIBPROTOBUF_EXPORT char* FastInt64ToBuffer(int64 i, char* buffer);
char* FastUInt32ToBuffer(uint32 i, char* buffer); // inline below
char* FastUInt64ToBuffer(uint64 i, char* buffer); // inline below
LIBPROTOBUF_EXPORT char* FastHexToBuffer(int i, char* buffer);
LIBPROTOBUF_EXPORT char* FastHex64ToBuffer(uint64 i, char* buffer);
LIBPROTOBUF_EXPORT char* FastHex32ToBuffer(uint32 i, char* buffer);
// at least 22 bytes long
inline char* FastIntToBuffer(int i, char* buffer) {
return (sizeof(i) == 4 ?
FastInt32ToBuffer(i, buffer) : FastInt64ToBuffer(i, buffer));
}
inline char* FastUIntToBuffer(unsigned int i, char* buffer) {
return (sizeof(i) == 4 ?
FastUInt32ToBuffer(i, buffer) : FastUInt64ToBuffer(i, buffer));
}
inline char* FastLongToBuffer(long i, char* buffer) {
return (sizeof(i) == 4 ?
FastInt32ToBuffer(i, buffer) : FastInt64ToBuffer(i, buffer));
}
inline char* FastULongToBuffer(unsigned long i, char* buffer) {
return (sizeof(i) == 4 ?
FastUInt32ToBuffer(i, buffer) : FastUInt64ToBuffer(i, buffer));
}
// ----------------------------------------------------------------------
// FastInt32ToBufferLeft()
// FastUInt32ToBufferLeft()
// FastInt64ToBufferLeft()
// FastUInt64ToBufferLeft()
//
// Like the Fast*ToBuffer() functions above, these are intended for speed.
// Unlike the Fast*ToBuffer() functions, however, these functions write
// their output to the beginning of the buffer (hence the name, as the
// output is left-aligned). The caller is responsible for ensuring that
// the buffer has enough space to hold the output.
//
// Returns a pointer to the end of the string (i.e. the null character
// terminating the string).
// ----------------------------------------------------------------------
LIBPROTOBUF_EXPORT char* FastInt32ToBufferLeft(int32 i, char* buffer);
LIBPROTOBUF_EXPORT char* FastUInt32ToBufferLeft(uint32 i, char* buffer);
LIBPROTOBUF_EXPORT char* FastInt64ToBufferLeft(int64 i, char* buffer);
LIBPROTOBUF_EXPORT char* FastUInt64ToBufferLeft(uint64 i, char* buffer);
// Just define these in terms of the above.
inline char* FastUInt32ToBuffer(uint32 i, char* buffer) {
FastUInt32ToBufferLeft(i, buffer);
return buffer;
}
inline char* FastUInt64ToBuffer(uint64 i, char* buffer) {
FastUInt64ToBufferLeft(i, buffer);
return buffer;
}
inline string SimpleBtoa(bool value) {
return value ? "true" : "false";
}
// ----------------------------------------------------------------------
// SimpleItoa()
// Description: converts an integer to a string.
//
// Return value: string
// ----------------------------------------------------------------------
LIBPROTOBUF_EXPORT string SimpleItoa(int i);
LIBPROTOBUF_EXPORT string SimpleItoa(unsigned int i);
LIBPROTOBUF_EXPORT string SimpleItoa(long i);
LIBPROTOBUF_EXPORT string SimpleItoa(unsigned long i);
LIBPROTOBUF_EXPORT string SimpleItoa(long long i);
LIBPROTOBUF_EXPORT string SimpleItoa(unsigned long long i);
// ----------------------------------------------------------------------
// SimpleDtoa()
// SimpleFtoa()
// DoubleToBuffer()
// FloatToBuffer()
// Description: converts a double or float to a string which, if
// passed to NoLocaleStrtod(), will produce the exact same original double
// (except in case of NaN; all NaNs are considered the same value).
// We try to keep the string short but it's not guaranteed to be as
// short as possible.
//
// DoubleToBuffer() and FloatToBuffer() write the text to the given
// buffer and return it. The buffer must be at least
// kDoubleToBufferSize bytes for doubles and kFloatToBufferSize
// bytes for floats. kFastToBufferSize is also guaranteed to be large
// enough to hold either.
//
// Return value: string
// ----------------------------------------------------------------------
LIBPROTOBUF_EXPORT string SimpleDtoa(double value);
LIBPROTOBUF_EXPORT string SimpleFtoa(float value);
LIBPROTOBUF_EXPORT char* DoubleToBuffer(double i, char* buffer);
LIBPROTOBUF_EXPORT char* FloatToBuffer(float i, char* buffer);
// In practice, doubles should never need more than 24 bytes and floats
// should never need more than 14 (including null terminators), but we
// overestimate to be safe.
static const int kDoubleToBufferSize = 32;
static const int kFloatToBufferSize = 24;
namespace strings {
enum PadSpec {
NO_PAD = 1,
ZERO_PAD_2,
ZERO_PAD_3,
ZERO_PAD_4,
ZERO_PAD_5,
ZERO_PAD_6,
ZERO_PAD_7,
ZERO_PAD_8,
ZERO_PAD_9,
ZERO_PAD_10,
ZERO_PAD_11,
ZERO_PAD_12,
ZERO_PAD_13,
ZERO_PAD_14,
ZERO_PAD_15,
ZERO_PAD_16,
};
struct Hex {
uint64 value;
enum PadSpec spec;
template <class Int>
explicit Hex(Int v, PadSpec s = NO_PAD)
: spec(s) {
// Prevent sign-extension by casting integers to
// their unsigned counterparts.
#ifdef LANG_CXX11
static_assert(
sizeof(v) == 1 || sizeof(v) == 2 || sizeof(v) == 4 || sizeof(v) == 8,
"Unknown integer type");
#endif
value = sizeof(v) == 1 ? static_cast<uint8>(v)
: sizeof(v) == 2 ? static_cast<uint16>(v)
: sizeof(v) == 4 ? static_cast<uint32>(v)
: static_cast<uint64>(v);
}
};
struct LIBPROTOBUF_EXPORT AlphaNum {
const char *piece_data_; // move these to string_ref eventually
size_t piece_size_; // move these to string_ref eventually
char digits[kFastToBufferSize];
// No bool ctor -- bools convert to an integral type.
// A bool ctor would also convert incoming pointers (bletch).
AlphaNum(int32 i32)
: piece_data_(digits),
piece_size_(FastInt32ToBufferLeft(i32, digits) - &digits[0]) {}
AlphaNum(uint32 u32)
: piece_data_(digits),
piece_size_(FastUInt32ToBufferLeft(u32, digits) - &digits[0]) {}
AlphaNum(int64 i64)
: piece_data_(digits),
piece_size_(FastInt64ToBufferLeft(i64, digits) - &digits[0]) {}
AlphaNum(uint64 u64)
: piece_data_(digits),
piece_size_(FastUInt64ToBufferLeft(u64, digits) - &digits[0]) {}
AlphaNum(float f)
: piece_data_(digits), piece_size_(strlen(FloatToBuffer(f, digits))) {}
AlphaNum(double f)
: piece_data_(digits), piece_size_(strlen(DoubleToBuffer(f, digits))) {}
AlphaNum(Hex hex);
AlphaNum(const char* c_str)
: piece_data_(c_str), piece_size_(strlen(c_str)) {}
// TODO: Add a string_ref constructor, eventually
// AlphaNum(const StringPiece &pc) : piece(pc) {}
AlphaNum(const string& str)
: piece_data_(str.data()), piece_size_(str.size()) {}
AlphaNum(StringPiece str)
: piece_data_(str.data()), piece_size_(str.size()) {}
AlphaNum(internal::StringPiecePod str)
: piece_data_(str.data()), piece_size_(str.size()) {}
size_t size() const { return piece_size_; }
const char *data() const { return piece_data_; }
private:
// Use ":" not ':'
AlphaNum(char c); // NOLINT(runtime/explicit)
// Disallow copy and assign.
AlphaNum(const AlphaNum&);
void operator=(const AlphaNum&);
};
} // namespace strings
using strings::AlphaNum;
// ----------------------------------------------------------------------
// StrCat()
// This merges the given strings or numbers, with no delimiter. This
// is designed to be the fastest possible way to construct a string out
// of a mix of raw C strings, strings, bool values,
// and numeric values.
//
// Don't use this for user-visible strings. The localization process
// works poorly on strings built up out of fragments.
//
// For clarity and performance, don't use StrCat when appending to a
// string. In particular, avoid using any of these (anti-)patterns:
// str.append(StrCat(...)
// str += StrCat(...)
// str = StrCat(str, ...)
// where the last is the worse, with the potential to change a loop
// from a linear time operation with O(1) dynamic allocations into a
// quadratic time operation with O(n) dynamic allocations. StrAppend
// is a better choice than any of the above, subject to the restriction
// of StrAppend(&str, a, b, c, ...) that none of the a, b, c, ... may
// be a reference into str.
// ----------------------------------------------------------------------
LIBPROTOBUF_EXPORT string StrCat(const AlphaNum& a, const AlphaNum& b);
LIBPROTOBUF_EXPORT string StrCat(const AlphaNum& a, const AlphaNum& b,
const AlphaNum& c);
LIBPROTOBUF_EXPORT string StrCat(const AlphaNum& a, const AlphaNum& b,
const AlphaNum& c, const AlphaNum& d);
LIBPROTOBUF_EXPORT string StrCat(const AlphaNum& a, const AlphaNum& b,
const AlphaNum& c, const AlphaNum& d,
const AlphaNum& e);
LIBPROTOBUF_EXPORT string StrCat(const AlphaNum& a, const AlphaNum& b,
const AlphaNum& c, const AlphaNum& d,
const AlphaNum& e, const AlphaNum& f);
LIBPROTOBUF_EXPORT string StrCat(const AlphaNum& a, const AlphaNum& b,
const AlphaNum& c, const AlphaNum& d,
const AlphaNum& e, const AlphaNum& f,
const AlphaNum& g);
LIBPROTOBUF_EXPORT string StrCat(const AlphaNum& a, const AlphaNum& b,
const AlphaNum& c, const AlphaNum& d,
const AlphaNum& e, const AlphaNum& f,
const AlphaNum& g, const AlphaNum& h);
LIBPROTOBUF_EXPORT string StrCat(const AlphaNum& a, const AlphaNum& b,
const AlphaNum& c, const AlphaNum& d,
const AlphaNum& e, const AlphaNum& f,
const AlphaNum& g, const AlphaNum& h,
const AlphaNum& i);
inline string StrCat(const AlphaNum& a) { return string(a.data(), a.size()); }
// ----------------------------------------------------------------------
// StrAppend()
// Same as above, but adds the output to the given string.
// WARNING: For speed, StrAppend does not try to check each of its input
// arguments to be sure that they are not a subset of the string being
// appended to. That is, while this will work:
//
// string s = "foo";
// s += s;
//
// This will not (necessarily) work:
//
// string s = "foo";
// StrAppend(&s, s);
//
// Note: while StrCat supports appending up to 9 arguments, StrAppend
// is currently limited to 4. That's rarely an issue except when
// automatically transforming StrCat to StrAppend, and can easily be
// worked around as consecutive calls to StrAppend are quite efficient.
// ----------------------------------------------------------------------
LIBPROTOBUF_EXPORT void StrAppend(string* dest, const AlphaNum& a);
LIBPROTOBUF_EXPORT void StrAppend(string* dest, const AlphaNum& a,
const AlphaNum& b);
LIBPROTOBUF_EXPORT void StrAppend(string* dest, const AlphaNum& a,
const AlphaNum& b, const AlphaNum& c);
LIBPROTOBUF_EXPORT void StrAppend(string* dest, const AlphaNum& a,
const AlphaNum& b, const AlphaNum& c,
const AlphaNum& d);
// ----------------------------------------------------------------------
// Join()
// These methods concatenate a range of components into a C++ string, using
// the C-string "delim" as a separator between components.
// ----------------------------------------------------------------------
template <typename Iterator>
void Join(Iterator start, Iterator end,
const char* delim, string* result) {
for (Iterator it = start; it != end; ++it) {
if (it != start) {
result->append(delim);
}
StrAppend(result, *it);
}
}
template <typename Range>
string Join(const Range& components,
const char* delim) {
string result;
Join(components.begin(), components.end(), delim, &result);
return result;
}
// ----------------------------------------------------------------------
// ToHex()
// Return a lower-case hex string representation of the given integer.
// ----------------------------------------------------------------------
LIBPROTOBUF_EXPORT string ToHex(uint64 num);
// ----------------------------------------------------------------------
// GlobalReplaceSubstring()
// Replaces all instances of a substring in a string. Does nothing
// if 'substring' is empty. Returns the number of replacements.
//
// NOTE: The string pieces must not overlap s.
// ----------------------------------------------------------------------
LIBPROTOBUF_EXPORT int GlobalReplaceSubstring(const string& substring,
const string& replacement,
string* s);
// ----------------------------------------------------------------------
// Base64Unescape()
// Converts "src" which is encoded in Base64 to its binary equivalent and
// writes it to "dest". If src contains invalid characters, dest is cleared
// and the function returns false. Returns true on success.
// ----------------------------------------------------------------------
LIBPROTOBUF_EXPORT bool Base64Unescape(StringPiece src, string* dest);
// ----------------------------------------------------------------------
// WebSafeBase64Unescape()
// This is a variation of Base64Unescape which uses '-' instead of '+', and
// '_' instead of '/'. src is not null terminated, instead specify len. I
// recommend that slen<szdest, but we honor szdest anyway.
// RETURNS the length of dest, or -1 if src contains invalid chars.
// The variation that stores into a string clears the string first, and
// returns false (with dest empty) if src contains invalid chars; for
// this version src and dest must be different strings.
// ----------------------------------------------------------------------
LIBPROTOBUF_EXPORT int WebSafeBase64Unescape(const char* src, int slen,
char* dest, int szdest);
LIBPROTOBUF_EXPORT bool WebSafeBase64Unescape(StringPiece src, string* dest);
// Return the length to use for the output buffer given to the base64 escape
// routines. Make sure to use the same value for do_padding in both.
// This function may return incorrect results if given input_len values that
// are extremely high, which should happen rarely.
LIBPROTOBUF_EXPORT int CalculateBase64EscapedLen(int input_len,
bool do_padding);
// Use this version when calling Base64Escape without a do_padding arg.
LIBPROTOBUF_EXPORT int CalculateBase64EscapedLen(int input_len);
// ----------------------------------------------------------------------
// Base64Escape()
// WebSafeBase64Escape()
// Encode "src" to "dest" using base64 encoding.
// src is not null terminated, instead specify len.
// 'dest' should have at least CalculateBase64EscapedLen() length.
// RETURNS the length of dest.
// The WebSafe variation use '-' instead of '+' and '_' instead of '/'
// so that we can place the out in the URL or cookies without having
// to escape them. It also has an extra parameter "do_padding",
// which when set to false will prevent padding with "=".
// ----------------------------------------------------------------------
LIBPROTOBUF_EXPORT int Base64Escape(const unsigned char* src, int slen,
char* dest, int szdest);
LIBPROTOBUF_EXPORT int WebSafeBase64Escape(
const unsigned char* src, int slen, char* dest,
int szdest, bool do_padding);
// Encode src into dest with padding.
LIBPROTOBUF_EXPORT void Base64Escape(StringPiece src, string* dest);
// Encode src into dest web-safely without padding.
LIBPROTOBUF_EXPORT void WebSafeBase64Escape(StringPiece src, string* dest);
// Encode src into dest web-safely with padding.
LIBPROTOBUF_EXPORT void WebSafeBase64EscapeWithPadding(StringPiece src,
string* dest);
LIBPROTOBUF_EXPORT void Base64Escape(const unsigned char* src, int szsrc,
string* dest, bool do_padding);
LIBPROTOBUF_EXPORT void WebSafeBase64Escape(const unsigned char* src, int szsrc,
string* dest, bool do_padding);
inline bool IsValidCodePoint(uint32 code_point) {
return code_point < 0xD800 ||
(code_point >= 0xE000 && code_point <= 0x10FFFF);
}
static const int UTFmax = 4;
// ----------------------------------------------------------------------
// EncodeAsUTF8Char()
// Helper to append a Unicode code point to a string as UTF8, without bringing
// in any external dependencies. The output buffer must be as least 4 bytes
// large.
// ----------------------------------------------------------------------
LIBPROTOBUF_EXPORT int EncodeAsUTF8Char(uint32 code_point, char* output);
// ----------------------------------------------------------------------
// UTF8FirstLetterNumBytes()
// Length of the first UTF-8 character.
// ----------------------------------------------------------------------
LIBPROTOBUF_EXPORT int UTF8FirstLetterNumBytes(const char* src, int len);
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_STUBS_STRUTIL_H__

View File

@ -0,0 +1,75 @@
// 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_STUBS_TIME_H_
#define GOOGLE_PROTOBUF_STUBS_TIME_H_
#include <google/protobuf/stubs/common.h>
namespace google {
namespace protobuf {
namespace internal {
struct DateTime {
int year;
int month;
int day;
int hour;
int minute;
int second;
};
// Converts a timestamp (seconds elapsed since 1970-01-01T00:00:00, could be
// negative to represent time before 1970-01-01) to DateTime. Returns false
// if the timestamp is not in the range between 0001-01-01T00:00:00 and
// 9999-12-31T23:59:59.
bool LIBPROTOBUF_EXPORT SecondsToDateTime(int64 seconds, DateTime* time);
// Converts DateTime to a timestamp (seconds since 1970-01-01T00:00:00).
// Returns false if the DateTime is not valid or is not in the valid range.
bool LIBPROTOBUF_EXPORT DateTimeToSeconds(const DateTime& time, int64* seconds);
void LIBPROTOBUF_EXPORT GetCurrentTime(int64* seconds, int32* nanos);
// Formats a time string in RFC3339 fromat.
//
// For example, "2015-05-20T13:29:35.120Z". For nanos, 0, 3, 6 or 9 fractional
// digits will be used depending on how many are required to represent the exact
// value.
//
// Note that "nanos" must in the range of [0, 999999999].
string LIBPROTOBUF_EXPORT FormatTime(int64 seconds, int32 nanos);
// Parses a time string. This method accepts RFC3339 date/time string with UTC
// offset. For example, "2015-05-20T13:29:35.120-08:00".
bool LIBPROTOBUF_EXPORT ParseTime(const string& value, int64* seconds, int32* nanos);
} // namespace internal
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_STUBS_TIME_H_

View File

@ -0,0 +1,893 @@
// 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)
// atenasio@google.com (Chris Atenasio) (ZigZag transform)
// wink@google.com (Wink Saville) (refactored from wire_format.h)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
//
// This header is logically internal, but is made public because it is used
// from protocol-compiler-generated code, which may reside in other components.
#ifndef GOOGLE_PROTOBUF_WIRE_FORMAT_LITE_H__
#define GOOGLE_PROTOBUF_WIRE_FORMAT_LITE_H__
#include <string>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/message_lite.h>
#include <google/protobuf/stubs/port.h>
#include <google/protobuf/repeated_field.h>
// Do UTF-8 validation on string type in Debug build only
#ifndef NDEBUG
#define GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
#endif
// Avoid conflict with iOS where <ConditionalMacros.h> #defines TYPE_BOOL.
//
// If some one needs the macro TYPE_BOOL in a file that includes this header, it's
// possible to bring it back using push/pop_macro as follows.
//
// #pragma push_macro("TYPE_BOOL")
// #include this header and/or all headers that need the macro to be undefined.
// #pragma pop_macro("TYPE_BOOL")
#undef TYPE_BOOL
namespace google {
namespace protobuf {
template <typename T> class RepeatedField; // repeated_field.h
}
namespace protobuf {
namespace internal {
class StringPieceField;
// This class is for internal use by the protocol buffer library and by
// protocol-complier-generated message classes. It must not be called
// directly by clients.
//
// This class contains helpers for implementing the binary protocol buffer
// wire format without the need for reflection. Use WireFormat when using
// reflection.
//
// This class is really a namespace that contains only static methods.
class LIBPROTOBUF_EXPORT WireFormatLite {
public:
// -----------------------------------------------------------------
// Helper constants and functions related to the format. These are
// mostly meant for internal and generated code to use.
// The wire format is composed of a sequence of tag/value pairs, each
// of which contains the value of one field (or one element of a repeated
// field). Each tag is encoded as a varint. The lower bits of the tag
// identify its wire type, which specifies the format of the data to follow.
// The rest of the bits contain the field number. Each type of field (as
// declared by FieldDescriptor::Type, in descriptor.h) maps to one of
// these wire types. Immediately following each tag is the field's value,
// encoded in the format specified by the wire type. Because the tag
// identifies the encoding of this data, it is possible to skip
// unrecognized fields for forwards compatibility.
enum WireType {
WIRETYPE_VARINT = 0,
WIRETYPE_FIXED64 = 1,
WIRETYPE_LENGTH_DELIMITED = 2,
WIRETYPE_START_GROUP = 3,
WIRETYPE_END_GROUP = 4,
WIRETYPE_FIXED32 = 5,
};
// Lite alternative to FieldDescriptor::Type. Must be kept in sync.
enum FieldType {
TYPE_DOUBLE = 1,
TYPE_FLOAT = 2,
TYPE_INT64 = 3,
TYPE_UINT64 = 4,
TYPE_INT32 = 5,
TYPE_FIXED64 = 6,
TYPE_FIXED32 = 7,
TYPE_BOOL = 8,
TYPE_STRING = 9,
TYPE_GROUP = 10,
TYPE_MESSAGE = 11,
TYPE_BYTES = 12,
TYPE_UINT32 = 13,
TYPE_ENUM = 14,
TYPE_SFIXED32 = 15,
TYPE_SFIXED64 = 16,
TYPE_SINT32 = 17,
TYPE_SINT64 = 18,
MAX_FIELD_TYPE = 18,
};
// Lite alternative to FieldDescriptor::CppType. Must be kept in sync.
enum CppType {
CPPTYPE_INT32 = 1,
CPPTYPE_INT64 = 2,
CPPTYPE_UINT32 = 3,
CPPTYPE_UINT64 = 4,
CPPTYPE_DOUBLE = 5,
CPPTYPE_FLOAT = 6,
CPPTYPE_BOOL = 7,
CPPTYPE_ENUM = 8,
CPPTYPE_STRING = 9,
CPPTYPE_MESSAGE = 10,
MAX_CPPTYPE = 10,
};
// Helper method to get the CppType for a particular Type.
static CppType FieldTypeToCppType(FieldType type);
// Given a FieldDescriptor::Type return its WireType
static inline WireFormatLite::WireType WireTypeForFieldType(
WireFormatLite::FieldType type) {
return kWireTypeForFieldType[type];
}
// Number of bits in a tag which identify the wire type.
static const int kTagTypeBits = 3;
// Mask for those bits.
static const uint32 kTagTypeMask = (1 << kTagTypeBits) - 1;
// Helper functions for encoding and decoding tags. (Inlined below and in
// _inl.h)
//
// This is different from MakeTag(field->number(), field->type()) in the case
// of packed repeated fields.
static uint32 MakeTag(int field_number, WireType type);
static WireType GetTagWireType(uint32 tag);
static int GetTagFieldNumber(uint32 tag);
// Compute the byte size of a tag. For groups, this includes both the start
// and end tags.
static inline size_t TagSize(int field_number,
WireFormatLite::FieldType type);
// Skips a field value with the given tag. The input should start
// positioned immediately after the tag. Skipped values are simply discarded,
// not recorded anywhere. See WireFormat::SkipField() for a version that
// records to an UnknownFieldSet.
static bool SkipField(io::CodedInputStream* input, uint32 tag);
// Skips a field value with the given tag. The input should start
// positioned immediately after the tag. Skipped values are recorded to a
// CodedOutputStream.
static bool SkipField(io::CodedInputStream* input, uint32 tag,
io::CodedOutputStream* output);
// Reads and ignores a message from the input. Skipped values are simply
// discarded, not recorded anywhere. See WireFormat::SkipMessage() for a
// version that records to an UnknownFieldSet.
static bool SkipMessage(io::CodedInputStream* input);
// Reads and ignores a message from the input. Skipped values are recorded
// to a CodedOutputStream.
static bool SkipMessage(io::CodedInputStream* input,
io::CodedOutputStream* output);
// This macro does the same thing as WireFormatLite::MakeTag(), but the
// result is usable as a compile-time constant, which makes it usable
// as a switch case or a template input. WireFormatLite::MakeTag() is more
// type-safe, though, so prefer it if possible.
#define GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(FIELD_NUMBER, TYPE) \
static_cast<uint32>( \
(static_cast<uint32>(FIELD_NUMBER) << ::google::protobuf::internal::WireFormatLite::kTagTypeBits) \
| (TYPE))
// These are the tags for the old MessageSet format, which was defined as:
// message MessageSet {
// repeated group Item = 1 {
// required int32 type_id = 2;
// required string message = 3;
// }
// }
static const int kMessageSetItemNumber = 1;
static const int kMessageSetTypeIdNumber = 2;
static const int kMessageSetMessageNumber = 3;
static const int kMessageSetItemStartTag =
GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(kMessageSetItemNumber,
WireFormatLite::WIRETYPE_START_GROUP);
static const int kMessageSetItemEndTag =
GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(kMessageSetItemNumber,
WireFormatLite::WIRETYPE_END_GROUP);
static const int kMessageSetTypeIdTag =
GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(kMessageSetTypeIdNumber,
WireFormatLite::WIRETYPE_VARINT);
static const int kMessageSetMessageTag =
GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(kMessageSetMessageNumber,
WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
// Byte size of all tags of a MessageSet::Item combined.
static const size_t kMessageSetItemTagsSize;
// Helper functions for converting between floats/doubles and IEEE-754
// uint32s/uint64s so that they can be written. (Assumes your platform
// uses IEEE-754 floats.)
static uint32 EncodeFloat(float value);
static float DecodeFloat(uint32 value);
static uint64 EncodeDouble(double value);
static double DecodeDouble(uint64 value);
// Helper functions for mapping signed integers to unsigned integers in
// such a way that numbers with small magnitudes will encode to smaller
// varints. If you simply static_cast a negative number to an unsigned
// number and varint-encode it, it will always take 10 bytes, defeating
// the purpose of varint. So, for the "sint32" and "sint64" field types,
// we ZigZag-encode the values.
static uint32 ZigZagEncode32(int32 n);
static int32 ZigZagDecode32(uint32 n);
static uint64 ZigZagEncode64(int64 n);
static int64 ZigZagDecode64(uint64 n);
// =================================================================
// Methods for reading/writing individual field. The implementations
// of these methods are defined in wire_format_lite_inl.h; you must #include
// that file to use these.
#ifdef NDEBUG
#define INL GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
#else
// Avoid excessive inlining in non-optimized builds. Without other optimizations
// the inlining is not going to provide benefits anyway and the huge resulting
// functions, especially in the proto-generated serialization functions, produce
// stack frames so large that many tests run into stack overflows (b/32192897).
#define INL
#endif
// Read fields, not including tags. The assumption is that you already
// read the tag to determine what field to read.
// For primitive fields, we just use a templatized routine parameterized by
// the represented type and the FieldType. These are specialized with the
// appropriate definition for each declared type.
template <typename CType, enum FieldType DeclaredType>
INL static bool ReadPrimitive(io::CodedInputStream* input, CType* value);
// Reads repeated primitive values, with optimizations for repeats.
// tag_size and tag should both be compile-time constants provided by the
// protocol compiler.
template <typename CType, enum FieldType DeclaredType>
INL static bool ReadRepeatedPrimitive(int tag_size, uint32 tag,
io::CodedInputStream* input,
RepeatedField<CType>* value);
// Identical to ReadRepeatedPrimitive, except will not inline the
// implementation.
template <typename CType, enum FieldType DeclaredType>
static bool ReadRepeatedPrimitiveNoInline(int tag_size, uint32 tag,
io::CodedInputStream* input,
RepeatedField<CType>* value);
// Reads a primitive value directly from the provided buffer. It returns a
// pointer past the segment of data that was read.
//
// This is only implemented for the types with fixed wire size, e.g.
// float, double, and the (s)fixed* types.
template <typename CType, enum FieldType DeclaredType> INL
static const uint8* ReadPrimitiveFromArray(const uint8* buffer, CType* value);
// Reads a primitive packed field.
//
// This is only implemented for packable types.
template <typename CType, enum FieldType DeclaredType>
INL static bool ReadPackedPrimitive(io::CodedInputStream* input,
RepeatedField<CType>* value);
// Identical to ReadPackedPrimitive, except will not inline the
// implementation.
template <typename CType, enum FieldType DeclaredType>
static bool ReadPackedPrimitiveNoInline(io::CodedInputStream* input,
RepeatedField<CType>* value);
// Read a packed enum field. If the is_valid function is not NULL, values for
// which is_valid(value) returns false are silently dropped.
static bool ReadPackedEnumNoInline(io::CodedInputStream* input,
bool (*is_valid)(int),
RepeatedField<int>* values);
// Read a packed enum field. If the is_valid function is not NULL, values for
// which is_valid(value) returns false are appended to unknown_fields_stream.
static bool ReadPackedEnumPreserveUnknowns(
io::CodedInputStream* input, int field_number, bool (*is_valid)(int),
io::CodedOutputStream* unknown_fields_stream, RepeatedField<int>* values);
// Read a string. ReadString(..., string* value) requires an existing string.
static inline bool ReadString(io::CodedInputStream* input, string* value);
// ReadString(..., string** p) is internal-only, and should only be called
// from generated code. It starts by setting *p to "new string"
// if *p == &GetEmptyStringAlreadyInited(). It then invokes
// ReadString(io::CodedInputStream* input, *p). This is useful for reducing
// code size.
static inline bool ReadString(io::CodedInputStream* input, string** p);
// Analogous to ReadString().
static bool ReadBytes(io::CodedInputStream* input, string* value);
static bool ReadBytes(io::CodedInputStream* input, string** p);
enum Operation {
PARSE = 0,
SERIALIZE = 1,
};
// Returns true if the data is valid UTF-8.
static bool VerifyUtf8String(const char* data, int size,
Operation op,
const char* field_name);
template <typename MessageType>
static inline bool ReadGroup(int field_number, io::CodedInputStream* input,
MessageType* value);
template <typename MessageType>
static inline bool ReadMessage(io::CodedInputStream* input,
MessageType* value);
// Do not use.
template <typename MessageType>
static inline bool ReadGroupNoVirtual(int field_number,
io::CodedInputStream* input,
MessageType* value) {
return ReadGroup(field_number, input, value);
}
template<typename MessageType>
static inline bool ReadMessageNoVirtual(io::CodedInputStream* input,
MessageType* value) {
return ReadMessage(input, value);
}
// Write a tag. The Write*() functions typically include the tag, so
// normally there's no need to call this unless using the Write*NoTag()
// variants.
INL static void WriteTag(int field_number, WireType type,
io::CodedOutputStream* output);
// Write fields, without tags.
INL static void WriteInt32NoTag(int32 value, io::CodedOutputStream* output);
INL static void WriteInt64NoTag(int64 value, io::CodedOutputStream* output);
INL static void WriteUInt32NoTag(uint32 value, io::CodedOutputStream* output);
INL static void WriteUInt64NoTag(uint64 value, io::CodedOutputStream* output);
INL static void WriteSInt32NoTag(int32 value, io::CodedOutputStream* output);
INL static void WriteSInt64NoTag(int64 value, io::CodedOutputStream* output);
INL static void WriteFixed32NoTag(uint32 value,
io::CodedOutputStream* output);
INL static void WriteFixed64NoTag(uint64 value,
io::CodedOutputStream* output);
INL static void WriteSFixed32NoTag(int32 value,
io::CodedOutputStream* output);
INL static void WriteSFixed64NoTag(int64 value,
io::CodedOutputStream* output);
INL static void WriteFloatNoTag(float value, io::CodedOutputStream* output);
INL static void WriteDoubleNoTag(double value, io::CodedOutputStream* output);
INL static void WriteBoolNoTag(bool value, io::CodedOutputStream* output);
INL static void WriteEnumNoTag(int value, io::CodedOutputStream* output);
// Write array of primitive fields, without tags
static void WriteFloatArray(const float* a, int n,
io::CodedOutputStream* output);
static void WriteDoubleArray(const double* a, int n,
io::CodedOutputStream* output);
static void WriteFixed32Array(const uint32* a, int n,
io::CodedOutputStream* output);
static void WriteFixed64Array(const uint64* a, int n,
io::CodedOutputStream* output);
static void WriteSFixed32Array(const int32* a, int n,
io::CodedOutputStream* output);
static void WriteSFixed64Array(const int64* a, int n,
io::CodedOutputStream* output);
static void WriteBoolArray(const bool* a, int n,
io::CodedOutputStream* output);
// Write fields, including tags.
static void WriteInt32(int field_number, int32 value,
io::CodedOutputStream* output);
static void WriteInt64(int field_number, int64 value,
io::CodedOutputStream* output);
static void WriteUInt32(int field_number, uint32 value,
io::CodedOutputStream* output);
static void WriteUInt64(int field_number, uint64 value,
io::CodedOutputStream* output);
static void WriteSInt32(int field_number, int32 value,
io::CodedOutputStream* output);
static void WriteSInt64(int field_number, int64 value,
io::CodedOutputStream* output);
static void WriteFixed32(int field_number, uint32 value,
io::CodedOutputStream* output);
static void WriteFixed64(int field_number, uint64 value,
io::CodedOutputStream* output);
static void WriteSFixed32(int field_number, int32 value,
io::CodedOutputStream* output);
static void WriteSFixed64(int field_number, int64 value,
io::CodedOutputStream* output);
static void WriteFloat(int field_number, float value,
io::CodedOutputStream* output);
static void WriteDouble(int field_number, double value,
io::CodedOutputStream* output);
static void WriteBool(int field_number, bool value,
io::CodedOutputStream* output);
static void WriteEnum(int field_number, int value,
io::CodedOutputStream* output);
static void WriteString(int field_number, const string& value,
io::CodedOutputStream* output);
static void WriteBytes(int field_number, const string& value,
io::CodedOutputStream* output);
static void WriteStringMaybeAliased(int field_number, const string& value,
io::CodedOutputStream* output);
static void WriteBytesMaybeAliased(int field_number, const string& value,
io::CodedOutputStream* output);
static void WriteGroup(int field_number, const MessageLite& value,
io::CodedOutputStream* output);
static void WriteMessage(int field_number, const MessageLite& value,
io::CodedOutputStream* output);
// Like above, but these will check if the output stream has enough
// space to write directly to a flat array.
static void WriteGroupMaybeToArray(int field_number, const MessageLite& value,
io::CodedOutputStream* output);
static void WriteMessageMaybeToArray(int field_number,
const MessageLite& value,
io::CodedOutputStream* output);
// Like above, but de-virtualize the call to SerializeWithCachedSizes(). The
// pointer must point at an instance of MessageType, *not* a subclass (or
// the subclass must not override SerializeWithCachedSizes()).
template <typename MessageType>
static inline void WriteGroupNoVirtual(int field_number,
const MessageType& value,
io::CodedOutputStream* output);
template <typename MessageType>
static inline void WriteMessageNoVirtual(int field_number,
const MessageType& value,
io::CodedOutputStream* output);
// Like above, but use only *ToArray methods of CodedOutputStream.
INL static uint8* WriteTagToArray(int field_number, WireType type,
uint8* target);
// Write fields, without tags.
INL static uint8* WriteInt32NoTagToArray(int32 value, uint8* target);
INL static uint8* WriteInt64NoTagToArray(int64 value, uint8* target);
INL static uint8* WriteUInt32NoTagToArray(uint32 value, uint8* target);
INL static uint8* WriteUInt64NoTagToArray(uint64 value, uint8* target);
INL static uint8* WriteSInt32NoTagToArray(int32 value, uint8* target);
INL static uint8* WriteSInt64NoTagToArray(int64 value, uint8* target);
INL static uint8* WriteFixed32NoTagToArray(uint32 value, uint8* target);
INL static uint8* WriteFixed64NoTagToArray(uint64 value, uint8* target);
INL static uint8* WriteSFixed32NoTagToArray(int32 value, uint8* target);
INL static uint8* WriteSFixed64NoTagToArray(int64 value, uint8* target);
INL static uint8* WriteFloatNoTagToArray(float value, uint8* target);
INL static uint8* WriteDoubleNoTagToArray(double value, uint8* target);
INL static uint8* WriteBoolNoTagToArray(bool value, uint8* target);
INL static uint8* WriteEnumNoTagToArray(int value, uint8* target);
// Write fields, without tags. These require that value.size() > 0.
template<typename T>
INL static uint8* WritePrimitiveNoTagToArray(
const RepeatedField<T>& value,
uint8* (*Writer)(T, uint8*), uint8* target);
template<typename T>
INL static uint8* WriteFixedNoTagToArray(
const RepeatedField<T>& value,
uint8* (*Writer)(T, uint8*), uint8* target);
INL static uint8* WriteInt32NoTagToArray(
const RepeatedField< int32>& value, uint8* output);
INL static uint8* WriteInt64NoTagToArray(
const RepeatedField< int64>& value, uint8* output);
INL static uint8* WriteUInt32NoTagToArray(
const RepeatedField<uint32>& value, uint8* output);
INL static uint8* WriteUInt64NoTagToArray(
const RepeatedField<uint64>& value, uint8* output);
INL static uint8* WriteSInt32NoTagToArray(
const RepeatedField< int32>& value, uint8* output);
INL static uint8* WriteSInt64NoTagToArray(
const RepeatedField< int64>& value, uint8* output);
INL static uint8* WriteFixed32NoTagToArray(
const RepeatedField<uint32>& value, uint8* output);
INL static uint8* WriteFixed64NoTagToArray(
const RepeatedField<uint64>& value, uint8* output);
INL static uint8* WriteSFixed32NoTagToArray(
const RepeatedField< int32>& value, uint8* output);
INL static uint8* WriteSFixed64NoTagToArray(
const RepeatedField< int64>& value, uint8* output);
INL static uint8* WriteFloatNoTagToArray(
const RepeatedField< float>& value, uint8* output);
INL static uint8* WriteDoubleNoTagToArray(
const RepeatedField<double>& value, uint8* output);
INL static uint8* WriteBoolNoTagToArray(
const RepeatedField< bool>& value, uint8* output);
INL static uint8* WriteEnumNoTagToArray(
const RepeatedField< int>& value, uint8* output);
// Write fields, including tags.
INL static uint8* WriteInt32ToArray(int field_number, int32 value,
uint8* target);
INL static uint8* WriteInt64ToArray(int field_number, int64 value,
uint8* target);
INL static uint8* WriteUInt32ToArray(int field_number, uint32 value,
uint8* target);
INL static uint8* WriteUInt64ToArray(int field_number, uint64 value,
uint8* target);
INL static uint8* WriteSInt32ToArray(int field_number, int32 value,
uint8* target);
INL static uint8* WriteSInt64ToArray(int field_number, int64 value,
uint8* target);
INL static uint8* WriteFixed32ToArray(int field_number, uint32 value,
uint8* target);
INL static uint8* WriteFixed64ToArray(int field_number, uint64 value,
uint8* target);
INL static uint8* WriteSFixed32ToArray(int field_number, int32 value,
uint8* target);
INL static uint8* WriteSFixed64ToArray(int field_number, int64 value,
uint8* target);
INL static uint8* WriteFloatToArray(int field_number, float value,
uint8* target);
INL static uint8* WriteDoubleToArray(int field_number, double value,
uint8* target);
INL static uint8* WriteBoolToArray(int field_number, bool value,
uint8* target);
INL static uint8* WriteEnumToArray(int field_number, int value,
uint8* target);
template<typename T>
INL static uint8* WritePrimitiveToArray(
int field_number,
const RepeatedField<T>& value,
uint8* (*Writer)(int, T, uint8*), uint8* target);
INL static uint8* WriteInt32ToArray(
int field_number, const RepeatedField< int32>& value, uint8* output);
INL static uint8* WriteInt64ToArray(
int field_number, const RepeatedField< int64>& value, uint8* output);
INL static uint8* WriteUInt32ToArray(
int field_number, const RepeatedField<uint32>& value, uint8* output);
INL static uint8* WriteUInt64ToArray(
int field_number, const RepeatedField<uint64>& value, uint8* output);
INL static uint8* WriteSInt32ToArray(
int field_number, const RepeatedField< int32>& value, uint8* output);
INL static uint8* WriteSInt64ToArray(
int field_number, const RepeatedField< int64>& value, uint8* output);
INL static uint8* WriteFixed32ToArray(
int field_number, const RepeatedField<uint32>& value, uint8* output);
INL static uint8* WriteFixed64ToArray(
int field_number, const RepeatedField<uint64>& value, uint8* output);
INL static uint8* WriteSFixed32ToArray(
int field_number, const RepeatedField< int32>& value, uint8* output);
INL static uint8* WriteSFixed64ToArray(
int field_number, const RepeatedField< int64>& value, uint8* output);
INL static uint8* WriteFloatToArray(
int field_number, const RepeatedField< float>& value, uint8* output);
INL static uint8* WriteDoubleToArray(
int field_number, const RepeatedField<double>& value, uint8* output);
INL static uint8* WriteBoolToArray(
int field_number, const RepeatedField< bool>& value, uint8* output);
INL static uint8* WriteEnumToArray(
int field_number, const RepeatedField< int>& value, uint8* output);
INL static uint8* WriteStringToArray(int field_number, const string& value,
uint8* target);
INL static uint8* WriteBytesToArray(int field_number, const string& value,
uint8* target);
// Whether to serialize deterministically (e.g., map keys are
// sorted) is a property of a CodedOutputStream, and in the process
// of serialization, the "ToArray" variants may be invoked. But they don't
// have a CodedOutputStream available, so they get an additional parameter
// telling them whether to serialize deterministically.
template<typename MessageType>
INL static uint8* InternalWriteGroupToArray(int field_number,
const MessageType& value,
bool deterministic,
uint8* target);
template<typename MessageType>
INL static uint8* InternalWriteMessageToArray(int field_number,
const MessageType& value,
bool deterministic,
uint8* target);
// Like above, but de-virtualize the call to SerializeWithCachedSizes(). The
// pointer must point at an instance of MessageType, *not* a subclass (or
// the subclass must not override SerializeWithCachedSizes()).
template <typename MessageType>
INL static uint8* InternalWriteGroupNoVirtualToArray(int field_number,
const MessageType& value,
bool deterministic,
uint8* target);
template <typename MessageType>
INL static uint8* InternalWriteMessageNoVirtualToArray(
int field_number, const MessageType& value, bool deterministic,
uint8* target);
// For backward-compatibility, the last four methods also have versions
// that are non-deterministic always.
INL static uint8* WriteGroupToArray(int field_number,
const MessageLite& value, uint8* target) {
return InternalWriteGroupToArray(field_number, value, false, target);
}
INL static uint8* WriteMessageToArray(int field_number,
const MessageLite& value,
uint8* target) {
return InternalWriteMessageToArray(field_number, value, false, target);
}
template <typename MessageType>
INL static uint8* WriteGroupNoVirtualToArray(int field_number,
const MessageType& value,
uint8* target) {
return InternalWriteGroupNoVirtualToArray(field_number, value, false,
target);
}
template <typename MessageType>
INL static uint8* WriteMessageNoVirtualToArray(int field_number,
const MessageType& value,
uint8* target) {
return InternalWriteMessageNoVirtualToArray(field_number, value, false,
target);
}
#undef INL
// Compute the byte size of a field. The XxSize() functions do NOT include
// the tag, so you must also call TagSize(). (This is because, for repeated
// fields, you should only call TagSize() once and multiply it by the element
// count, but you may have to call XxSize() for each individual element.)
static inline size_t Int32Size ( int32 value);
static inline size_t Int64Size ( int64 value);
static inline size_t UInt32Size (uint32 value);
static inline size_t UInt64Size (uint64 value);
static inline size_t SInt32Size ( int32 value);
static inline size_t SInt64Size ( int64 value);
static inline size_t EnumSize ( int value);
static size_t Int32Size (const RepeatedField< int32>& value);
static size_t Int64Size (const RepeatedField< int64>& value);
static size_t UInt32Size(const RepeatedField<uint32>& value);
static size_t UInt64Size(const RepeatedField<uint64>& value);
static size_t SInt32Size(const RepeatedField< int32>& value);
static size_t SInt64Size(const RepeatedField< int64>& value);
static size_t EnumSize (const RepeatedField< int>& value);
// These types always have the same size.
static const size_t kFixed32Size = 4;
static const size_t kFixed64Size = 8;
static const size_t kSFixed32Size = 4;
static const size_t kSFixed64Size = 8;
static const size_t kFloatSize = 4;
static const size_t kDoubleSize = 8;
static const size_t kBoolSize = 1;
static inline size_t StringSize(const string& value);
static inline size_t BytesSize (const string& value);
template<typename MessageType>
static inline size_t GroupSize (const MessageType& value);
template<typename MessageType>
static inline size_t MessageSize(const MessageType& value);
// Like above, but de-virtualize the call to ByteSize(). The
// pointer must point at an instance of MessageType, *not* a subclass (or
// the subclass must not override ByteSize()).
template<typename MessageType>
static inline size_t GroupSizeNoVirtual (const MessageType& value);
template<typename MessageType>
static inline size_t MessageSizeNoVirtual(const MessageType& value);
// Given the length of data, calculate the byte size of the data on the
// wire if we encode the data as a length delimited field.
static inline size_t LengthDelimitedSize(size_t length);
private:
// A helper method for the repeated primitive reader. This method has
// optimizations for primitive types that have fixed size on the wire, and
// can be read using potentially faster paths.
template <typename CType, enum FieldType DeclaredType>
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
static bool ReadRepeatedFixedSizePrimitive(
int tag_size,
uint32 tag,
google::protobuf::io::CodedInputStream* input,
RepeatedField<CType>* value);
// Like ReadRepeatedFixedSizePrimitive but for packed primitive fields.
template <typename CType, enum FieldType DeclaredType>
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
static bool ReadPackedFixedSizePrimitive(
google::protobuf::io::CodedInputStream* input, RepeatedField<CType>* value);
static const CppType kFieldTypeToCppTypeMap[];
static const WireFormatLite::WireType kWireTypeForFieldType[];
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(WireFormatLite);
};
// A class which deals with unknown values. The default implementation just
// discards them. WireFormat defines a subclass which writes to an
// UnknownFieldSet. This class is used by ExtensionSet::ParseField(), since
// ExtensionSet is part of the lite library but UnknownFieldSet is not.
class LIBPROTOBUF_EXPORT FieldSkipper {
public:
FieldSkipper() {}
virtual ~FieldSkipper() {}
// Skip a field whose tag has already been consumed.
virtual bool SkipField(io::CodedInputStream* input, uint32 tag);
// Skip an entire message or group, up to an end-group tag (which is consumed)
// or end-of-stream.
virtual bool SkipMessage(io::CodedInputStream* input);
// Deal with an already-parsed unrecognized enum value. The default
// implementation does nothing, but the UnknownFieldSet-based implementation
// saves it as an unknown varint.
virtual void SkipUnknownEnum(int field_number, int value);
};
// Subclass of FieldSkipper which saves skipped fields to a CodedOutputStream.
class LIBPROTOBUF_EXPORT CodedOutputStreamFieldSkipper : public FieldSkipper {
public:
explicit CodedOutputStreamFieldSkipper(io::CodedOutputStream* unknown_fields)
: unknown_fields_(unknown_fields) {}
virtual ~CodedOutputStreamFieldSkipper() {}
// implements FieldSkipper -----------------------------------------
virtual bool SkipField(io::CodedInputStream* input, uint32 tag);
virtual bool SkipMessage(io::CodedInputStream* input);
virtual void SkipUnknownEnum(int field_number, int value);
protected:
io::CodedOutputStream* unknown_fields_;
};
// inline methods ====================================================
inline WireFormatLite::CppType
WireFormatLite::FieldTypeToCppType(FieldType type) {
return kFieldTypeToCppTypeMap[type];
}
inline uint32 WireFormatLite::MakeTag(int field_number, WireType type) {
return GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(field_number, type);
}
inline WireFormatLite::WireType WireFormatLite::GetTagWireType(uint32 tag) {
return static_cast<WireType>(tag & kTagTypeMask);
}
inline int WireFormatLite::GetTagFieldNumber(uint32 tag) {
return static_cast<int>(tag >> kTagTypeBits);
}
inline size_t WireFormatLite::TagSize(int field_number,
WireFormatLite::FieldType type) {
size_t result = io::CodedOutputStream::VarintSize32(
static_cast<uint32>(field_number << kTagTypeBits));
if (type == TYPE_GROUP) {
// Groups have both a start and an end tag.
return result * 2;
} else {
return result;
}
}
inline uint32 WireFormatLite::EncodeFloat(float value) {
union {float f; uint32 i;};
f = value;
return i;
}
inline float WireFormatLite::DecodeFloat(uint32 value) {
union {float f; uint32 i;};
i = value;
return f;
}
inline uint64 WireFormatLite::EncodeDouble(double value) {
union {double f; uint64 i;};
f = value;
return i;
}
inline double WireFormatLite::DecodeDouble(uint64 value) {
union {double f; uint64 i;};
i = value;
return f;
}
// ZigZag Transform: Encodes signed integers so that they can be
// effectively used with varint encoding.
//
// varint operates on unsigned integers, encoding smaller numbers into
// fewer bytes. If you try to use it on a signed integer, it will treat
// this number as a very large unsigned integer, which means that even
// small signed numbers like -1 will take the maximum number of bytes
// (10) to encode. ZigZagEncode() maps signed integers to unsigned
// in such a way that those with a small absolute value will have smaller
// encoded values, making them appropriate for encoding using varint.
//
// int32 -> uint32
// -------------------------
// 0 -> 0
// -1 -> 1
// 1 -> 2
// -2 -> 3
// ... -> ...
// 2147483647 -> 4294967294
// -2147483648 -> 4294967295
//
// >> encode >>
// << decode <<
inline uint32 WireFormatLite::ZigZagEncode32(int32 n) {
// Note: the right-shift must be arithmetic
// Note: left shift must be unsigned because of overflow
return (static_cast<uint32>(n) << 1) ^ static_cast<uint32>(n >> 31);
}
inline int32 WireFormatLite::ZigZagDecode32(uint32 n) {
// Note: Using unsigned types prevent undefined behavior
return static_cast<int32>((n >> 1) ^ (~(n & 1) + 1));
}
inline uint64 WireFormatLite::ZigZagEncode64(int64 n) {
// Note: the right-shift must be arithmetic
// Note: left shift must be unsigned because of overflow
return (static_cast<uint64>(n) << 1) ^ static_cast<uint64>(n >> 63);
}
inline int64 WireFormatLite::ZigZagDecode64(uint64 n) {
// Note: Using unsigned types prevent undefined behavior
return static_cast<int64>((n >> 1) ^ (~(n & 1) + 1));
}
// String is for UTF-8 text only, but, even so, ReadString() can simply
// call ReadBytes().
inline bool WireFormatLite::ReadString(io::CodedInputStream* input,
string* value) {
return ReadBytes(input, value);
}
inline bool WireFormatLite::ReadString(io::CodedInputStream* input,
string** p) {
return ReadBytes(input, p);
}
} // namespace internal
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_WIRE_FORMAT_LITE_H__

View File

@ -0,0 +1,996 @@
// 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)
// wink@google.com (Wink Saville) (refactored from wire_format.h)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
#ifndef GOOGLE_PROTOBUF_WIRE_FORMAT_LITE_INL_H__
#define GOOGLE_PROTOBUF_WIRE_FORMAT_LITE_INL_H__
#include <algorithm>
#include <string>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/message_lite.h>
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/wire_format_lite.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/arenastring.h>
namespace google {
namespace protobuf {
namespace internal {
// Implementation details of ReadPrimitive.
template <>
inline bool WireFormatLite::ReadPrimitive<int32, WireFormatLite::TYPE_INT32>(
io::CodedInputStream* input,
int32* value) {
uint32 temp;
if (!input->ReadVarint32(&temp)) return false;
*value = static_cast<int32>(temp);
return true;
}
template <>
inline bool WireFormatLite::ReadPrimitive<int64, WireFormatLite::TYPE_INT64>(
io::CodedInputStream* input,
int64* value) {
uint64 temp;
if (!input->ReadVarint64(&temp)) return false;
*value = static_cast<int64>(temp);
return true;
}
template <>
inline bool WireFormatLite::ReadPrimitive<uint32, WireFormatLite::TYPE_UINT32>(
io::CodedInputStream* input,
uint32* value) {
return input->ReadVarint32(value);
}
template <>
inline bool WireFormatLite::ReadPrimitive<uint64, WireFormatLite::TYPE_UINT64>(
io::CodedInputStream* input,
uint64* value) {
return input->ReadVarint64(value);
}
template <>
inline bool WireFormatLite::ReadPrimitive<int32, WireFormatLite::TYPE_SINT32>(
io::CodedInputStream* input,
int32* value) {
uint32 temp;
if (!input->ReadVarint32(&temp)) return false;
*value = ZigZagDecode32(temp);
return true;
}
template <>
inline bool WireFormatLite::ReadPrimitive<int64, WireFormatLite::TYPE_SINT64>(
io::CodedInputStream* input,
int64* value) {
uint64 temp;
if (!input->ReadVarint64(&temp)) return false;
*value = ZigZagDecode64(temp);
return true;
}
template <>
inline bool WireFormatLite::ReadPrimitive<uint32, WireFormatLite::TYPE_FIXED32>(
io::CodedInputStream* input,
uint32* value) {
return input->ReadLittleEndian32(value);
}
template <>
inline bool WireFormatLite::ReadPrimitive<uint64, WireFormatLite::TYPE_FIXED64>(
io::CodedInputStream* input,
uint64* value) {
return input->ReadLittleEndian64(value);
}
template <>
inline bool WireFormatLite::ReadPrimitive<int32, WireFormatLite::TYPE_SFIXED32>(
io::CodedInputStream* input,
int32* value) {
uint32 temp;
if (!input->ReadLittleEndian32(&temp)) return false;
*value = static_cast<int32>(temp);
return true;
}
template <>
inline bool WireFormatLite::ReadPrimitive<int64, WireFormatLite::TYPE_SFIXED64>(
io::CodedInputStream* input,
int64* value) {
uint64 temp;
if (!input->ReadLittleEndian64(&temp)) return false;
*value = static_cast<int64>(temp);
return true;
}
template <>
inline bool WireFormatLite::ReadPrimitive<float, WireFormatLite::TYPE_FLOAT>(
io::CodedInputStream* input,
float* value) {
uint32 temp;
if (!input->ReadLittleEndian32(&temp)) return false;
*value = DecodeFloat(temp);
return true;
}
template <>
inline bool WireFormatLite::ReadPrimitive<double, WireFormatLite::TYPE_DOUBLE>(
io::CodedInputStream* input,
double* value) {
uint64 temp;
if (!input->ReadLittleEndian64(&temp)) return false;
*value = DecodeDouble(temp);
return true;
}
template <>
inline bool WireFormatLite::ReadPrimitive<bool, WireFormatLite::TYPE_BOOL>(
io::CodedInputStream* input,
bool* value) {
uint64 temp;
if (!input->ReadVarint64(&temp)) return false;
*value = temp != 0;
return true;
}
template <>
inline bool WireFormatLite::ReadPrimitive<int, WireFormatLite::TYPE_ENUM>(
io::CodedInputStream* input,
int* value) {
uint32 temp;
if (!input->ReadVarint32(&temp)) return false;
*value = static_cast<int>(temp);
return true;
}
template <>
inline const uint8* WireFormatLite::ReadPrimitiveFromArray<
uint32, WireFormatLite::TYPE_FIXED32>(
const uint8* buffer,
uint32* value) {
return io::CodedInputStream::ReadLittleEndian32FromArray(buffer, value);
}
template <>
inline const uint8* WireFormatLite::ReadPrimitiveFromArray<
uint64, WireFormatLite::TYPE_FIXED64>(
const uint8* buffer,
uint64* value) {
return io::CodedInputStream::ReadLittleEndian64FromArray(buffer, value);
}
template <>
inline const uint8* WireFormatLite::ReadPrimitiveFromArray<
int32, WireFormatLite::TYPE_SFIXED32>(
const uint8* buffer,
int32* value) {
uint32 temp;
buffer = io::CodedInputStream::ReadLittleEndian32FromArray(buffer, &temp);
*value = static_cast<int32>(temp);
return buffer;
}
template <>
inline const uint8* WireFormatLite::ReadPrimitiveFromArray<
int64, WireFormatLite::TYPE_SFIXED64>(
const uint8* buffer,
int64* value) {
uint64 temp;
buffer = io::CodedInputStream::ReadLittleEndian64FromArray(buffer, &temp);
*value = static_cast<int64>(temp);
return buffer;
}
template <>
inline const uint8* WireFormatLite::ReadPrimitiveFromArray<
float, WireFormatLite::TYPE_FLOAT>(
const uint8* buffer,
float* value) {
uint32 temp;
buffer = io::CodedInputStream::ReadLittleEndian32FromArray(buffer, &temp);
*value = DecodeFloat(temp);
return buffer;
}
template <>
inline const uint8* WireFormatLite::ReadPrimitiveFromArray<
double, WireFormatLite::TYPE_DOUBLE>(
const uint8* buffer,
double* value) {
uint64 temp;
buffer = io::CodedInputStream::ReadLittleEndian64FromArray(buffer, &temp);
*value = DecodeDouble(temp);
return buffer;
}
template <typename CType, enum WireFormatLite::FieldType DeclaredType>
inline bool WireFormatLite::ReadRepeatedPrimitive(
int, // tag_size, unused.
uint32 tag,
io::CodedInputStream* input,
RepeatedField<CType>* values) {
CType value;
if (!ReadPrimitive<CType, DeclaredType>(input, &value)) return false;
values->Add(value);
int elements_already_reserved = values->Capacity() - values->size();
while (elements_already_reserved > 0 && input->ExpectTag(tag)) {
if (!ReadPrimitive<CType, DeclaredType>(input, &value)) return false;
values->AddAlreadyReserved(value);
elements_already_reserved--;
}
return true;
}
template <typename CType, enum WireFormatLite::FieldType DeclaredType>
inline bool WireFormatLite::ReadRepeatedFixedSizePrimitive(
int tag_size,
uint32 tag,
io::CodedInputStream* input,
RepeatedField<CType>* values) {
GOOGLE_DCHECK_EQ(UInt32Size(tag), static_cast<size_t>(tag_size));
CType value;
if (!ReadPrimitive<CType, DeclaredType>(input, &value))
return false;
values->Add(value);
// For fixed size values, repeated values can be read more quickly by
// reading directly from a raw array.
//
// We can get a tight loop by only reading as many elements as can be
// added to the RepeatedField without having to do any resizing. Additionally,
// we only try to read as many elements as are available from the current
// buffer space. Doing so avoids having to perform boundary checks when
// reading the value: the maximum number of elements that can be read is
// known outside of the loop.
const void* void_pointer;
int size;
input->GetDirectBufferPointerInline(&void_pointer, &size);
if (size > 0) {
const uint8* buffer = reinterpret_cast<const uint8*>(void_pointer);
// The number of bytes each type occupies on the wire.
const int per_value_size = tag_size + static_cast<int>(sizeof(value));
// parentheses around (std::min) prevents macro expansion of min(...)
int elements_available =
(std::min)(values->Capacity() - values->size(), size / per_value_size);
int num_read = 0;
while (num_read < elements_available &&
(buffer = io::CodedInputStream::ExpectTagFromArray(
buffer, tag)) != NULL) {
buffer = ReadPrimitiveFromArray<CType, DeclaredType>(buffer, &value);
values->AddAlreadyReserved(value);
++num_read;
}
const int read_bytes = num_read * per_value_size;
if (read_bytes > 0) {
input->Skip(read_bytes);
}
}
return true;
}
// Specializations of ReadRepeatedPrimitive for the fixed size types, which use
// the optimized code path.
#define READ_REPEATED_FIXED_SIZE_PRIMITIVE(CPPTYPE, DECLARED_TYPE) \
template <> \
inline bool WireFormatLite::ReadRepeatedPrimitive< \
CPPTYPE, WireFormatLite::DECLARED_TYPE>( \
int tag_size, \
uint32 tag, \
io::CodedInputStream* input, \
RepeatedField<CPPTYPE>* values) { \
return ReadRepeatedFixedSizePrimitive< \
CPPTYPE, WireFormatLite::DECLARED_TYPE>( \
tag_size, tag, input, values); \
}
READ_REPEATED_FIXED_SIZE_PRIMITIVE(uint32, TYPE_FIXED32)
READ_REPEATED_FIXED_SIZE_PRIMITIVE(uint64, TYPE_FIXED64)
READ_REPEATED_FIXED_SIZE_PRIMITIVE(int32, TYPE_SFIXED32)
READ_REPEATED_FIXED_SIZE_PRIMITIVE(int64, TYPE_SFIXED64)
READ_REPEATED_FIXED_SIZE_PRIMITIVE(float, TYPE_FLOAT)
READ_REPEATED_FIXED_SIZE_PRIMITIVE(double, TYPE_DOUBLE)
#undef READ_REPEATED_FIXED_SIZE_PRIMITIVE
template <typename CType, enum WireFormatLite::FieldType DeclaredType>
bool WireFormatLite::ReadRepeatedPrimitiveNoInline(
int tag_size,
uint32 tag,
io::CodedInputStream* input,
RepeatedField<CType>* value) {
return ReadRepeatedPrimitive<CType, DeclaredType>(
tag_size, tag, input, value);
}
template <typename CType, enum WireFormatLite::FieldType DeclaredType>
inline bool WireFormatLite::ReadPackedPrimitive(io::CodedInputStream* input,
RepeatedField<CType>* values) {
int length;
if (!input->ReadVarintSizeAsInt(&length)) return false;
io::CodedInputStream::Limit limit = input->PushLimit(length);
while (input->BytesUntilLimit() > 0) {
CType value;
if (!ReadPrimitive<CType, DeclaredType>(input, &value)) return false;
values->Add(value);
}
input->PopLimit(limit);
return true;
}
template <typename CType, enum WireFormatLite::FieldType DeclaredType>
inline bool WireFormatLite::ReadPackedFixedSizePrimitive(
io::CodedInputStream* input, RepeatedField<CType>* values) {
int length;
if (!input->ReadVarintSizeAsInt(&length)) return false;
const int old_entries = values->size();
const int new_entries = length / static_cast<int>(sizeof(CType));
const int new_bytes = new_entries * static_cast<int>(sizeof(CType));
if (new_bytes != length) return false;
// We would *like* to pre-allocate the buffer to write into (for
// speed), but *must* avoid performing a very large allocation due
// to a malicious user-supplied "length" above. So we have a fast
// path that pre-allocates when the "length" is less than a bound.
// We determine the bound by calling BytesUntilTotalBytesLimit() and
// BytesUntilLimit(). These return -1 to mean "no limit set".
// There are four cases:
// TotalBytesLimit Limit
// -1 -1 Use slow path.
// -1 >= 0 Use fast path if length <= Limit.
// >= 0 -1 Use slow path.
// >= 0 >= 0 Use fast path if length <= min(both limits).
int64 bytes_limit = input->BytesUntilTotalBytesLimit();
if (bytes_limit == -1) {
bytes_limit = input->BytesUntilLimit();
} else {
// parentheses around (std::min) prevents macro expansion of min(...)
bytes_limit =
(std::min)(bytes_limit, static_cast<int64>(input->BytesUntilLimit()));
}
if (bytes_limit >= new_bytes) {
// Fast-path that pre-allocates *values to the final size.
#if defined(PROTOBUF_LITTLE_ENDIAN)
values->Resize(old_entries + new_entries, 0);
// values->mutable_data() may change after Resize(), so do this after:
void* dest = reinterpret_cast<void*>(values->mutable_data() + old_entries);
if (!input->ReadRaw(dest, new_bytes)) {
values->Truncate(old_entries);
return false;
}
#else
values->Reserve(old_entries + new_entries);
CType value;
for (int i = 0; i < new_entries; ++i) {
if (!ReadPrimitive<CType, DeclaredType>(input, &value)) return false;
values->AddAlreadyReserved(value);
}
#endif
} else {
// This is the slow-path case where "length" may be too large to
// safely allocate. We read as much as we can into *values
// without pre-allocating "length" bytes.
CType value;
for (int i = 0; i < new_entries; ++i) {
if (!ReadPrimitive<CType, DeclaredType>(input, &value)) return false;
values->Add(value);
}
}
return true;
}
// Specializations of ReadPackedPrimitive for the fixed size types, which use
// an optimized code path.
#define READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(CPPTYPE, DECLARED_TYPE) \
template <> \
inline bool WireFormatLite::ReadPackedPrimitive< \
CPPTYPE, WireFormatLite::DECLARED_TYPE>( \
io::CodedInputStream* input, \
RepeatedField<CPPTYPE>* values) { \
return ReadPackedFixedSizePrimitive< \
CPPTYPE, WireFormatLite::DECLARED_TYPE>(input, values); \
}
READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(uint32, TYPE_FIXED32)
READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(uint64, TYPE_FIXED64)
READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(int32, TYPE_SFIXED32)
READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(int64, TYPE_SFIXED64)
READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(float, TYPE_FLOAT)
READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(double, TYPE_DOUBLE)
#undef READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE
template <typename CType, enum WireFormatLite::FieldType DeclaredType>
bool WireFormatLite::ReadPackedPrimitiveNoInline(io::CodedInputStream* input,
RepeatedField<CType>* values) {
return ReadPackedPrimitive<CType, DeclaredType>(input, values);
}
template<typename MessageType>
inline bool WireFormatLite::ReadGroup(
int field_number, io::CodedInputStream* input,
MessageType* value) {
if (!input->IncrementRecursionDepth()) return false;
if (!value->MergePartialFromCodedStream(input)) return false;
input->UnsafeDecrementRecursionDepth();
// Make sure the last thing read was an end tag for this group.
if (!input->LastTagWas(MakeTag(field_number, WIRETYPE_END_GROUP))) {
return false;
}
return true;
}
template<typename MessageType>
inline bool WireFormatLite::ReadMessage(
io::CodedInputStream* input, MessageType* value) {
int length;
if (!input->ReadVarintSizeAsInt(&length)) return false;
std::pair<io::CodedInputStream::Limit, int> p =
input->IncrementRecursionDepthAndPushLimit(length);
if (p.second < 0 || !value->MergePartialFromCodedStream(input)) return false;
// Make sure that parsing stopped when the limit was hit, not at an endgroup
// tag.
return input->DecrementRecursionDepthAndPopLimit(p.first);
}
// ===================================================================
inline void WireFormatLite::WriteTag(int field_number, WireType type,
io::CodedOutputStream* output) {
output->WriteTag(MakeTag(field_number, type));
}
inline void WireFormatLite::WriteInt32NoTag(int32 value,
io::CodedOutputStream* output) {
output->WriteVarint32SignExtended(value);
}
inline void WireFormatLite::WriteInt64NoTag(int64 value,
io::CodedOutputStream* output) {
output->WriteVarint64(static_cast<uint64>(value));
}
inline void WireFormatLite::WriteUInt32NoTag(uint32 value,
io::CodedOutputStream* output) {
output->WriteVarint32(value);
}
inline void WireFormatLite::WriteUInt64NoTag(uint64 value,
io::CodedOutputStream* output) {
output->WriteVarint64(value);
}
inline void WireFormatLite::WriteSInt32NoTag(int32 value,
io::CodedOutputStream* output) {
output->WriteVarint32(ZigZagEncode32(value));
}
inline void WireFormatLite::WriteSInt64NoTag(int64 value,
io::CodedOutputStream* output) {
output->WriteVarint64(ZigZagEncode64(value));
}
inline void WireFormatLite::WriteFixed32NoTag(uint32 value,
io::CodedOutputStream* output) {
output->WriteLittleEndian32(value);
}
inline void WireFormatLite::WriteFixed64NoTag(uint64 value,
io::CodedOutputStream* output) {
output->WriteLittleEndian64(value);
}
inline void WireFormatLite::WriteSFixed32NoTag(int32 value,
io::CodedOutputStream* output) {
output->WriteLittleEndian32(static_cast<uint32>(value));
}
inline void WireFormatLite::WriteSFixed64NoTag(int64 value,
io::CodedOutputStream* output) {
output->WriteLittleEndian64(static_cast<uint64>(value));
}
inline void WireFormatLite::WriteFloatNoTag(float value,
io::CodedOutputStream* output) {
output->WriteLittleEndian32(EncodeFloat(value));
}
inline void WireFormatLite::WriteDoubleNoTag(double value,
io::CodedOutputStream* output) {
output->WriteLittleEndian64(EncodeDouble(value));
}
inline void WireFormatLite::WriteBoolNoTag(bool value,
io::CodedOutputStream* output) {
output->WriteVarint32(value ? 1 : 0);
}
inline void WireFormatLite::WriteEnumNoTag(int value,
io::CodedOutputStream* output) {
output->WriteVarint32SignExtended(value);
}
// See comment on ReadGroupNoVirtual to understand the need for this template
// parameter name.
template<typename MessageType_WorkAroundCppLookupDefect>
inline void WireFormatLite::WriteGroupNoVirtual(
int field_number, const MessageType_WorkAroundCppLookupDefect& value,
io::CodedOutputStream* output) {
WriteTag(field_number, WIRETYPE_START_GROUP, output);
value.MessageType_WorkAroundCppLookupDefect::SerializeWithCachedSizes(output);
WriteTag(field_number, WIRETYPE_END_GROUP, output);
}
template<typename MessageType_WorkAroundCppLookupDefect>
inline void WireFormatLite::WriteMessageNoVirtual(
int field_number, const MessageType_WorkAroundCppLookupDefect& value,
io::CodedOutputStream* output) {
WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output);
output->WriteVarint32(
value.MessageType_WorkAroundCppLookupDefect::GetCachedSize());
value.MessageType_WorkAroundCppLookupDefect::SerializeWithCachedSizes(output);
}
// ===================================================================
inline uint8* WireFormatLite::WriteTagToArray(int field_number,
WireType type,
uint8* target) {
return io::CodedOutputStream::WriteTagToArray(MakeTag(field_number, type),
target);
}
inline uint8* WireFormatLite::WriteInt32NoTagToArray(int32 value,
uint8* target) {
return io::CodedOutputStream::WriteVarint32SignExtendedToArray(value, target);
}
inline uint8* WireFormatLite::WriteInt64NoTagToArray(int64 value,
uint8* target) {
return io::CodedOutputStream::WriteVarint64ToArray(
static_cast<uint64>(value), target);
}
inline uint8* WireFormatLite::WriteUInt32NoTagToArray(uint32 value,
uint8* target) {
return io::CodedOutputStream::WriteVarint32ToArray(value, target);
}
inline uint8* WireFormatLite::WriteUInt64NoTagToArray(uint64 value,
uint8* target) {
return io::CodedOutputStream::WriteVarint64ToArray(value, target);
}
inline uint8* WireFormatLite::WriteSInt32NoTagToArray(int32 value,
uint8* target) {
return io::CodedOutputStream::WriteVarint32ToArray(ZigZagEncode32(value),
target);
}
inline uint8* WireFormatLite::WriteSInt64NoTagToArray(int64 value,
uint8* target) {
return io::CodedOutputStream::WriteVarint64ToArray(ZigZagEncode64(value),
target);
}
inline uint8* WireFormatLite::WriteFixed32NoTagToArray(uint32 value,
uint8* target) {
return io::CodedOutputStream::WriteLittleEndian32ToArray(value, target);
}
inline uint8* WireFormatLite::WriteFixed64NoTagToArray(uint64 value,
uint8* target) {
return io::CodedOutputStream::WriteLittleEndian64ToArray(value, target);
}
inline uint8* WireFormatLite::WriteSFixed32NoTagToArray(int32 value,
uint8* target) {
return io::CodedOutputStream::WriteLittleEndian32ToArray(
static_cast<uint32>(value), target);
}
inline uint8* WireFormatLite::WriteSFixed64NoTagToArray(int64 value,
uint8* target) {
return io::CodedOutputStream::WriteLittleEndian64ToArray(
static_cast<uint64>(value), target);
}
inline uint8* WireFormatLite::WriteFloatNoTagToArray(float value,
uint8* target) {
return io::CodedOutputStream::WriteLittleEndian32ToArray(EncodeFloat(value),
target);
}
inline uint8* WireFormatLite::WriteDoubleNoTagToArray(double value,
uint8* target) {
return io::CodedOutputStream::WriteLittleEndian64ToArray(EncodeDouble(value),
target);
}
inline uint8* WireFormatLite::WriteBoolNoTagToArray(bool value,
uint8* target) {
return io::CodedOutputStream::WriteVarint32ToArray(value ? 1 : 0, target);
}
inline uint8* WireFormatLite::WriteEnumNoTagToArray(int value,
uint8* target) {
return io::CodedOutputStream::WriteVarint32SignExtendedToArray(value, target);
}
template<typename T>
inline uint8* WireFormatLite::WritePrimitiveNoTagToArray(
const RepeatedField<T>& value,
uint8* (*Writer)(T, uint8*), uint8* target) {
const int n = value.size();
GOOGLE_DCHECK_GT(n, 0);
const T* ii = value.unsafe_data();
int i = 0;
do {
target = Writer(ii[i], target);
} while (++i < n);
return target;
}
template<typename T>
inline uint8* WireFormatLite::WriteFixedNoTagToArray(
const RepeatedField<T>& value,
uint8* (*Writer)(T, uint8*), uint8* target) {
#if defined(PROTOBUF_LITTLE_ENDIAN)
(void) Writer;
const int n = value.size();
GOOGLE_DCHECK_GT(n, 0);
const T* ii = value.unsafe_data();
const int bytes = n * static_cast<int>(sizeof(ii[0]));
memcpy(target, ii, static_cast<size_t>(bytes));
return target + bytes;
#else
return WritePrimitiveNoTagToArray(value, Writer, target);
#endif
}
inline uint8* WireFormatLite::WriteInt32NoTagToArray(
const RepeatedField< int32>& value, uint8* target) {
return WritePrimitiveNoTagToArray(value, WriteInt32NoTagToArray, target);
}
inline uint8* WireFormatLite::WriteInt64NoTagToArray(
const RepeatedField< int64>& value, uint8* target) {
return WritePrimitiveNoTagToArray(value, WriteInt64NoTagToArray, target);
}
inline uint8* WireFormatLite::WriteUInt32NoTagToArray(
const RepeatedField<uint32>& value, uint8* target) {
return WritePrimitiveNoTagToArray(value, WriteUInt32NoTagToArray, target);
}
inline uint8* WireFormatLite::WriteUInt64NoTagToArray(
const RepeatedField<uint64>& value, uint8* target) {
return WritePrimitiveNoTagToArray(value, WriteUInt64NoTagToArray, target);
}
inline uint8* WireFormatLite::WriteSInt32NoTagToArray(
const RepeatedField< int32>& value, uint8* target) {
return WritePrimitiveNoTagToArray(value, WriteSInt32NoTagToArray, target);
}
inline uint8* WireFormatLite::WriteSInt64NoTagToArray(
const RepeatedField< int64>& value, uint8* target) {
return WritePrimitiveNoTagToArray(value, WriteSInt64NoTagToArray, target);
}
inline uint8* WireFormatLite::WriteFixed32NoTagToArray(
const RepeatedField<uint32>& value, uint8* target) {
return WriteFixedNoTagToArray(value, WriteFixed32NoTagToArray, target);
}
inline uint8* WireFormatLite::WriteFixed64NoTagToArray(
const RepeatedField<uint64>& value, uint8* target) {
return WriteFixedNoTagToArray(value, WriteFixed64NoTagToArray, target);
}
inline uint8* WireFormatLite::WriteSFixed32NoTagToArray(
const RepeatedField< int32>& value, uint8* target) {
return WriteFixedNoTagToArray(value, WriteSFixed32NoTagToArray, target);
}
inline uint8* WireFormatLite::WriteSFixed64NoTagToArray(
const RepeatedField< int64>& value, uint8* target) {
return WriteFixedNoTagToArray(value, WriteSFixed64NoTagToArray, target);
}
inline uint8* WireFormatLite::WriteFloatNoTagToArray(
const RepeatedField< float>& value, uint8* target) {
return WriteFixedNoTagToArray(value, WriteFloatNoTagToArray, target);
}
inline uint8* WireFormatLite::WriteDoubleNoTagToArray(
const RepeatedField<double>& value, uint8* target) {
return WriteFixedNoTagToArray(value, WriteDoubleNoTagToArray, target);
}
inline uint8* WireFormatLite::WriteBoolNoTagToArray(
const RepeatedField< bool>& value, uint8* target) {
return WritePrimitiveNoTagToArray(value, WriteBoolNoTagToArray, target);
}
inline uint8* WireFormatLite::WriteEnumNoTagToArray(
const RepeatedField< int>& value, uint8* target) {
return WritePrimitiveNoTagToArray(value, WriteEnumNoTagToArray, target);
}
inline uint8* WireFormatLite::WriteInt32ToArray(int field_number,
int32 value,
uint8* target) {
target = WriteTagToArray(field_number, WIRETYPE_VARINT, target);
return WriteInt32NoTagToArray(value, target);
}
inline uint8* WireFormatLite::WriteInt64ToArray(int field_number,
int64 value,
uint8* target) {
target = WriteTagToArray(field_number, WIRETYPE_VARINT, target);
return WriteInt64NoTagToArray(value, target);
}
inline uint8* WireFormatLite::WriteUInt32ToArray(int field_number,
uint32 value,
uint8* target) {
target = WriteTagToArray(field_number, WIRETYPE_VARINT, target);
return WriteUInt32NoTagToArray(value, target);
}
inline uint8* WireFormatLite::WriteUInt64ToArray(int field_number,
uint64 value,
uint8* target) {
target = WriteTagToArray(field_number, WIRETYPE_VARINT, target);
return WriteUInt64NoTagToArray(value, target);
}
inline uint8* WireFormatLite::WriteSInt32ToArray(int field_number,
int32 value,
uint8* target) {
target = WriteTagToArray(field_number, WIRETYPE_VARINT, target);
return WriteSInt32NoTagToArray(value, target);
}
inline uint8* WireFormatLite::WriteSInt64ToArray(int field_number,
int64 value,
uint8* target) {
target = WriteTagToArray(field_number, WIRETYPE_VARINT, target);
return WriteSInt64NoTagToArray(value, target);
}
inline uint8* WireFormatLite::WriteFixed32ToArray(int field_number,
uint32 value,
uint8* target) {
target = WriteTagToArray(field_number, WIRETYPE_FIXED32, target);
return WriteFixed32NoTagToArray(value, target);
}
inline uint8* WireFormatLite::WriteFixed64ToArray(int field_number,
uint64 value,
uint8* target) {
target = WriteTagToArray(field_number, WIRETYPE_FIXED64, target);
return WriteFixed64NoTagToArray(value, target);
}
inline uint8* WireFormatLite::WriteSFixed32ToArray(int field_number,
int32 value,
uint8* target) {
target = WriteTagToArray(field_number, WIRETYPE_FIXED32, target);
return WriteSFixed32NoTagToArray(value, target);
}
inline uint8* WireFormatLite::WriteSFixed64ToArray(int field_number,
int64 value,
uint8* target) {
target = WriteTagToArray(field_number, WIRETYPE_FIXED64, target);
return WriteSFixed64NoTagToArray(value, target);
}
inline uint8* WireFormatLite::WriteFloatToArray(int field_number,
float value,
uint8* target) {
target = WriteTagToArray(field_number, WIRETYPE_FIXED32, target);
return WriteFloatNoTagToArray(value, target);
}
inline uint8* WireFormatLite::WriteDoubleToArray(int field_number,
double value,
uint8* target) {
target = WriteTagToArray(field_number, WIRETYPE_FIXED64, target);
return WriteDoubleNoTagToArray(value, target);
}
inline uint8* WireFormatLite::WriteBoolToArray(int field_number,
bool value,
uint8* target) {
target = WriteTagToArray(field_number, WIRETYPE_VARINT, target);
return WriteBoolNoTagToArray(value, target);
}
inline uint8* WireFormatLite::WriteEnumToArray(int field_number,
int value,
uint8* target) {
target = WriteTagToArray(field_number, WIRETYPE_VARINT, target);
return WriteEnumNoTagToArray(value, target);
}
template<typename T>
inline uint8* WireFormatLite::WritePrimitiveToArray(
int field_number,
const RepeatedField<T>& value,
uint8* (*Writer)(int, T, uint8*), uint8* target) {
const int n = value.size();
if (n == 0) {
return target;
}
const T* ii = value.unsafe_data();
int i = 0;
do {
target = Writer(field_number, ii[i], target);
} while (++i < n);
return target;
}
inline uint8* WireFormatLite::WriteInt32ToArray(
int field_number, const RepeatedField< int32>& value, uint8* target) {
return WritePrimitiveToArray(field_number, value, WriteInt32ToArray, target);
}
inline uint8* WireFormatLite::WriteInt64ToArray(
int field_number, const RepeatedField< int64>& value, uint8* target) {
return WritePrimitiveToArray(field_number, value, WriteInt64ToArray, target);
}
inline uint8* WireFormatLite::WriteUInt32ToArray(
int field_number, const RepeatedField<uint32>& value, uint8* target) {
return WritePrimitiveToArray(field_number, value, WriteUInt32ToArray, target);
}
inline uint8* WireFormatLite::WriteUInt64ToArray(
int field_number, const RepeatedField<uint64>& value, uint8* target) {
return WritePrimitiveToArray(field_number, value, WriteUInt64ToArray, target);
}
inline uint8* WireFormatLite::WriteSInt32ToArray(
int field_number, const RepeatedField< int32>& value, uint8* target) {
return WritePrimitiveToArray(field_number, value, WriteSInt32ToArray, target);
}
inline uint8* WireFormatLite::WriteSInt64ToArray(
int field_number, const RepeatedField< int64>& value, uint8* target) {
return WritePrimitiveToArray(field_number, value, WriteSInt64ToArray, target);
}
inline uint8* WireFormatLite::WriteFixed32ToArray(
int field_number, const RepeatedField<uint32>& value, uint8* target) {
return WritePrimitiveToArray(
field_number, value, WriteFixed32ToArray, target);
}
inline uint8* WireFormatLite::WriteFixed64ToArray(
int field_number, const RepeatedField<uint64>& value, uint8* target) {
return WritePrimitiveToArray(
field_number, value, WriteFixed64ToArray, target);
}
inline uint8* WireFormatLite::WriteSFixed32ToArray(
int field_number, const RepeatedField< int32>& value, uint8* target) {
return WritePrimitiveToArray(
field_number, value, WriteSFixed32ToArray, target);
}
inline uint8* WireFormatLite::WriteSFixed64ToArray(
int field_number, const RepeatedField< int64>& value, uint8* target) {
return WritePrimitiveToArray(
field_number, value, WriteSFixed64ToArray, target);
}
inline uint8* WireFormatLite::WriteFloatToArray(
int field_number, const RepeatedField< float>& value, uint8* target) {
return WritePrimitiveToArray(field_number, value, WriteFloatToArray, target);
}
inline uint8* WireFormatLite::WriteDoubleToArray(
int field_number, const RepeatedField<double>& value, uint8* target) {
return WritePrimitiveToArray(field_number, value, WriteDoubleToArray, target);
}
inline uint8* WireFormatLite::WriteBoolToArray(
int field_number, const RepeatedField< bool>& value, uint8* target) {
return WritePrimitiveToArray(field_number, value, WriteBoolToArray, target);
}
inline uint8* WireFormatLite::WriteEnumToArray(
int field_number, const RepeatedField< int>& value, uint8* target) {
return WritePrimitiveToArray(field_number, value, WriteEnumToArray, target);
}
inline uint8* WireFormatLite::WriteStringToArray(int field_number,
const string& value,
uint8* target) {
// String is for UTF-8 text only
// WARNING: In wire_format.cc, both strings and bytes are handled by
// WriteString() to avoid code duplication. If the implementations become
// different, you will need to update that usage.
target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target);
return io::CodedOutputStream::WriteStringWithSizeToArray(value, target);
}
inline uint8* WireFormatLite::WriteBytesToArray(int field_number,
const string& value,
uint8* target) {
target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target);
return io::CodedOutputStream::WriteStringWithSizeToArray(value, target);
}
template<typename MessageType>
inline uint8* WireFormatLite::InternalWriteGroupToArray(
int field_number, const MessageType& value, bool deterministic,
uint8* target) {
target = WriteTagToArray(field_number, WIRETYPE_START_GROUP, target);
target = value.InternalSerializeWithCachedSizesToArray(deterministic, target);
return WriteTagToArray(field_number, WIRETYPE_END_GROUP, target);
}
template<typename MessageType>
inline uint8* WireFormatLite::InternalWriteMessageToArray(
int field_number, const MessageType& value, bool deterministic,
uint8* target) {
target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target);
target = io::CodedOutputStream::WriteVarint32ToArray(
static_cast<uint32>(value.GetCachedSize()), target);
return value.InternalSerializeWithCachedSizesToArray(deterministic, target);
}
// See comment on ReadGroupNoVirtual to understand the need for this template
// parameter name.
template<typename MessageType_WorkAroundCppLookupDefect>
inline uint8* WireFormatLite::InternalWriteGroupNoVirtualToArray(
int field_number, const MessageType_WorkAroundCppLookupDefect& value,
bool deterministic, uint8* target) {
target = WriteTagToArray(field_number, WIRETYPE_START_GROUP, target);
target = value.MessageType_WorkAroundCppLookupDefect::
InternalSerializeWithCachedSizesToArray(deterministic, target);
return WriteTagToArray(field_number, WIRETYPE_END_GROUP, target);
}
template<typename MessageType_WorkAroundCppLookupDefect>
inline uint8* WireFormatLite::InternalWriteMessageNoVirtualToArray(
int field_number, const MessageType_WorkAroundCppLookupDefect& value,
bool deterministic, uint8* target) {
target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target);
target = io::CodedOutputStream::WriteVarint32ToArray(
static_cast<uint32>(
value.MessageType_WorkAroundCppLookupDefect::GetCachedSize()),
target);
return value.MessageType_WorkAroundCppLookupDefect::
InternalSerializeWithCachedSizesToArray(deterministic, target);
}
// ===================================================================
inline size_t WireFormatLite::Int32Size(int32 value) {
return io::CodedOutputStream::VarintSize32SignExtended(value);
}
inline size_t WireFormatLite::Int64Size(int64 value) {
return io::CodedOutputStream::VarintSize64(static_cast<uint64>(value));
}
inline size_t WireFormatLite::UInt32Size(uint32 value) {
return io::CodedOutputStream::VarintSize32(value);
}
inline size_t WireFormatLite::UInt64Size(uint64 value) {
return io::CodedOutputStream::VarintSize64(value);
}
inline size_t WireFormatLite::SInt32Size(int32 value) {
return io::CodedOutputStream::VarintSize32(ZigZagEncode32(value));
}
inline size_t WireFormatLite::SInt64Size(int64 value) {
return io::CodedOutputStream::VarintSize64(ZigZagEncode64(value));
}
inline size_t WireFormatLite::EnumSize(int value) {
return io::CodedOutputStream::VarintSize32SignExtended(value);
}
inline size_t WireFormatLite::StringSize(const string& value) {
return LengthDelimitedSize(value.size());
}
inline size_t WireFormatLite::BytesSize(const string& value) {
return LengthDelimitedSize(value.size());
}
template<typename MessageType>
inline size_t WireFormatLite::GroupSize(const MessageType& value) {
return value.ByteSizeLong();
}
template<typename MessageType>
inline size_t WireFormatLite::MessageSize(const MessageType& value) {
return LengthDelimitedSize(value.ByteSizeLong());
}
// See comment on ReadGroupNoVirtual to understand the need for this template
// parameter name.
template<typename MessageType_WorkAroundCppLookupDefect>
inline size_t WireFormatLite::GroupSizeNoVirtual(
const MessageType_WorkAroundCppLookupDefect& value) {
return value.MessageType_WorkAroundCppLookupDefect::ByteSizeLong();
}
template<typename MessageType_WorkAroundCppLookupDefect>
inline size_t WireFormatLite::MessageSizeNoVirtual(
const MessageType_WorkAroundCppLookupDefect& value) {
return LengthDelimitedSize(
value.MessageType_WorkAroundCppLookupDefect::ByteSizeLong());
}
inline size_t WireFormatLite::LengthDelimitedSize(size_t length) {
// The static_cast here prevents an error in certain compiler configurations
// but is not technically correct--if length is too large to fit in a uint32
// then it will be silently truncated. We will need to fix this if we ever
// decide to start supporting serialized messages greater than 2 GiB in size.
return length + io::CodedOutputStream::VarintSize32(
static_cast<uint32>(length));
}
} // namespace internal
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_WIRE_FORMAT_LITE_INL_H__

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.
#include <google/protobuf/implicit_weak_message.h>
#include <google/protobuf/stubs/once.h>
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
#include <google/protobuf/wire_format_lite.h>
namespace google {
namespace protobuf {
namespace internal {
bool ImplicitWeakMessage::MergePartialFromCodedStream(io::CodedInputStream* input) {
io::StringOutputStream string_stream(&data_);
io::CodedOutputStream coded_stream(&string_stream, false);
return WireFormatLite::SkipMessage(input, &coded_stream);
}
::google::protobuf::internal::ExplicitlyConstructed<ImplicitWeakMessage>
implicit_weak_message_default_instance;
GOOGLE_PROTOBUF_DECLARE_ONCE(implicit_weak_message_once_init_);
void InitImplicitWeakMessageDefaultInstance() {
implicit_weak_message_default_instance.DefaultConstruct();
}
const ImplicitWeakMessage* ImplicitWeakMessage::default_instance() {
::google::protobuf::GoogleOnceInit(&implicit_weak_message_once_init_,
&InitImplicitWeakMessageDefaultInstance);
return &implicit_weak_message_default_instance.get();
}
} // namespace internal
} // namespace protobuf
} // namespace google

201
third_party/protobuf-lite/int128.cc vendored Normal file
View File

@ -0,0 +1,201 @@
// 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/int128.h>
#include <iomanip>
#include <ostream> // NOLINT(readability/streams)
#include <sstream>
namespace google {
namespace protobuf {
const uint128_pod kuint128max = {
static_cast<uint64>(GOOGLE_LONGLONG(0xFFFFFFFFFFFFFFFF)),
static_cast<uint64>(GOOGLE_LONGLONG(0xFFFFFFFFFFFFFFFF))
};
// Returns the 0-based position of the last set bit (i.e., most significant bit)
// in the given uint64. The argument may not be 0.
//
// For example:
// Given: 5 (decimal) == 101 (binary)
// Returns: 2
#define STEP(T, n, pos, sh) \
do { \
if ((n) >= (static_cast<T>(1) << (sh))) { \
(n) = (n) >> (sh); \
(pos) |= (sh); \
} \
} while (0)
static inline int Fls64(uint64 n) {
GOOGLE_DCHECK_NE(0, n);
int pos = 0;
STEP(uint64, n, pos, 0x20);
uint32 n32 = n;
STEP(uint32, n32, pos, 0x10);
STEP(uint32, n32, pos, 0x08);
STEP(uint32, n32, pos, 0x04);
return pos + ((GOOGLE_ULONGLONG(0x3333333322221100) >> (n32 << 2)) & 0x3);
}
#undef STEP
// Like Fls64() above, but returns the 0-based position of the last set bit
// (i.e., most significant bit) in the given uint128. The argument may not be 0.
static inline int Fls128(uint128 n) {
if (uint64 hi = Uint128High64(n)) {
return Fls64(hi) + 64;
}
return Fls64(Uint128Low64(n));
}
// Long division/modulo for uint128 implemented using the shift-subtract
// division algorithm adapted from:
// http://stackoverflow.com/questions/5386377/division-without-using
void uint128::DivModImpl(uint128 dividend, uint128 divisor,
uint128* quotient_ret, uint128* remainder_ret) {
if (divisor == 0) {
GOOGLE_LOG(FATAL) << "Division or mod by zero: dividend.hi=" << dividend.hi_
<< ", lo=" << dividend.lo_;
}
if (divisor > dividend) {
*quotient_ret = 0;
*remainder_ret = dividend;
return;
}
if (divisor == dividend) {
*quotient_ret = 1;
*remainder_ret = 0;
return;
}
uint128 denominator = divisor;
uint128 position = 1;
uint128 quotient = 0;
// Left aligns the MSB of the denominator and the dividend.
int shift = Fls128(dividend) - Fls128(denominator);
denominator <<= shift;
position <<= shift;
// Uses shift-subtract algorithm to divide dividend by denominator. The
// remainder will be left in dividend.
while (position > 0) {
if (dividend >= denominator) {
dividend -= denominator;
quotient |= position;
}
position >>= 1;
denominator >>= 1;
}
*quotient_ret = quotient;
*remainder_ret = dividend;
}
uint128& uint128::operator/=(const uint128& divisor) {
uint128 quotient = 0;
uint128 remainder = 0;
DivModImpl(*this, divisor, &quotient, &remainder);
*this = quotient;
return *this;
}
uint128& uint128::operator%=(const uint128& divisor) {
uint128 quotient = 0;
uint128 remainder = 0;
DivModImpl(*this, divisor, &quotient, &remainder);
*this = remainder;
return *this;
}
std::ostream& operator<<(std::ostream& o, const uint128& b) {
std::ios_base::fmtflags flags = o.flags();
// Select a divisor which is the largest power of the base < 2^64.
uint128 div;
std::streamsize div_base_log;
switch (flags & std::ios::basefield) {
case std::ios::hex:
div = static_cast<uint64>(GOOGLE_ULONGLONG(0x1000000000000000)); // 16^15
div_base_log = 15;
break;
case std::ios::oct:
div = static_cast<uint64>(GOOGLE_ULONGLONG(01000000000000000000000)); // 8^21
div_base_log = 21;
break;
default: // std::ios::dec
div = static_cast<uint64>(GOOGLE_ULONGLONG(10000000000000000000)); // 10^19
div_base_log = 19;
break;
}
// Now piece together the uint128 representation from three chunks of
// the original value, each less than "div" and therefore representable
// as a uint64.
std::ostringstream os;
std::ios_base::fmtflags copy_mask =
std::ios::basefield | std::ios::showbase | std::ios::uppercase;
os.setf(flags & copy_mask, copy_mask);
uint128 high = b;
uint128 low;
uint128::DivModImpl(high, div, &high, &low);
uint128 mid;
uint128::DivModImpl(high, div, &high, &mid);
if (high.lo_ != 0) {
os << high.lo_;
os << std::noshowbase << std::setfill('0') << std::setw(div_base_log);
os << mid.lo_;
os << std::setw(div_base_log);
} else if (mid.lo_ != 0) {
os << mid.lo_;
os << std::noshowbase << std::setfill('0') << std::setw(div_base_log);
}
os << low.lo_;
std::string rep = os.str();
// Add the requisite padding.
std::streamsize width = o.width(0);
if (width > rep.size()) {
if ((flags & std::ios::adjustfield) == std::ios::left) {
rep.append(width - rep.size(), o.fill());
} else {
rep.insert(static_cast<std::string::size_type>(0),
width - rep.size(), o.fill());
}
}
// Stream the final representation in a single "<<" call.
return o << rep;
}
} // namespace protobuf
} // namespace google

414
third_party/protobuf-lite/io_win32.cc vendored Normal file
View File

@ -0,0 +1,414 @@
// 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: laszlocsomor@google.com (Laszlo Csomor)
//
// Implementation for long-path-aware open/mkdir/access/etc. on Windows, as well
// as for the supporting utility functions.
//
// These functions convert the input path to an absolute Windows path
// with "\\?\" prefix, then pass that to _wopen/_wmkdir/_waccess/etc.
// (declared in <io.h>) respectively. This allows working with files/directories
// whose paths are longer than MAX_PATH (260 chars).
//
// This file is only used on Windows, it's empty on other platforms.
#if defined(_WIN32)
// Comment this out to fall back to using the ANSI versions (open, mkdir, ...)
// instead of the Unicode ones (_wopen, _wmkdir, ...). Doing so can be useful to
// debug failing tests if that's caused by the long path support.
#define SUPPORT_LONGPATHS
#include <ctype.h>
#include <direct.h>
#include <errno.h>
#include <fcntl.h>
#include <io.h>
#include <memory>
#include <sys/stat.h>
#include <sys/types.h>
#include <wctype.h>
#include <windows.h>
#include <google/protobuf/stubs/io_win32.h>
#include <memory>
#include <sstream>
#include <string>
#include <vector>
namespace google {
namespace protobuf {
namespace internal {
namespace win32 {
namespace {
using std::string;
using std::wstring;
template <typename char_type>
struct CharTraits {
static bool is_alpha(char_type ch);
};
template <>
struct CharTraits<char> {
static bool is_alpha(char ch) { return isalpha(ch); }
};
template <>
struct CharTraits<wchar_t> {
static bool is_alpha(wchar_t ch) { return iswalpha(ch); }
};
template <typename char_type>
bool null_or_empty(const char_type* s) {
return s == NULL || *s == 0;
}
// Returns true if the path starts with a drive letter, e.g. "c:".
// Note that this won't check for the "\" after the drive letter, so this also
// returns true for "c:foo" (which is "c:\${PWD}\foo").
// This check requires that a path not have a longpath prefix ("\\?\").
template <typename char_type>
bool has_drive_letter(const char_type* ch) {
return CharTraits<char_type>::is_alpha(ch[0]) && ch[1] == ':';
}
// Returns true if the path starts with a longpath prefix ("\\?\").
template <typename char_type>
bool has_longpath_prefix(const char_type* path) {
return path[0] == '\\' && path[1] == '\\' && path[2] == '?' &&
path[3] == '\\';
}
template <typename char_type>
bool is_separator(char_type c) {
return c == '/' || c == '\\';
}
// Returns true if the path starts with a drive specifier (e.g. "c:\").
template <typename char_type>
bool is_path_absolute(const char_type* path) {
return has_drive_letter(path) && is_separator(path[2]);
}
template <typename char_type>
bool is_drive_relative(const char_type* path) {
return has_drive_letter(path) && (path[2] == 0 || !is_separator(path[2]));
}
wstring join_paths(const wstring& path1, const wstring& path2) {
if (path1.empty() || is_path_absolute(path2.c_str()) ||
has_longpath_prefix(path2.c_str())) {
return path2;
}
if (path2.empty()) {
return path1;
}
if (is_separator(path1[path1.size() - 1])) {
return is_separator(path2[0]) ? (path1 + path2.substr(1))
: (path1 + path2);
} else {
return is_separator(path2[0]) ? (path1 + path2)
: (path1 + L'\\' + path2);
}
}
wstring normalize(wstring path) {
if (has_longpath_prefix(path.c_str())) {
path = path.substr(4);
}
static const wstring dot(L".");
static const wstring dotdot(L"..");
const WCHAR* p = path.c_str();
std::vector<wstring> segments;
int segment_start = -1;
// Find the path segments in `path` (separated by "/").
for (int i = 0;; ++i) {
if (!is_separator(p[i]) && p[i] != L'\0') {
// The current character does not end a segment, so start one unless it's
// already started.
if (segment_start < 0) {
segment_start = i;
}
} else if (segment_start >= 0 && i > segment_start) {
// The current character is "/" or "\0", so this ends a segment.
// Add that to `segments` if there's anything to add; handle "." and "..".
wstring segment(p, segment_start, i - segment_start);
segment_start = -1;
if (segment == dotdot) {
if (!segments.empty() &&
(!has_drive_letter(segments[0].c_str()) || segments.size() > 1)) {
segments.pop_back();
}
} else if (segment != dot && !segment.empty()) {
segments.push_back(segment);
}
}
if (p[i] == L'\0') {
break;
}
}
// Handle the case when `path` is just a drive specifier (or some degenerate
// form of it, e.g. "c:\..").
if (segments.size() == 1 && segments[0].size() == 2 &&
has_drive_letter(segments[0].c_str())) {
return segments[0] + L'\\';
}
// Join all segments.
bool first = true;
std::wstringstream result;
for (int i = 0; i < segments.size(); ++i) {
if (!first) {
result << L'\\';
}
first = false;
result << segments[i];
}
// Preserve trailing separator if the input contained it.
if (!path.empty() && is_separator(p[path.size() - 1])) {
result << L'\\';
}
return result.str();
}
bool as_windows_path(const char* path, wstring* result) {
if (null_or_empty(path)) {
result->clear();
return true;
}
wstring wpath;
if (!strings::utf8_to_wcs(path, &wpath)) {
return false;
}
if (has_longpath_prefix(wpath.c_str())) {
*result = wpath;
return true;
}
if (is_separator(path[0]) || is_drive_relative(path)) {
return false;
}
if (!is_path_absolute(wpath.c_str())) {
int size = ::GetCurrentDirectoryW(0, NULL);
if (size == 0 && GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
return false;
}
std::unique_ptr<WCHAR[]> wcwd(new WCHAR[size]);
::GetCurrentDirectoryW(size, wcwd.get());
wpath = join_paths(wcwd.get(), wpath);
}
wpath = normalize(wpath);
if (!has_longpath_prefix(wpath.c_str())) {
// Add the "\\?\" prefix unconditionally. This way we prevent the Win32 API
// from processing the path and "helpfully" removing trailing dots from the
// path, for example.
// See https://github.com/bazelbuild/bazel/issues/2935
wpath = wstring(L"\\\\?\\") + wpath;
}
*result = wpath;
return true;
}
} // namespace
int open(const char* path, int flags, int mode) {
#ifdef SUPPORT_LONGPATHS
wstring wpath;
if (!as_windows_path(path, &wpath)) {
errno = ENOENT;
return -1;
}
return ::_wopen(wpath.c_str(), flags, mode);
#else
return ::_open(path, flags, mode);
#endif
}
int mkdir(const char* path, int _mode) {
#ifdef SUPPORT_LONGPATHS
wstring wpath;
if (!as_windows_path(path, &wpath)) {
errno = ENOENT;
return -1;
}
return ::_wmkdir(wpath.c_str());
#else // not SUPPORT_LONGPATHS
return ::_mkdir(path);
#endif // not SUPPORT_LONGPATHS
}
int access(const char* path, int mode) {
#ifdef SUPPORT_LONGPATHS
wstring wpath;
if (!as_windows_path(path, &wpath)) {
errno = ENOENT;
return -1;
}
return ::_waccess(wpath.c_str(), mode);
#else
return ::_access(path, mode);
#endif
}
int chdir(const char* path) {
#ifdef SUPPORT_LONGPATHS
wstring wpath;
if (!as_windows_path(path, &wpath)) {
errno = ENOENT;
return -1;
}
return ::_wchdir(wpath.c_str());
#else
return ::_chdir(path);
#endif
}
int stat(const char* path, struct _stat* buffer) {
#ifdef SUPPORT_LONGPATHS
wstring wpath;
if (!as_windows_path(path, &wpath)) {
errno = ENOENT;
return -1;
}
return ::_wstat(wpath.c_str(), buffer);
#else // not SUPPORT_LONGPATHS
return ::_stat(path, buffer);
#endif // not SUPPORT_LONGPATHS
}
FILE* fopen(const char* path, const char* mode) {
#ifdef SUPPORT_LONGPATHS
if (null_or_empty(path)) {
errno = EINVAL;
return NULL;
}
wstring wpath;
if (!as_windows_path(path, &wpath)) {
errno = ENOENT;
return NULL;
}
wstring wmode;
if (!strings::utf8_to_wcs(mode, &wmode)) {
errno = EINVAL;
return NULL;
}
return ::_wfopen(wpath.c_str(), wmode.c_str());
#else
return ::fopen(path, mode);
#endif
}
int close(int fd) { return ::close(fd); }
int dup(int fd) { return ::_dup(fd); }
int dup2(int fd1, int fd2) { return ::_dup2(fd1, fd2); }
int read(int fd, void* buffer, size_t size) {
return ::_read(fd, buffer, size);
}
int setmode(int fd, int mode) { return ::_setmode(fd, mode); }
int write(int fd, const void* buffer, size_t size) {
return ::_write(fd, buffer, size);
}
wstring testonly_utf8_to_winpath(const char* path) {
wstring wpath;
return as_windows_path(path, &wpath) ? wpath : wstring();
}
namespace strings {
bool wcs_to_mbs(const WCHAR* s, string* out, bool outUtf8) {
if (null_or_empty(s)) {
out->clear();
return true;
}
BOOL usedDefaultChar = FALSE;
SetLastError(0);
int size = WideCharToMultiByte(
outUtf8 ? CP_UTF8 : CP_ACP, 0, s, -1, NULL, 0, NULL,
outUtf8 ? NULL : &usedDefaultChar);
if ((size == 0 && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|| usedDefaultChar) {
return false;
}
std::unique_ptr<CHAR[]> astr(new CHAR[size]);
WideCharToMultiByte(
outUtf8 ? CP_UTF8 : CP_ACP, 0, s, -1, astr.get(), size, NULL, NULL);
out->assign(astr.get());
return true;
}
bool mbs_to_wcs(const char* s, wstring* out, bool inUtf8) {
if (null_or_empty(s)) {
out->clear();
return true;
}
SetLastError(0);
int size =
MultiByteToWideChar(inUtf8 ? CP_UTF8 : CP_ACP, 0, s, -1, NULL, 0);
if (size == 0 && GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
return false;
}
std::unique_ptr<WCHAR[]> wstr(new WCHAR[size]);
MultiByteToWideChar(
inUtf8 ? CP_UTF8 : CP_ACP, 0, s, -1, wstr.get(), size + 1);
out->assign(wstr.get());
return true;
}
bool utf8_to_wcs(const char* input, wstring* out) {
return mbs_to_wcs(input, out, true);
}
bool wcs_to_utf8(const wchar_t* input, string* out) {
return wcs_to_mbs(input, out, true);
}
} // namespace strings
} // namespace win32
} // namespace internal
} // namespace protobuf
} // namespace google
#endif // defined(_WIN32)

View File

@ -0,0 +1,407 @@
// 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.
// Authors: wink@google.com (Wink Saville),
// kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
#include <climits>
#include <google/protobuf/arena.h>
#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/message_lite.h>
#include <google/protobuf/repeated_field.h>
#include <string>
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
#include <google/protobuf/stubs/stl_util.h>
namespace google {
namespace protobuf {
string MessageLite::InitializationErrorString() const {
return "(cannot determine missing fields for lite message)";
}
namespace {
// When serializing, we first compute the byte size, then serialize the message.
// If serialization produces a different number of bytes than expected, we
// call this function, which crashes. The problem could be due to a bug in the
// protobuf implementation but is more likely caused by concurrent modification
// of the message. This function attempts to distinguish between the two and
// provide a useful error message.
void ByteSizeConsistencyError(size_t byte_size_before_serialization,
size_t byte_size_after_serialization,
size_t bytes_produced_by_serialization,
const MessageLite& message) {
GOOGLE_CHECK_EQ(byte_size_before_serialization, byte_size_after_serialization)
<< message.GetTypeName()
<< " was modified concurrently during serialization.";
GOOGLE_CHECK_EQ(bytes_produced_by_serialization, byte_size_before_serialization)
<< "Byte size calculation and serialization were inconsistent. This "
"may indicate a bug in protocol buffers or it may be caused by "
"concurrent modification of " << message.GetTypeName() << ".";
GOOGLE_LOG(FATAL) << "This shouldn't be called if all the sizes are equal.";
}
string InitializationErrorMessage(const char* action,
const MessageLite& message) {
// Note: We want to avoid depending on strutil in the lite library, otherwise
// we'd use:
//
// return strings::Substitute(
// "Can't $0 message of type \"$1\" because it is missing required "
// "fields: $2",
// action, message.GetTypeName(),
// message.InitializationErrorString());
string result;
result += "Can't ";
result += action;
result += " message of type \"";
result += message.GetTypeName();
result += "\" because it is missing required fields: ";
result += message.InitializationErrorString();
return result;
}
// Several of the Parse methods below just do one thing and then call another
// method. In a naive implementation, we might have ParseFromString() call
// ParseFromArray() which would call ParseFromZeroCopyStream() which would call
// ParseFromCodedStream() which would call MergeFromCodedStream() which would
// call MergePartialFromCodedStream(). However, when parsing very small
// messages, every function call introduces significant overhead. To avoid
// this without reproducing code, we use these forced-inline helpers.
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE bool InlineMergeFromCodedStream(
io::CodedInputStream* input, MessageLite* message);
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE bool InlineParseFromCodedStream(
io::CodedInputStream* input, MessageLite* message);
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE bool InlineParsePartialFromCodedStream(
io::CodedInputStream* input, MessageLite* message);
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE bool InlineParseFromArray(
const void* data, int size, MessageLite* message);
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE bool InlineParsePartialFromArray(
const void* data, int size, MessageLite* message);
inline bool InlineMergeFromCodedStream(io::CodedInputStream* input,
MessageLite* message) {
if (!message->MergePartialFromCodedStream(input)) return false;
if (!message->IsInitialized()) {
GOOGLE_LOG(ERROR) << InitializationErrorMessage("parse", *message);
return false;
}
return true;
}
inline bool InlineParseFromCodedStream(io::CodedInputStream* input,
MessageLite* message) {
message->Clear();
return InlineMergeFromCodedStream(input, message);
}
inline bool InlineParsePartialFromCodedStream(io::CodedInputStream* input,
MessageLite* message) {
message->Clear();
return message->MergePartialFromCodedStream(input);
}
inline bool InlineParseFromArray(
const void* data, int size, MessageLite* message) {
io::CodedInputStream input(reinterpret_cast<const uint8*>(data), size);
return InlineParseFromCodedStream(&input, message) &&
input.ConsumedEntireMessage();
}
inline bool InlineParsePartialFromArray(
const void* data, int size, MessageLite* message) {
io::CodedInputStream input(reinterpret_cast<const uint8*>(data), size);
return InlineParsePartialFromCodedStream(&input, message) &&
input.ConsumedEntireMessage();
}
} // namespace
MessageLite* MessageLite::New(::google::protobuf::Arena* arena) const {
MessageLite* message = New();
if (arena != NULL) {
arena->Own(message);
}
return message;
}
bool MessageLite::MergeFromCodedStream(io::CodedInputStream* input) {
return InlineMergeFromCodedStream(input, this);
}
bool MessageLite::ParseFromCodedStream(io::CodedInputStream* input) {
return InlineParseFromCodedStream(input, this);
}
bool MessageLite::ParsePartialFromCodedStream(io::CodedInputStream* input) {
return InlineParsePartialFromCodedStream(input, this);
}
bool MessageLite::ParseFromZeroCopyStream(io::ZeroCopyInputStream* input) {
io::CodedInputStream decoder(input);
return ParseFromCodedStream(&decoder) && decoder.ConsumedEntireMessage();
}
bool MessageLite::ParsePartialFromZeroCopyStream(
io::ZeroCopyInputStream* input) {
io::CodedInputStream decoder(input);
return ParsePartialFromCodedStream(&decoder) &&
decoder.ConsumedEntireMessage();
}
bool MessageLite::ParseFromBoundedZeroCopyStream(
io::ZeroCopyInputStream* input, int size) {
io::CodedInputStream decoder(input);
decoder.PushLimit(size);
return ParseFromCodedStream(&decoder) &&
decoder.ConsumedEntireMessage() &&
decoder.BytesUntilLimit() == 0;
}
bool MessageLite::ParsePartialFromBoundedZeroCopyStream(
io::ZeroCopyInputStream* input, int size) {
io::CodedInputStream decoder(input);
decoder.PushLimit(size);
return ParsePartialFromCodedStream(&decoder) &&
decoder.ConsumedEntireMessage() &&
decoder.BytesUntilLimit() == 0;
}
bool MessageLite::ParseFromString(const string& data) {
return InlineParseFromArray(data.data(), data.size(), this);
}
bool MessageLite::ParsePartialFromString(const string& data) {
return InlineParsePartialFromArray(data.data(), data.size(), this);
}
bool MessageLite::ParseFromArray(const void* data, int size) {
return InlineParseFromArray(data, size, this);
}
bool MessageLite::ParsePartialFromArray(const void* data, int size) {
return InlineParsePartialFromArray(data, size, this);
}
// ===================================================================
uint8* MessageLite::SerializeWithCachedSizesToArray(uint8* target) const {
return InternalSerializeWithCachedSizesToArray(
io::CodedOutputStream::IsDefaultSerializationDeterministic(), target);
}
bool MessageLite::SerializeToCodedStream(io::CodedOutputStream* output) const {
GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this);
return SerializePartialToCodedStream(output);
}
bool MessageLite::SerializePartialToCodedStream(
io::CodedOutputStream* output) const {
const size_t size = ByteSizeLong(); // Force size to be cached.
if (size > INT_MAX) {
GOOGLE_LOG(ERROR) << "Exceeded maximum protobuf size of 2GB: " << size;
return false;
}
uint8* buffer = output->GetDirectBufferForNBytesAndAdvance(size);
if (buffer != NULL) {
uint8* end = InternalSerializeWithCachedSizesToArray(
output->IsSerializationDeterministic(), buffer);
if (end - buffer != size) {
ByteSizeConsistencyError(size, ByteSizeLong(), end - buffer, *this);
}
return true;
} else {
int original_byte_count = output->ByteCount();
SerializeWithCachedSizes(output);
if (output->HadError()) {
return false;
}
int final_byte_count = output->ByteCount();
if (final_byte_count - original_byte_count != size) {
ByteSizeConsistencyError(size, ByteSizeLong(),
final_byte_count - original_byte_count, *this);
}
return true;
}
}
bool MessageLite::SerializeToZeroCopyStream(
io::ZeroCopyOutputStream* output) const {
io::CodedOutputStream encoder(output);
return SerializeToCodedStream(&encoder);
}
bool MessageLite::SerializePartialToZeroCopyStream(
io::ZeroCopyOutputStream* output) const {
io::CodedOutputStream encoder(output);
return SerializePartialToCodedStream(&encoder);
}
bool MessageLite::AppendToString(string* output) const {
GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this);
return AppendPartialToString(output);
}
bool MessageLite::AppendPartialToString(string* output) const {
size_t old_size = output->size();
size_t byte_size = ByteSizeLong();
if (byte_size > INT_MAX) {
GOOGLE_LOG(ERROR) << "Exceeded maximum protobuf size of 2GB: " << byte_size;
return false;
}
STLStringResizeUninitialized(output, old_size + byte_size);
uint8* start =
reinterpret_cast<uint8*>(io::mutable_string_data(output) + old_size);
uint8* end = SerializeWithCachedSizesToArray(start);
if (end - start != byte_size) {
ByteSizeConsistencyError(byte_size, ByteSizeLong(), end - start, *this);
}
return true;
}
bool MessageLite::SerializeToString(string* output) const {
output->clear();
return AppendToString(output);
}
bool MessageLite::SerializePartialToString(string* output) const {
output->clear();
return AppendPartialToString(output);
}
bool MessageLite::SerializeToArray(void* data, int size) const {
GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this);
return SerializePartialToArray(data, size);
}
bool MessageLite::SerializePartialToArray(void* data, int size) const {
int byte_size = ByteSizeLong();
if (size < byte_size) return false;
uint8* start = reinterpret_cast<uint8*>(data);
uint8* end = SerializeWithCachedSizesToArray(start);
if (end - start != byte_size) {
ByteSizeConsistencyError(byte_size, ByteSizeLong(), end - start, *this);
}
return true;
}
string MessageLite::SerializeAsString() const {
// If the compiler implements the (Named) Return Value Optimization,
// the local variable 'output' will not actually reside on the stack
// of this function, but will be overlaid with the object that the
// caller supplied for the return value to be constructed in.
string output;
if (!AppendToString(&output))
output.clear();
return output;
}
string MessageLite::SerializePartialAsString() const {
string output;
if (!AppendPartialToString(&output))
output.clear();
return output;
}
void MessageLite::SerializeWithCachedSizes(
io::CodedOutputStream* output) const {
GOOGLE_DCHECK(InternalGetTable());
internal::TableSerialize(
*this,
static_cast<const internal::SerializationTable*>(InternalGetTable()),
output);
}
// The table driven code optimizes the case that the CodedOutputStream buffer
// is large enough to serialize into it directly.
// If the proto is optimized for speed, this method will be overridden by
// generated code for maximum speed. If the proto is optimized for size or
// is lite, then we need to specialize this to avoid infinite recursion.
uint8* MessageLite::InternalSerializeWithCachedSizesToArray(
bool deterministic, uint8* target) const {
const internal::SerializationTable* table =
static_cast<const internal::SerializationTable*>(InternalGetTable());
if (table == NULL) {
// We only optimize this when using optimize_for = SPEED. In other cases
// we just use the CodedOutputStream path.
int size = GetCachedSize();
io::ArrayOutputStream out(target, size);
io::CodedOutputStream coded_out(&out);
coded_out.SetSerializationDeterministic(deterministic);
SerializeWithCachedSizes(&coded_out);
GOOGLE_CHECK(!coded_out.HadError());
return target + size;
} else {
return internal::TableSerializeToArray(*this, table, deterministic, target);
}
}
namespace internal {
template<>
MessageLite* GenericTypeHandler<MessageLite>::NewFromPrototype(
const MessageLite* prototype, google::protobuf::Arena* arena) {
return prototype->New(arena);
}
template <>
void GenericTypeHandler<MessageLite>::Merge(const MessageLite& from,
MessageLite* to) {
to->CheckTypeAndMergeFrom(from);
}
template<>
void GenericTypeHandler<string>::Merge(const string& from,
string* to) {
*to = from;
}
bool proto3_preserve_unknown_ = true;
void SetProto3PreserveUnknownsDefault(bool preserve) {
proto3_preserve_unknown_ = preserve;
}
} // namespace internal
} // namespace protobuf
} // namespace google

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