Patch internal change 111557819.

Defer calls to mutable_unknown_fields() until it is actually required to
save memory for C++ lite runtime.

Change-Id: Ica9c1fd276cdb164942d1e7b6e098c83ee3ffdc5
This commit is contained in:
Feng Xiao 2016-01-06 18:06:43 -08:00
parent 363316a8d7
commit 76195058e2
6 changed files with 179 additions and 4 deletions

View File

@ -1772,6 +1772,17 @@ GenerateShutdownCode(io::Printer* printer) {
void MessageGenerator::
GenerateClassMethods(io::Printer* printer) {
// mutable_unknown_fields wrapper function for LazyStringOutputStream
// callback.
if (!UseUnknownFieldSet(descriptor_->file())) {
printer->Print(
"static ::std::string* MutableUnknownFieldsFor$classname$(\n"
" $classname$* ptr) {\n"
" return ptr->mutable_unknown_fields();\n"
"}\n"
"\n",
"classname", classname_);
}
if (IsAnyMessage(descriptor_)) {
printer->Print(
"void $classname$::PackFrom(const ::google::protobuf::Message& message) {\n"
@ -2814,7 +2825,9 @@ GenerateMergeFrom(io::Printer* printer) {
"}\n");
} else {
printer->Print(
"mutable_unknown_fields()->append(from.unknown_fields());\n");
"if (!from.unknown_fields().empty()) {\n"
" mutable_unknown_fields()->append(from.unknown_fields());\n"
"}\n");
}
}
@ -2889,11 +2902,16 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
"classname", classname_);
if (!UseUnknownFieldSet(descriptor_->file())) {
// Use LazyStringOutputString to avoid initializing unknown fields string
// unless it is actually needed. For the same reason, disable eager refresh
// on the CodedOutputStream.
printer->Print(
" ::google::protobuf::io::StringOutputStream unknown_fields_string(\n"
" mutable_unknown_fields());\n"
" ::google::protobuf::io::LazyStringOutputStream unknown_fields_string(\n"
" ::google::protobuf::internal::NewPermanentCallback(\n"
" &MutableUnknownFieldsFor$classname$, this));\n"
" ::google::protobuf::io::CodedOutputStream unknown_fields_stream(\n"
" &unknown_fields_string);\n");
" &unknown_fields_string, false);\n",
"classname", classname_);
}
printer->Print(

View File

@ -629,6 +629,24 @@ CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* output)
had_error_ = false;
}
CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* output,
bool do_eager_refresh)
: output_(output),
buffer_(NULL),
buffer_size_(0),
total_bytes_(0),
had_error_(false),
aliasing_enabled_(false) {
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();
}

View File

@ -666,6 +666,7 @@ class LIBPROTOBUF_EXPORT CodedOutputStream {
public:
// Create an CodedOutputStream that writes to the given ZeroCopyOutputStream.
explicit CodedOutputStream(ZeroCopyOutputStream* output);
CodedOutputStream(ZeroCopyOutputStream* output, bool do_eager_refresh);
// Destroy the CodedOutputStream and position the underlying
// ZeroCopyOutputStream immediately after the last byte written.

View File

@ -157,6 +157,7 @@ StringOutputStream::~StringOutputStream() {
}
bool StringOutputStream::Next(void** data, int* size) {
GOOGLE_CHECK_NE(NULL, target_);
int old_size = target_->size();
// Grow the string.
@ -188,14 +189,44 @@ bool StringOutputStream::Next(void** data, int* size) {
void StringOutputStream::BackUp(int count) {
GOOGLE_CHECK_GE(count, 0);
GOOGLE_CHECK_NE(NULL, target_);
GOOGLE_CHECK_LE(count, target_->size());
target_->resize(target_->size() - count);
}
int64 StringOutputStream::ByteCount() const {
GOOGLE_CHECK_NE(NULL, target_);
return target_->size();
}
void StringOutputStream::SetString(string* target) {
target_ = target;
}
// ===================================================================
LazyStringOutputStream::LazyStringOutputStream(
ResultCallback<string*>* callback)
: StringOutputStream(NULL),
callback_(GOOGLE_CHECK_NOTNULL(callback)),
string_is_set_(false) {
}
LazyStringOutputStream::~LazyStringOutputStream() {
}
bool LazyStringOutputStream::Next(void** data, int* size) {
if (!string_is_set_) {
SetString(callback_->Run());
string_is_set_ = true;
}
return StringOutputStream::Next(data, size);
}
int64 LazyStringOutputStream::ByteCount() const {
return string_is_set_ ? StringOutputStream::ByteCount() : 0;
}
// ===================================================================
CopyingInputStream::~CopyingInputStream() {}

View File

@ -148,6 +148,9 @@ class LIBPROTOBUF_EXPORT StringOutputStream : public ZeroCopyOutputStream {
void BackUp(int count);
int64 ByteCount() const;
protected:
void SetString(string* target);
private:
static const int kMinimumSize = 16;
@ -156,6 +159,27 @@ class LIBPROTOBUF_EXPORT StringOutputStream : public ZeroCopyOutputStream {
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringOutputStream);
};
// LazyStringOutputStream is a StringOutputStream with lazy acquisition of
// the output string from a callback. The string is owned externally, and not
// deleted in the stream destructor.
class LIBPROTOBUF_EXPORT LazyStringOutputStream : public StringOutputStream {
public:
// Callback should be permanent (non-self-deleting). Ownership is transferred
// to the LazyStringOutputStream.
explicit LazyStringOutputStream(ResultCallback<string*>* callback);
~LazyStringOutputStream();
// implements ZeroCopyOutputStream, overriding StringOutputStream -----------
bool Next(void** data, int* size);
int64 ByteCount() const;
private:
const scoped_ptr<ResultCallback<string*> > callback_;
bool string_is_set_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(LazyStringOutputStream);
};
// Note: There is no StringInputStream. Instead, just create an
// ArrayInputStream as follows:
// ArrayInputStream input(str.data(), str.size());

View File

@ -78,6 +78,18 @@ class LIBPROTOBUF_EXPORT Closure {
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Closure);
};
template<typename R>
class LIBPROTOBUF_EXPORT 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:
@ -240,6 +252,50 @@ class MethodClosure2 : public Closure {
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:
@ -408,6 +464,33 @@ inline Closure* NewPermanentCallback(
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)) {