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:
parent
363316a8d7
commit
76195058e2
@ -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(
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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() {}
|
||||
|
@ -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());
|
||||
|
@ -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)) {
|
||||
|
Loading…
Reference in New Issue
Block a user